• 🏆 Texturing Contest #33 is OPEN! Contestants must re-texture a SD unit model found in-game (Warcraft 3 Classic), recreating the unit into a peaceful NPC version. 🔗Click here to enter!
  • It's time for the first HD Modeling Contest of 2024. Join the theme discussion for Hive's HD Modeling Contest #6! Click here to post your idea!

[GUI] Unit Fusion System 0.05

This bundle is marked as useful / simple. Simplicity is bliss, low effort and/or may contain minor bugs.
  • Like
Reactions: blink
Unit Fusion System
by rulerofiron99

Description:
Combine/fuse units, replace a number of component units with one new unit.

Example Uses:
  • Combine Templars into Archons as in Starcraft
  • Make a version of Binders that:
    • Doesn't use circles of power / map areas for fusion
    • Is more efficient (AFAIK)

Features:
  • Visually "clean" - no circles of power, no special map areas. Simply give units the ability, cast it, and we're done.
  • Limitless number of combinations (in theory), although more combinations = more lag as with all good things
  • Limitless number of unit types for a combination (as long as the string can be /2, more accurately)
Limitations:
  • Maximum of one of each unit type for a combination; will look at increasing this in a future version.

Triggers:
  • UFS Units 02
    • Events
    • Conditions
    • Actions
      • -------- ----- --------
      • Set ufsVAR_unitId = (ufsVAR_unitId + 1)
      • Set ufsVAR_unitTag[ufsVAR_unitId] = 03
      • Set ufsVAR_unitType[ufsVAR_unitId] = Gnoll Poacher
      • Set ufsVAR_unitMorph[ufsVAR_unitId] = 0102
      • -------- ----- --------
  • UFS Units Setup
    • Events
    • Conditions
    • Actions
      • -------- don't edit this one --------
      • Set boolStart = False
      • Set tempSize = 0
      • Set indexOffset = 1
      • For each (Integer C) from 1 to ufsVAR_unitId, do (Actions)
        • Loop - Actions
          • Set tempInt = (Length of ufsVAR_unitMorph[C])
          • -------- check if the morph string is empty --------
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • tempInt Equal to tempSize
            • Then - Actions
              • -------- set the offset from position 1+ --------
              • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                • If - Conditions
                  • C Not equal to indexOffset
                • Then - Actions
                  • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                    • If - Conditions
                      • boolStart Equal to False
                    • Then - Actions
                      • Set ufsVAR_fuseIdStart[1] = indexOffset
                      • Set boolStart = True
                    • Else - Actions
                  • Set lastIndexForEnd = indexOffset
                  • -------- swap with top element --------
                  • -------- save the indices to be swapped --------
                  • Set tempReplaceIdComingFrom = C
                  • Set tempReplaceIdToBeTaken = indexOffset
                  • -------- save the first index' data --------
                  • Set tempReplaceTag = ufsVAR_unitTag[tempReplaceIdToBeTaken]
                  • Set tempReplaceUnitType = ufsVAR_unitType[tempReplaceIdToBeTaken]
                  • Set tempReplaceMorph = ufsVAR_unitMorph[tempReplaceIdToBeTaken]
                  • -------- replace the index data --------
                  • Set ufsVAR_unitTag[tempReplaceIdToBeTaken] = ufsVAR_unitTag[tempReplaceIdComingFrom]
                  • Set ufsVAR_unitType[tempReplaceIdToBeTaken] = ufsVAR_unitType[tempReplaceIdComingFrom]
                  • Set ufsVAR_unitMorph[tempReplaceIdToBeTaken] = ufsVAR_unitMorph[tempReplaceIdComingFrom]
                  • -------- replace source index data --------
                  • Set ufsVAR_unitTag[tempReplaceIdComingFrom] = tempReplaceTag
                  • Set ufsVAR_unitType[tempReplaceIdComingFrom] = tempReplaceUnitType
                  • Set ufsVAR_unitMorph[tempReplaceIdComingFrom] = tempReplaceMorph
                • Else - Actions
              • Set indexOffset = (indexOffset + 1)
            • Else - Actions
      • Set ufsVAR_fuseIdEnd[1] = lastIndexForEnd
      • -------- now sort the rest, counting down from highest size --------
      • -------- index offset must remain what it is! --------
      • -------- find highest size --------
      • Set tempSize = 0
      • For each (Integer C) from 1 to ufsVAR_unitId, do (Actions)
        • Loop - Actions
          • Set tempInt = (Length of ufsVAR_unitMorph[C])
          • -------- check if checking morph size is greater that current greatest --------
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • tempInt Greater than tempSize
            • Then - Actions
              • Set tempSize = tempInt
            • Else - Actions
      • -------- string of X has X/2 "pieces" --------
      • Set tempSize = (tempSize / 2)
      • -------- loop from highest size --------
      • For each (Integer forA) from 1 to (tempSize + 2), do (Actions)
        • Loop - Actions
          • -------- forA = current size being checked for --------
          • -------- if element with size is found, replace it to indexOffset --------
          • Set boolStart = False
          • For each (Integer C) from 1 to ufsVAR_unitId, do (Actions)
            • Loop - Actions
              • Set tempInt = (Length of ufsVAR_unitMorph[C])
              • Set tempInt = (tempInt / 2)
              • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                • If - Conditions
                  • tempInt Equal to tempSize
                • Then - Actions
                  • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                    • If - Conditions
                      • Or - Any (Conditions) are true
                        • Conditions
                          • C Not equal to indexOffset
                          • True Equal to True
                    • Then - Actions
                      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                        • If - Conditions
                          • boolStart Equal to False
                        • Then - Actions
                          • Set ufsVAR_fuseIdStart[tempSize] = indexOffset
                          • Set boolStart = True
                        • Else - Actions
                      • Set lastIndexForEnd = indexOffset
                      • -------- swap with top element --------
                      • -------- save the indices to be swapped --------
                      • Set tempReplaceIdComingFrom = C
                      • Set tempReplaceIdToBeTaken = indexOffset
                      • -------- save the first index' data --------
                      • Set tempReplaceTag = ufsVAR_unitTag[tempReplaceIdToBeTaken]
                      • Set tempReplaceUnitType = ufsVAR_unitType[tempReplaceIdToBeTaken]
                      • Set tempReplaceMorph = ufsVAR_unitMorph[tempReplaceIdToBeTaken]
                      • -------- replace the index data --------
                      • Set ufsVAR_unitTag[tempReplaceIdToBeTaken] = ufsVAR_unitTag[tempReplaceIdComingFrom]
                      • Set ufsVAR_unitType[tempReplaceIdToBeTaken] = ufsVAR_unitType[tempReplaceIdComingFrom]
                      • Set ufsVAR_unitMorph[tempReplaceIdToBeTaken] = ufsVAR_unitMorph[tempReplaceIdComingFrom]
                      • -------- replace source index data --------
                      • Set ufsVAR_unitTag[tempReplaceIdComingFrom] = tempReplaceTag
                      • Set ufsVAR_unitType[tempReplaceIdComingFrom] = tempReplaceUnitType
                      • Set ufsVAR_unitMorph[tempReplaceIdComingFrom] = tempReplaceMorph
                    • Else - Actions
                  • -------- set the offset from position 1+ --------
                  • Set indexOffset = (indexOffset + 1)
                • Else - Actions
          • Set ufsVAR_fuseIdEnd[tempSize] = lastIndexForEnd
          • -------- reduce temp size to check for next highest element --------
          • Set tempSize = (tempSize - 1)
      • -------- add units to hashtable --------
      • For each (Integer C) from 1 to ufsVAR_unitId, do (Actions)
        • Loop - Actions
          • Set TempUnitType = ufsVAR_unitType[C]
          • Custom script: set udg_TempInt = udg_TempUnitType
          • Hashtable - Save True as 0 of TempInt in Hashtable
  • UFS Add Unit
    • Events
      • Game - UnitIndexEvent becomes Equal to 1.00
    • Conditions
      • (UDexUnits[UDex] is A Hero) Equal to False
    • Actions
      • Set TempUnit = UDexUnits[UDex]
      • Custom script: set udg_TempInt = GetUnitTypeId(udg_TempUnit)
      • Set Boolean = (Load 0 of TempInt from Hashtable)
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • Boolean Equal to True
        • Then - Actions
          • Unit - Add ufsVAR_FuseAbility to UDexUnits[UDex]
        • Else - Actions
  • UFS Combine
    • Events
      • Unit - A unit Starts the effect of an ability
    • Conditions
      • (Ability being cast) Equal to ufsVAR_FuseAbility
    • Actions
      • Set tempPlayer = (Triggering player)
      • Set tempGroup = (Units currently selected by tempPlayer)
      • Set ufs_fuseGroupSize = (Number of units in tempGroup)
      • For each (Integer forA) from ufsVAR_fuseIdStart[ufs_fuseGroupSize] to ufsVAR_fuseIdEnd[ufs_fuseGroupSize], do (Actions)
        • Loop - Actions
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • (Length of ufsVAR_unitMorph[forA]) Not equal to 0
            • Then - Actions
              • Set ufs_combineLength = ((Length of ufsVAR_unitMorph[forA]) / 2)
              • For each (Integer B) from 1 to ufs_combineLength, do (Actions)
                • Loop - Actions
                  • Set ufs_combineTestBool[(Integer B)] = False
              • For each (Integer B) from 1 to ufs_combineLength, do (Actions)
                • Loop - Actions
                  • -------- get 1st/2nd/etc combine tag from unit morph tag --------
                  • Set ufs_combineTag = <Empty String>
                  • For each (Integer C) from 1 to ufsVAR_unitId, do (Actions)
                    • Loop - Actions
                      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                        • If - Conditions
                          • ufsVAR_unitTag[C] Equal to (Substring(ufsVAR_unitMorph[forA], (((Integer B) x 2) + -1), (((Integer B) x 2) + 0)))
                        • Then - Actions
                          • Set ufs_combineTag = ufsVAR_unitTag[C]
                        • Else - Actions
                  • -------- test combineTag against every unit tag selected --------
                  • Set ufs_combineTest = <Empty String>
                  • Unit Group - Pick every unit in tempGroup and do (Actions)
                    • Loop - Actions
                      • For each (Integer C) from 1 to ufsVAR_unitId, do (Actions)
                        • Loop - Actions
                          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                            • If - Conditions
                              • (Unit-type of (Picked unit)) Equal to ufsVAR_unitType[C]
                            • Then - Actions
                              • Set ufs_combineTest = ufsVAR_unitTag[C]
                            • Else - Actions
                      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                        • If - Conditions
                          • ufs_combineTag Equal to ufs_combineTest
                        • Then - Actions
                          • Set ufs_combineTestBool[(Integer B)] = True
                        • Else - Actions
              • Set ufs_finalTest = True
              • For each (Integer B) from 1 to ufs_combineLength, do (Actions)
                • Loop - Actions
                  • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                    • If - Conditions
                      • ufs_combineTestBool[(Integer B)] Equal to False
                    • Then - Actions
                      • Set ufs_finalTest = False
                    • Else - Actions
              • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                • If - Conditions
                  • ufs_finalTest Equal to True
                • Then - Actions
                  • Set ufs_x = 0.00
                  • Set ufs_y = 0.00
                  • Unit Group - Pick every unit in tempGroup and do (Actions)
                    • Loop - Actions
                      • Set tempLoc = (Position of (Picked unit))
                      • Set ufs_x = (ufs_x + (X of tempLoc))
                      • Set ufs_y = (ufs_y + (Y of tempLoc))
                      • Custom script: call RemoveLocation(udg_tempLoc)
                  • Set ufs_x = (ufs_x / (Real((Number of units in tempGroup))))
                  • Set ufs_y = (ufs_y / (Real((Number of units in tempGroup))))
                  • Set ufs_resultString = <Empty String>
                  • Unit Group - Pick every unit in tempGroup and do (Actions)
                    • Loop - Actions
                      • Set ufs_resultString = (ufs_resultString + ( + + (Name of (Picked unit))))
                      • Unit Group - Remove (Picked unit) from tempGroup
                      • Unit - Explode (Picked unit)
                  • Set tempLoc = (Point(ufs_x, ufs_y))
                  • Unit - Create 1 ufsVAR_unitType[forA] for tempPlayer at tempLoc facing Default building facing degrees
                  • Selection - Select (Last created unit) for tempPlayer
                  • Set ufs_resultString = (ufs_resultString + ( = + (Name of (Last created unit))))
                  • Set ufs_resultString = (Substring(ufs_resultString, 4, (Length of ufs_resultString)))
                  • Set tempForce = (Player group(tempPlayer))
                  • Game - Display to tempForce for 10.00 seconds the text: ufs_resultString
                  • Custom script: call DestroyForce(udg_tempForce)
                  • Special Effect - Create a special effect attached to the origin of (Last created unit) using Abilities\Spells\Demon\DarkPortal\DarkPortalTarget.mdl
                  • Special Effect - Destroy (Last created special effect)
                  • Custom script: call RemoveLocation(udg_tempLoc)
                • Else - Actions
            • Else - Actions
      • Custom script: call DestroyGroup(udg_tempGroup)
Changelog:

0.05
  • Replaced the for loop that adds the fuse ability with a hashtable check.
0.04
  • Improved user readability, all unit combinations are declared in one variable, and the game sorts them by itself
0.03
  • Fixed a player group leak
0.02
  • Added documentation on usage and installation
  • Fixed units all being given to player 1
  • Optimised things: replaced function calls with variables that call functions only at the start of the trigger
  • New unit is automatically selected
0.01
  • Release

Credits:

Thanks to:
  • Deathsite, Shadowz for creating Binders, the map that inspired me to create this system.
  • defskull - Helping me figure out hashtables!


Keywords:
fuse, fusion, bind, binders, combine, combiner, unit fusion, unit combiner, unit combine, unit fuse, archon
Contents

Unit Fusion System 0.05 (Map)

Reviews
12th Dec 2015 IcemanBo: Too long as NeedsFix. Rejected. 02:35, 30th Aug 2012 Magtheridon96: I've been trying to moderate this for quite some time, but every time I get to it, I get discouraged because of the variable names :L ufsVAR_ is a really...

Moderator

M

Moderator

12th Dec 2015
IcemanBo: Too long as NeedsFix. Rejected.

02:35, 30th Aug 2012
Magtheridon96: I've been trying to moderate this for quite some time, but every time I get to it, I get discouraged because of the variable names :L
ufsVAR_ is a really bad prefix because the VAR is extraneous and it's camelCamed.
In GUI, variable names should be written LikeThis because they're clearer that way.
In JASS, they are camelCased because they make the code look clearer.

I'm really sorry for this mediocre review, but it would still be a great improvement if you were to change the variable names.

ufsVar_unitTag can be something like FusionUnitTag or maybe FusionSysUnit. Really, anything to add clarity would be awesome.

Thank you for taking the time to read this, and thank you for the submission.
 
Level 33
Joined
Mar 27, 2008
Messages
8,035
  • For each (Integer B) from 1 to ufsVAR_unitId, do (Actions)
You could use IntegerVariable, remember ?

(Owner of (Triggering unit)))
(Owner of (Triggering unit)) -> (Triggering player), uses less function calls

Does this system only for Units ?
What about Heroes ?
I think it's pretty cool to fuse Hero-unit (but you gotta have limits to it (something like limit production of Unit A (Unit A + Unit A = Unit B), because Hero holds unique data, could possibly takes up the game engine space if you replace too many Hero)

Indexing is inefficiently done using a for loop; a future version will use hashtables instead.
You should, to avoid unneeded loops.
 
Level 25
Joined
Jul 10, 2006
Messages
3,315
(Owner of (Triggering unit)) -> (Triggering player), uses less function calls

Will this work even though the event is a unit event? Or does that imply the owning player as triggering player?

Does this system only for Units ?
What about Heroes ?
I think it's pretty cool to fuse Hero-unit (but you gotta have limits to it (something like limit production of Unit A (Unit A + Unit A = Unit B), because Hero holds unique data, could possibly takes up the game engine space if you replace too many Hero)

It will work with heroes as if they are units.

I'll add hero-specific functionality, such as combining stats, experience and items.
 
Level 14
Joined
Aug 8, 2010
Messages
1,021
Another good system from ruleronfire. I like it. But it needs more unit combinations. Also you can make it with levels. For example if unit1 and unit2 get combined, you create level 1 of unit3. But if 2 types of unit1 and 2 types of unit2 get combined, you create level 2 of unit3. This will be a good addition.

By the way, uploading things "under construction" is forbidden, isn't it?
 
Level 25
Joined
Jul 10, 2006
Messages
3,315
Another good system from ruleronfire. I like it. But it needs more unit combinations. Also you can make it with levels. For example if unit1 and unit2 get combined, you create level 1 of unit3. But if 2 types of unit1 and 2 types of unit2 get combined, you create level 2 of unit3. This will be a good addition.

Thanks for the input and idea, I'll add that functionality after I fix multiples of same unit types in the recipe.

By the way, uploading things "under construction" is forbidden, isn't it?

Technically the system works, albeit in a hard-to-configure way.

I added the "under constuction" note so that moderators shouldn't waste their time reviewing this until it meets the proper requirements. I uploaded it in case anyone wants to use it; and of course so that I can get feedback from you lot :)
 
Level 33
Joined
Mar 27, 2008
Messages
8,035
Suggestions;
- Add Selection to the newly fused unit to the Player (you don't have to re-select the fused unit)
- Add a proper documentary (both on this thread and inside Trigger Editor) on how to actually use it (I just blindly picking up 2 units and accidentally cast the Fuse ability), so I discover how to use your system (in-game) by accidents. That is in-game, but what about in Trigger Editor (Setup) trigger ? You should add a Trigger Comments there to let people easier to understand how to manipulate your system.
 
Level 25
Joined
Jul 10, 2006
Messages
3,315
This only works for player 1

  • Unit - Create 1 ufsVAR_unitType[forA] for Player 1 (Red) at tempLoc facing Default building facing degrees
also put some prefix on x/y variables - to common name

Whoops, fixing.

and wtf who said indexing is inefficient

If the system is used to check a few hundred unit types, wouldn't a hashtable be more efficient than checking each element in an array?
 
Level 23
Joined
Apr 16, 2012
Messages
4,041
array lookup is faster then hashtable, hashtable works the way that more filled it is the slower it is so no if you are not working with things like unit-type Id's there is no need to use hashtables
EDIT:
also you can only have 255 hashtables per map and when you init it you cant get rid of it(there is no destroy hashtable, the max you can get is flush parent hashtbale)
 
Top