1. Are you planning to upload your awesome spell or system to Hive? Please review the rules here.
    Dismiss Notice
  2. Join Texturing Contest #30 now in a legendary battle of mythological creatures!
    Dismiss Notice
  3. The Aftermath has been revealed for the 19th Terraining Contest! Be sure to check out the Results and see what came out of it.
    Dismiss Notice
  4. Melee Mapping Contest #3 - Results are out! Congratulate the winners and check plenty of new 4v4 melee maps designed for this competition!
    Dismiss Notice
  5. The winners of our cinematic soundtrack competition have been decided! Step by the Music Contest #11 - Results to check the entries and congratulate the winners!
    Dismiss Notice
  6. Check out the Staff job openings thread.
    Dismiss Notice

[GUI-Friendly] Unit Fusion System

Submitted by Tasyen
This bundle is marked as approved. It works and satisfies the submission rules.
Unit Fusion System is a System handling Spells making unit Fuse/tribute for summoning.

Features:
  • Define own custom Conditions for material (like over 50% HP)
  • Supports Target Point/Unit/non-Target Casts
  • Instant Fusions
  • FadeIn Fusions (Fusion Result starts with 100% transparency and become more visible over time)
  • PullTogehter Fusions (the Fusion parts will be pulled together)
  • PullTogehter and FadeIn can be combined
  • "Quite easy" adding additional Fusion/Sacrifice Spells
  • Kill/Remove Merging Unita and pull together a new unitType
  • Supports Hero Fusions.
  • Supports Timed Fusions, with defusions or simple timed life.
Code (vJASS):

//Unit Fusion System V8a
//by Tasyen
//======================================
//API
//======================================
//   function UnitDefusion takes unit u, boolean killed, integer indexFusion returns nothing
//       tries to defuse an unit u, killed, or Defusionen Index
//       indexFusion is faster, but most times you won't know the DefusionIndex
//       If you do not know the defusion index call it with -1

//   function UnitFusionStartFadeIn takes unit u, real dur, real hiddenStateAfter, string sfx, boolean immunDuringFade returns nothing
//       pauses an unit and makes it transparent both will be lost over time.
//       the pausing will be reapplied every timeout of "UnitFusionTimerSpeed"
//       - u the unit
//       - dur how long the process will take in seconds.
//       - hiddenStateAfter this much % will the unit stay transparent after finishing the process (expects a number from 0 to 100)
//       - sfx the modell which will displayed during the fadein
//       - immunDuringFade if true the unit becomes invulnurable during fadein.
//       - This will throw an FadeInFinish-Event with Fusion_Event_SpellData = -1
//       - To Manipulate this used Fusion_Object use udg_Fusion_Current_CreatedObject right after calling it.

//   function UnitFusionTimerStart takes nothing returns nothing
//       Activaded automatacly normally.
//       will start the System-timer, withthat the fusion behaviour overall.
//       use it if you stopped the timer manually.
//       "udg_Fusion_System_TimerDisabled = true" will prevent starting the timer that way.

//======================================
//   Fusion_Data_HeroStatsMod:
//    0 uses Results default
//    1 uses Average of fusion members
//    2 uses sum of fusion members

//   Fusion_Data_DefuseAfterDurHP is a % value between 0 and 1 or -1 to use Fusions %

//   Fusion_Event
//
//       1 = NonHero Fusion
//       2 = Hero Fusion
//       3 = FadeInFinish
//       -1 = Defusion

//       Fusion_Event_Fusion = the Fusion
//       Fusion_Event_Source = the Source casted fusion spell.
//       Fusion_Event_Group  = the merged/demerged Units; is does not contain substitutes.
//       Fusion_Event_SpellData = the data index of the used Spell for fusing.
//       Fusion_Event_SpellLevel = the level with which the fusion was casted.

//       Fusion_Event_SpellObject = the FusionObjectIndex with this you an manipulate data inside an event, most time unneeded.


// Arrays here generally start with 1

//======================================
//Constants
//======================================
//Will the Fusion will be automatacly added to the selection of the owning Player?
constant function UnitFusionAutoSelect takes nothing returns boolean
   return true
endfunction
constant function UnitFusionErrorMsg takes nothing returns string
   return "Misses:"
endfunction  

//ErrorMessage for each Missing Wildcard Unit.
//Looks like this:
//Misses:
// - Peon
// - Warlock
// - WildCard-Unit
// - WildCard-Unit
//
constant function UnitFusionWildCard takes nothing returns string
   return " - WildCard-Unit"
endfunction

//How much is an unit transparent while flying 255 = 0%, 0 = 100%
constant function UnitFusionFade takes nothing returns integer
   return 128
endfunction

//This is used to get units beeing at the edge of the AoE Indikator of a spell, beeing inside wither their hitbox.
constant function UnitMaxColison takes nothing returns real
   return 200.0
endfunction


//Intervale used for fadingIn/Pulling
constant function UnitFusionTimerSpeed  takes nothing returns real
   return 0.05
endfunction  

//How long one does see what is missing to fuse in seconds
constant function UnitFusionErrorDur takes nothing returns real
   return 11.0
endfunction

constant function UnitFusionEventNonHero takes nothing returns real
   return 1.0
endfunction
constant function UnitFusionEventHero takes nothing returns real
   return 2.0
endfunction
constant function UnitFusionEventFadeInFinish takes nothing returns real
   return 3.0
endfunction
constant function UnitFusionEventDefusion takes nothing returns real
   return -1.0
endfunction
//The Fusion_Current_ItemStack usage for Defusions starts at Offset.
constant function UnitDefusionItemOffset takes nothing returns integer
   return 200
endfunction
//Used by Fusion_Object_Type
constant function UnitFusionTypePull takes nothing returns string
   return "UnitFusionPulled"
endfunction
constant function UnitFusionTypeDefusion takes nothing returns string
   return "UnitDefusionMonitor"
endfunction
constant function UnitFusionTypeFadeIn takes nothing returns string
   return "UnitFusionFadeIn"
endfunction

function StringIsEmpty takes string s returns boolean
   return s == null or s == ""
endfunction
//======================================
//Code - Starts
//======================================
//This will return the Entering Index of the new Object
//And creates an pointer pointing at it.
//The LastUsed ObjectIndex is saved in udg_Fusion_Current_CreatedObject.
function UnitFusionInserObject takes nothing returns integer
   local integer returnValue
   if  udg_Fusion_System_ReuseSize > 0 then
       set returnValue = udg_Fusion_System_Reuse[udg_Fusion_System_ReuseSize]
       set udg_Fusion_System_ReuseSize = udg_Fusion_System_ReuseSize - 1
   else
       set udg_Fusion_System_ObjectSize = udg_Fusion_System_ObjectSize + 1
       set returnValue = udg_Fusion_System_ObjectSize
   endif
   set udg_Fusion_Current_CreatedObject = returnValue
   //Create Pointer with used Object.
   set udg_Fusion_System_Pointer_Last = udg_Fusion_System_Pointer_Last + 1
   set udg_Fusion_System_Pointer[udg_Fusion_System_Pointer_Last] = returnValue
   set udg_Fusion_Object_Pointer[returnValue] = udg_Fusion_System_Pointer_Last
   set udg_Fusion_System_Pointer_Finished[udg_Fusion_System_Pointer_Last] = false
   return returnValue
endfunction


//Will give you the index of an free spot in the Defusion Items.
function UnitDefusionItemGetFreeSpot takes nothing returns integer
   local integer returnValue
   if udg_Fusion_Item_DefReuseSize > 0 then
       set returnValue = udg_Fusion_Item_DefReuse[udg_Fusion_Item_DefReuseSize]
       set udg_Fusion_Item_DefReuseSize = udg_Fusion_Item_DefReuseSize - 1
   else
       set udg_Fusion_Item_DefSize = udg_Fusion_Item_DefSize + 1
       set returnValue = udg_Fusion_Item_DefSize
   endif
   return returnValue
endfunction

// Will Create a new Fusion Object
//Cloning Fusion, Source,LEvel,Owner,Data, add all Units to the a group
function UnitFusionCloneObject takes integer sourceObject returns integer
   local integer indexObject = UnitFusionInserObject()
   if udg_Fusion_Object_Loc[indexObject] == null then
       set udg_Fusion_Object_Loc[indexObject] = Location(GetLocationX(udg_Fusion_Object_Loc[sourceObject]),GetLocationY(udg_Fusion_Object_Loc[sourceObject]))
   else
       call MoveLocation(udg_Fusion_Object_Loc[indexObject],GetLocationX(udg_Fusion_Object_Loc[sourceObject]),GetLocationY(udg_Fusion_Object_Loc[sourceObject]))
   endif
   if udg_Fusion_Object_Group[indexObject] == null then
       set udg_Fusion_Object_Group[indexObject] = CreateGroup()
   else
       call GroupClear(udg_Fusion_Object_Group[indexObject])
   endif
   set udg_Fusion_Object_Fusion[indexObject] = udg_Fusion_Object_Fusion[sourceObject]
   set udg_Fusion_Object_Source[indexObject] = udg_Fusion_Object_Source[sourceObject]
   set udg_Fusion_Object_SpellLevel[indexObject] = udg_Fusion_Object_SpellLevel[sourceObject]

   set udg_Fusion_Object_DataIndex[indexObject] = udg_Fusion_Object_DataIndex[sourceObject]
   set udg_Fusion_Object_Effect[indexObject] = null
   call GroupAddGroup(udg_Fusion_Object_Group[sourceObject],udg_Fusion_Object_Group[indexObject])
//   call printCloneGroups(udg_Fusion_Object_Group[sourceObject],udg_Fusion_Object_Group[indexObject])
   return indexObject
endfunction

function UnitFusionItemStackRemove takes integer indexChoosen returns nothing
   //That makes no sense
   if indexChoosen == -1 then
       return
   endif
   if indexChoosen != udg_Fusion_Item_Size then
       set udg_Fusion_Item_Item[indexChoosen] = udg_Fusion_Item_Item[udg_Fusion_Item_Size]
       set udg_Fusion_Item_Owner[indexChoosen] =  udg_Fusion_Item_Owner[udg_Fusion_Item_Size]
   endif
   set udg_Fusion_Item_Item[udg_Fusion_Item_Size] = null
   set udg_Fusion_Item_Owner[udg_Fusion_Item_Size] = null
   set udg_Fusion_Item_Size = udg_Fusion_Item_Size - 1  
endfunction

//Returns the Item with the highest Level from the stack.
//removeReturned = true will take it from the stack and countdown.
function UnitFusionBestItem takes nothing returns integer
   local integer LoopA = 1
   local integer indexChoosen = -1
   local integer level = 0
   //Find one with highestLevel
   loop
       exitwhen LoopA > udg_Fusion_Item_Size
       if level <  GetItemLevel(udg_Fusion_Item_Item[LoopA]) then
           set indexChoosen = LoopA
           set level = GetItemLevel(udg_Fusion_Item_Item[LoopA])
       endif
       set LoopA = LoopA + 1
   endloop
   return indexChoosen
endfunction

//Returns the ItemTypeId of the item with the highest Level from the stack.
//removeReturned = true will take it from the stack and countdown.
//might be unneeded
function UnitFusionBestItemType takes boolean removeReturned returns integer
   local integer LoopA = 1
   local integer indexChoosen = -1
   local integer itemId = 0
   local integer level = 0
   //Find one with highestLevel
   loop
       exitwhen LoopA > udg_Fusion_Item_Size
       if level <  GetItemLevel(udg_Fusion_Item_Item[LoopA]) then
           set indexChoosen = LoopA
           set itemId = GetItemTypeId(udg_Fusion_Item_Item[indexChoosen])
           set level = GetItemLevel(udg_Fusion_Item_Item[LoopA])
       endif
       set LoopA = LoopA + 1
   endloop
   //Reindex?
   if removeReturned and indexChoosen != -1 then
       if indexChoosen != udg_Fusion_Item_Size then
           set udg_Fusion_Item_Item[indexChoosen] = udg_Fusion_Item_Item[udg_Fusion_Item_Size]
           set udg_Fusion_Item_Owner[udg_Fusion_Item_Size] =  udg_Fusion_Item_Owner[udg_Fusion_Item_Size]
       else
           set udg_Fusion_Item_Item[udg_Fusion_Item_Size] = null
           set udg_Fusion_Item_Owner[udg_Fusion_Item_Size] = null
       endif
       set udg_Fusion_Item_Size = udg_Fusion_Item_Size - 1
   endif
   return itemId
endfunction

//Take items from the ItemStack and move them to the Unit u.
//Will give the hero the best (heighest Level) first
function UnitFusionGiveItems takes unit u returns nothing
   local integer creationCount = UnitInventorySize(u)
   local integer indexChoosen
   local integer indexCurrent
   local integer indexLast
   loop
       exitwhen 0 == udg_Fusion_Item_Size or creationCount == 0
       set indexChoosen = UnitFusionBestItem()
       if indexChoosen != 0 then
           call UnitAddItem (u, udg_Fusion_Item_Item[indexChoosen])
           call UnitFusionItemStackRemove(indexChoosen)
           set creationCount = creationCount - 1
       else
           set creationCount = 0
       endif  
   endloop  
endfunction

//Take items from the ItemStack and move them to the Unit u.
//Will give the hero the best (heighest Level) first
// This will save items and old owners.
function UnitFusionGiveItemsSave takes unit u, integer indexDefusion returns nothing
   local integer creationCount = UnitInventorySize(u)
   local integer indexChoosen
   local integer indexCurrent
   local integer indexLast
   //This is the End point of this Defusions items.
   set udg_Fusion_Object_Int3[indexDefusion] = UnitDefusionItemGetFreeSpot()
   set indexCurrent =udg_Fusion_Object_Int3[indexDefusion]
   loop
       exitwhen 0 == udg_Fusion_Item_Size or creationCount == 0
       set indexChoosen = UnitFusionBestItem()
       if indexChoosen != -1 then
           set indexLast = indexCurrent
           set indexCurrent = UnitDefusionItemGetFreeSpot()
           set udg_Fusion_Item_DefNext[indexLast] = indexCurrent
           set udg_Fusion_Item_Item[indexCurrent] = udg_Fusion_Item_Item[indexChoosen]
           set udg_Fusion_Item_Owner[indexCurrent] = udg_Fusion_Item_Owner[indexChoosen]
           //call BJDebugMsg(GetItemName(udg_Fusion_Item_Item[indexCurrent])+ GetHeroProperName(udg_Fusion_Item_Owner[indexCurrent]))
           call UnitAddItem (u, udg_Fusion_Item_Item[indexChoosen])
           call UnitFusionItemStackRemove(indexChoosen)
           
           set creationCount = creationCount - 1
       else  
           set creationCount = 0  
       endif
   endloop  
   //finish the list
   set udg_Fusion_Item_DefNext[indexCurrent] = -1
endfunction

//This Loads all Items of the unit into the stack.
//Will Count up udg_Fusion_Item_Size
function UnitFusionLoadInventory takes unit u returns nothing
   local integer LoopInventory = 0
   //Gain Items
   if UnitInventorySize(u) != 0 then
       loop
           exitwhen LoopInventory == UnitInventorySize(u)
           if UnitItemInSlot(u, LoopInventory) != null then
               set udg_Fusion_Item_Size = udg_Fusion_Item_Size + 1
               set udg_Fusion_Item_Item[udg_Fusion_Item_Size] =  UnitItemInSlot(u, LoopInventory)
               set udg_Fusion_Item_Owner[udg_Fusion_Item_Size] =  u
           endif  
           set LoopInventory = LoopInventory + 1
       endloop
   endif
endfunction

//Overall timer
//Executes sub actions based on Type.
//Main Index for sub functions are
//   udg_Fusion_Current_Pointer the pointer
function UnitFusionTimer takes nothing returns nothing
   local integer LoopA = 1
   //call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,1,I2S(udg_Fusion_System_Pointer_Last))
   loop
       exitwhen LoopA > udg_Fusion_System_Pointer_Last
       if not udg_Fusion_System_Pointer_Finished[LoopA] then
           set udg_Fusion_Current_Pointer = LoopA
           set udg_Fusion_Current_Object = udg_Fusion_System_Pointer[LoopA]
           set udg_Fusion_Current_Data = udg_Fusion_Object_DataIndex[udg_Fusion_Current_Object]
           call ExecuteFunc(udg_Fusion_Object_Type[udg_Fusion_Current_Object])
       else
           //Mark DataRow reusable
           set udg_Fusion_System_ReuseSize = udg_Fusion_System_ReuseSize + 1
           set udg_Fusion_System_Reuse[udg_Fusion_System_ReuseSize] = udg_Fusion_System_Pointer[LoopA]
           //Pointer Reindex
           set udg_Fusion_Object_Pointer[udg_Fusion_System_Pointer[LoopA]] = udg_Fusion_System_Pointer_Last
           set udg_Fusion_System_Pointer_Finished[LoopA] = udg_Fusion_System_Pointer_Finished[udg_Fusion_System_Pointer_Last]
           set udg_Fusion_System_Pointer[LoopA] = udg_Fusion_System_Pointer[udg_Fusion_System_Pointer_Last]
           set udg_Fusion_System_Pointer_Last = udg_Fusion_System_Pointer_Last - 1
           set LoopA = LoopA - 1
       endif  
       set LoopA = LoopA + 1
   endloop
   if udg_Fusion_System_Pointer_Last == 0 then
       call PauseTimer(udg_Fusion_System_Timer)
   endif
endfunction

//This is called to (re)start the timer.
function UnitFusionTimerStart takes nothing returns nothing
   if not udg_Fusion_System_TimerDisabled then
       call TimerStart(udg_Fusion_System_Timer, UnitFusionTimerSpeed(),true, function UnitFusionTimer)
   endif
endfunction

function UnitDropInventory takes unit u returns nothing
   local integer LoopInventory = UnitInventorySize(u)
   if UnitInventorySize(u) != 0 then
       loop
           set LoopInventory = LoopInventory - 1
           exitwhen LoopInventory == -1
           call UnitRemoveItemFromSlot(u, LoopInventory)
       endloop
   endif  
endfunction

//This function will defusion an fusion unit.
//call it with index -1, if you don't know the Defusion index.
function UnitDefusion takes unit u, boolean killed, integer indexFusion returns nothing
   local integer LoopA = 1
   local integer LoopB
   local integer itemIndex
   local integer indexData
   local real x
   local real x2
   local real y
   local real y2
   local real angleInc
   local real angle
   local item i
   local integer amountMats
   local integer exp
   local unit fog
   local boolean wasSelected = IsUnitSelected(u, GetOwningPlayer(u))
   //Skip calls using unit without anyone in users.
   if FirstOfGroup(udg_Fusion_System_DefusionUser) == null and indexFusion == -1 then
       return
   endif  
   //call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 5, "Defusion")
   //When indexFusion unknown find it.
   if indexFusion == - 1 then
       loop
           exitwhen LoopA > udg_Fusion_System_Pointer_Last
           //Find Defusion
           if u == udg_Fusion_Object_Fusion[udg_Fusion_System_Pointer[LoopA]]   then
//               call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 5, "Nr:"+I2S(LoopA))
               set indexFusion = udg_Fusion_System_Pointer[LoopA]
               set udg_Fusion_System_Pointer_Finished[LoopA] = true
               exitwhen true
           endif
           set LoopA = LoopA + 1
       endloop
       set x = GetUnitX(u)
       set y = GetUnitY(u)
   else
       set udg_Fusion_System_Pointer_Finished[udg_Fusion_Object_Pointer[indexFusion]] = true
       set u = udg_Fusion_Object_Fusion[indexFusion]
       set x = GetLocationX(udg_Fusion_Object_Loc[indexFusion])
       set y = GetLocationY(udg_Fusion_Object_Loc[indexFusion])
   endif
   call GroupRemoveUnit(udg_Fusion_System_DefusionUser, u)
   //not found?
   if indexFusion == -1 then
       return
   endif  
   set indexData = udg_Fusion_Object_DataIndex[indexFusion]
   set amountMats = CountUnitsInGroup (udg_Fusion_Object_Group[indexFusion])
   //call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 5,  GetObjectName(udg_Fusion_Data_Spell[indexData]))
   call DestroyEffect( AddSpecialEffect(udg_Fusion_Data_DefuseSFX[indexData],x,y))
   //Drop Items and give them to their owners.
   if   udg_Fusion_Object_Int3[indexFusion] != -1 then
       set itemIndex = udg_Fusion_Object_Int3[indexFusion]
       loop
           exitwhen itemIndex == -1
           //call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 5, "Item Nr: "+I2S(itemIndex)+GetItemName(udg_Fusion_Item_Item[itemIndex]))
           if UnitHasItem(u, udg_Fusion_Item_Item[itemIndex]) then
   //           call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 5, "Give it to: "+I2S(itemIndex)+GetHeroProperName(udg_Fusion_Item_Owner[itemIndex]))
               call PauseUnit(udg_Fusion_Item_Owner[itemIndex], false)
               call ShowUnit(udg_Fusion_Item_Owner[itemIndex], true)
               call UnitAddItem(udg_Fusion_Item_Owner[itemIndex], udg_Fusion_Item_Item[itemIndex])
           endif
           //mark as free.
           set udg_Fusion_Item_DefReuseSize = udg_Fusion_Item_DefReuseSize + 1
           set udg_Fusion_Item_DefReuse[udg_Fusion_Item_DefReuseSize] = itemIndex
           //next item
           set itemIndex = udg_Fusion_Item_DefNext[itemIndex]
       endloop
       //Drop all items from the fusion.
       set LoopA = UnitInventorySize(u) - 1
       loop
           exitwhen LoopA == -1
           call SetItemPosition( UnitItemInSlot (u, LoopA),x,y)
           set LoopA = LoopA - 1
       endloop
   endif  
   //Prepare Event
   set udg_Fusion_Event_Fusion = u
   set udg_Fusion_Event_Source = udg_Fusion_Object_Source[indexFusion]
   set udg_Fusion_Event_SpellData = udg_Fusion_Object_DataIndex[indexFusion]
   set udg_Fusion_Event_SpellLevel = udg_Fusion_Object_SpellLevel[indexFusion]
   set udg_Fusion_Event_SpellObject = indexFusion
   call  GroupClear (udg_Fusion_Event_Group)
   //Remove the Fuion?
   if udg_Fusion_Data_Remove[indexData] then
       call RemoveUnit(u)
   else
       //Might be a Custom call to defuse
       call KillUnit(u)
   endif
   set angle = 0
   set angleInc = 2 * bj_PI / amountMats
   //Current Exp - old exp = gained Exp
   set exp = R2I((udg_Fusion_Object_Int2[indexFusion] - udg_Fusion_Object_Int1[indexFusion]) * udg_Fusion_Data_DefusionEXPMulti[indexData] / amountMats)
   //Restore fusion Parts.
   loop
       set fog = FirstOfGroup (udg_Fusion_Object_Group[indexFusion])
       exitwhen fog == null
       call GroupRemoveUnit(udg_Fusion_Object_Group[indexFusion],fog)
       set x2 = x + udg_Fusion_Data_DefuseDistance[indexData]*Cos(angle)
       set y2 = y + udg_Fusion_Data_DefuseDistance[indexData]*Sin(angle)
       set angle = angle + angleInc
   //   call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 5, "ReGain "+GetUnitName(fog) )
       //Make Mats useable
       call SetUnitPosition(fog, x2,y2)
       call ShowUnit(fog,true)
       call PauseUnit(fog,false)
       call SetUnitInvulnerable(fog, false )
       call SetUnitPathing (fog, true)
       call SetUnitVertexColor(fog,255,255,255,255)
       call UnitRemoveAbility(fog ,'Arav')
       call AddHeroXP(fog, exp, true)
       if udg_Fusion_Data_DefuseDispellMat[indexData] then
           call UnitRemoveBuffs(fog, true, true)
       endif
       call SetUnitFacing(fog,bj_RADTODEG * Atan2(y - y2, x - x2))
       //Load defused material into fusionGroup
       call GroupAddUnit(udg_Fusion_Event_Group, fog)
       //What shall happen with the mat?
       if (killed and not udg_Fusion_Data_DefuseOnKilled[indexData]) or ( not killed and not udg_Fusion_Data_DefuseAfterDur[indexData] )then
           //units are lost.
           call UnitDropInventory(fog)
           call RemoveUnit(fog)
       else
           call SetUnitUseFood( fog, true )
           if wasSelected then
               call SelectUnitAddForPlayer( fog, GetOwningPlayer(fog))
           endif
           if killed then
               //call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 5, "Fusion killed/Removed - Set Restored Unit's Life to ="+GetUnitName(u)+" "+ R2S(( GetUnitState(u, UNIT_STATE_MAX_LIFE))* udg_Fusion_Data_DefuseOnKilledHP[indexData]))
               call SetUnitState(fog, UNIT_STATE_LIFE, GetUnitState(fog, UNIT_STATE_MAX_LIFE) * udg_Fusion_Data_DefuseOnKilledHP[indexData])
               call SetUnitState(fog, UNIT_STATE_MANA, GetUnitState(fog, UNIT_STATE_MAX_MANA) * udg_Fusion_Data_DefuseOnKilledMP[indexData])
           else
               if udg_Fusion_Data_DefuseAfterDurHP[indexData] == -1 then
                   call SetUnitState(fog, UNIT_STATE_LIFE, GetUnitState(fog, UNIT_STATE_MAX_LIFE) * udg_Fusion_Object_Real1[indexFusion])
               else
                   call SetUnitState(fog, UNIT_STATE_LIFE, GetUnitState(fog, UNIT_STATE_MAX_LIFE) * udg_Fusion_Data_DefuseAfterDurHP[indexData])
               endif
               if udg_Fusion_Data_DefuseAfterDurMP[indexData] == -1 then
                   call SetUnitState(fog, UNIT_STATE_MANA, GetUnitState(fog, UNIT_STATE_MAX_MANA) * udg_Fusion_Object_Real2[indexFusion])
               else
                   call SetUnitState(fog, UNIT_STATE_MANA, GetUnitState(fog, UNIT_STATE_MAX_MANA) * udg_Fusion_Data_DefuseAfterDurMP[indexData])
               endif
           endif
       endif
   endloop
   //Throw Event
   set udg_Fusion_Event = UnitFusionEventDefusion()
   set udg_Fusion_Event = 0
endfunction

//Will get one the Life and Mana from the Defusion. To use on defusion.
//   Int1 = Old EP
//   Int2 = current ep
//   Real1 = current Life
//   Real2 = current Mana.
function UnitDefusionMonitor takes nothing returns nothing
   local integer indexObject = udg_Fusion_System_Pointer[udg_Fusion_Current_Pointer]
   
   //was Removed?
   if GetUnitState(udg_Fusion_Object_Fusion[indexObject], UNIT_STATE_MAX_LIFE) != 0  then

       set udg_Fusion_Object_Int2[indexObject] = GetHeroXP (udg_Fusion_Object_Fusion[indexObject])
       call MoveLocation(udg_Fusion_Object_Loc[indexObject],GetUnitX(udg_Fusion_Object_Fusion[indexObject]),GetUnitY(udg_Fusion_Object_Fusion[indexObject]))
       
   //Percent
       set udg_Fusion_Object_Real1[indexObject] = GetUnitState( udg_Fusion_Object_Fusion[indexObject], UNIT_STATE_LIFE)/ GetUnitState( udg_Fusion_Object_Fusion[indexObject], UNIT_STATE_MAX_LIFE)
       if GetUnitState(udg_Fusion_Object_Fusion[indexObject], UNIT_STATE_MAX_MANA) != 0 then
           set udg_Fusion_Object_Real2[indexObject] = GetUnitState( udg_Fusion_Object_Fusion[indexObject], UNIT_STATE_MANA)/GetUnitState( udg_Fusion_Object_Fusion[indexObject], UNIT_STATE_MAX_MANA)
       endif  
   else
       //call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 5, "Force Defusion: ")
       call UnitDefusion(null, true, indexObject)
   endif  
endfunction

//Triggers if an Unit dies.
function UnitDefusionDeath takes nothing returns nothing
   if IsUnitInGroup (GetTriggerUnit(), udg_Fusion_System_DefusionUser) then
       call UnitDefusion(GetTriggerUnit(), (GetKillingUnit() != null), -1 )
   endif
endfunction

//This will use the given Fusion_Object and use it for defusion
//If you need an new one call it with InserObject or with cloneObject
function UnitDefusionTransformObject takes integer indexObject returns nothing
   set udg_Fusion_Object_Int1[indexObject] = GetHeroXP (udg_Fusion_Object_Fusion[indexObject])
   set udg_Fusion_Object_Int2[indexObject] =  udg_Fusion_Object_Int1[indexObject]
   //Next Line saves defusions if they do not take over items
   set udg_Fusion_Object_Int3[indexObject] = -1
   set udg_Fusion_Object_Type[indexObject] = UnitFusionTypeDefusion()
   call DestroyEffect(udg_Fusion_Object_Effect[indexObject])
   set udg_Fusion_Object_Effect[indexObject] = null
   call GroupAddUnit(udg_Fusion_System_DefusionUser, udg_Fusion_Object_Fusion[indexObject])
   call UnitFusionTimerStart()
endfunction

//perfoms actions an Material for Defusion should do.
function UnitDefusionSaveMatObject takes unit u, integer indexObject returns nothing
   call GroupAddUnit(udg_Fusion_Object_Group[indexObject], u)
   call SetUnitInvulnerable(u, true )
   call PauseUnit(u, true )
   call ShowUnit(u, false)
   call SetUnitUseFood( u, false )
   call SetUnitPathing (u, false)
   call SetUnitPositionLoc(u, udg_Fusion_System_SaveLoc)
endfunction

//Action
// Real1 = remaningDur in seconds.
// Real2 = CurrentTransparenz
// Real3 = Transparenz change a intervale
function UnitFusionFadeIn  takes nothing returns nothing
   local integer indexObject = udg_Fusion_System_Pointer[udg_Fusion_Current_Pointer]
   local integer indexData = udg_Fusion_Object_DataIndex[indexObject]
   //Stop instantly when Fusion Unit was removed/dead.
   if GetWidgetLife(udg_Fusion_Object_Fusion[indexObject]) < 0.405 then
       set udg_Fusion_System_Pointer_Finished[udg_Fusion_Current_Pointer] = true
       call DestroyEffect(udg_Fusion_Object_Effect[indexObject])
       set udg_Fusion_Object_Effect[indexObject] = null
       return
   endif
   //Calc new Transperence
   set udg_Fusion_Object_Real2[indexObject] = udg_Fusion_Object_Real2[indexObject] + udg_Fusion_Object_Real3[indexObject]
   call SetUnitVertexColor(udg_Fusion_Object_Fusion[indexObject], 255, 255, 255, R2I(udg_Fusion_Object_Real2[indexObject]))
   set udg_Fusion_Object_Real1[indexObject] = udg_Fusion_Object_Real1[indexObject] - UnitFusionTimerSpeed()
   
   //FadeIn Finish?
   if udg_Fusion_Object_Real1[indexObject] <= 0.0 then
       set udg_Fusion_System_Pointer_Finished[udg_Fusion_Current_Pointer] = true
       //Finish destroy
       if not udg_Fusion_Object_Bool[indexObject] then
           call SetUnitInvulnerable(udg_Fusion_Object_Fusion[indexObject], false )
       endif
       call PauseUnit(udg_Fusion_Object_Fusion[indexObject], false)
       if UnitFusionAutoSelect() then
           call SelectUnitAddForPlayer(udg_Fusion_Object_Fusion[indexObject], GetOwningPlayer(udg_Fusion_Object_Fusion[indexObject]))
       endif
       //call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, UnitFusionErrorDur(),  udg_Fusion_Data_SFXResult[indexData] +" "+ udg_Fusion_Data_SFXResultAttacht[indexData] )
       call DestroyEffect(AddSpecialEffectTarget( udg_Fusion_Data_SFXResult[indexData] , udg_Fusion_Object_Fusion[indexObject],udg_Fusion_Data_SFXResultAttacht[indexData] ))
       call DestroyEffect(udg_Fusion_Object_Effect[indexObject])
       set udg_Fusion_Object_Effect[indexObject] = null
       //Throw Event
       call  GroupClear (udg_Fusion_Event_Group)
       call GroupAddGroup(udg_Fusion_Object_Group[indexObject], udg_Fusion_Event_Group)
       set udg_Fusion_Event_Fusion = udg_Fusion_Object_Fusion[indexObject]
       set udg_Fusion_Event_Source = udg_Fusion_Object_Source[indexObject]
       set udg_Fusion_Event_SpellData = indexData
       set udg_Fusion_Event_SpellLevel = udg_Fusion_Object_SpellLevel[indexObject]
       set udg_Fusion_Event_SpellObject = indexObject
       set udg_Fusion_Event = UnitFusionEventFadeInFinish()
       set udg_Fusion_Event = 0
       //this will clean the objct on next timer intervale
       else
           call PauseUnit(udg_Fusion_Object_Fusion[indexObject], true)
       endif  
endfunction

//Takeover an FusionObject for fading in
//To start an new call it with cloneObject(orginalObject)
// Real1 = remaningDur in seconds.
// Real2 = CurrentTransparenz
// Real3 = Transparenz change a intervale
function UnitFusionStartFadeInTakeOver  takes integer indexObject returns nothing
   local integer indexData = udg_Fusion_Object_DataIndex[indexObject]
   if not udg_Fusion_Data_FadeVulnerable[indexData] then
       call SetUnitInvulnerable( udg_Fusion_Object_Fusion[indexObject], true )
   endif
   set udg_Fusion_Object_Bool[indexObject] = udg_Fusion_Data_FadeVulnerable[indexData]
   call PauseUnit(udg_Fusion_Object_Fusion[indexObject], true)
   call SetUnitVertexColor(udg_Fusion_Object_Fusion[indexObject], 255, 255, 255, 0)
   if udg_Fusion_Object_Effect[indexObject] == null then
       set udg_Fusion_Object_Effect[indexObject] = AddSpecialEffect( udg_Fusion_Data_SFX[indexData] , GetUnitX(udg_Fusion_Object_Fusion[indexObject]),GetUnitY(udg_Fusion_Object_Fusion[indexObject]))
   endif
   set udg_Fusion_Object_Type[indexObject] = UnitFusionTypeFadeIn()
   set udg_Fusion_Object_Real1[indexObject] = udg_Fusion_Data_FadeIn[indexData]
   set udg_Fusion_Object_Real2[indexObject] = 0
   set udg_Fusion_Object_Real3[indexObject]= PercentToInt(100 - udg_Fusion_Data_FadeInHidden[indexData], 255) / udg_Fusion_Data_FadeIn[indexData] * UnitFusionTimerSpeed()
   //Duration above 0?
   if udg_Fusion_Data_ResultDur[indexData] + udg_Fusion_Data_ResultDurPerLevel[indexData] * udg_Fusion_Object_SpellLevel[indexObject] > 0 then
       call UnitApplyTimedLife( udg_Fusion_Object_Fusion[indexObject], 'BTLF', udg_Fusion_Data_ResultDur[indexData] + udg_Fusion_Data_ResultDurPerLevel[indexData] * udg_Fusion_Object_SpellLevel[indexObject] )
   endif  
   call UnitFusionTimerStart()
endfunction


//Start FadingIn for u
// Creates a new Fusion Object.
//This for peouple who want to use the fadeinEffect.
function UnitFusionStartFadeIn takes unit u, real dur, real hiddenStateAfter, string sfx, boolean immunDuringFade returns nothing
   local integer indexObject
   set indexObject = UnitFusionInserObject()
   if immunDuringFade then
       call SetUnitInvulnerable( u, true )
   endif
   set udg_Fusion_Object_Bool[indexObject] = immunDuringFade
   call PauseUnit(u, true)
   call SetUnitVertexColor(u, 255, 255, 255, 0)
   //Call it without unit.
   set udg_Fusion_Object_Fusion[indexObject] = u
   set udg_Fusion_Object_Type[indexObject] = UnitFusionTypeFadeIn()
   set udg_Fusion_Object_Real1[indexObject] = dur
   set udg_Fusion_Object_DataIndex[indexObject] = -1
   //Create new effect?
   set udg_Fusion_Object_Effect[indexObject] = AddSpecialEffect( sfx, GetUnitX(u), GetUnitY(u) )
   set udg_Fusion_Object_Real2[indexObject] = 0
   set udg_Fusion_Object_Real3[indexObject]= PercentToInt(100 - hiddenStateAfter, 255) / dur * UnitFusionTimerSpeed()
   call UnitFusionTimerStart()
endfunction

function UnitFusionPulledGetItems takes nothing returns nothing
   call UnitFusionLoadInventory(GetEnumUnit())
endfunction

//Subfunction - UnitFusionPulled
//Removes the material
function UnitFusionCleanMats takes nothing returns nothing
   local unit u = GetEnumUnit()
   call ShowUnit(u, false)
   call ShowUnit(u, true)
   if udg_Fusion_Data_Remove[udg_Fusion_Current_Data] then
           call UnitDropInventory(u)
           call RemoveUnit(u)
       else
           call KillUnit(u)  
   endif
   set u = null
endfunction

//Subfunction - UnitFusionPulled
//Removes substitutes missles
function UnitFusionPulledClean takes nothing returns nothing
   local unit u = GetEnumUnit()
   if GetUnitTypeId(u) == udg_Fusion_Data_Replace[udg_Fusion_Current_Data] then
       call GroupRemoveUnit(udg_Fusion_Object_Group[udg_Fusion_Current_Object] , u)
       call RemoveUnit(u)
   endif
   set u = null  
endfunction

//Loads real Units into the FusionEventGroup
//Old - Unneeded
function UnitFusionLoadParts takes nothing returns nothing
   if  GetUnitTypeId(GetEnumUnit()) != udg_Fusion_Data_Replace[udg_Fusion_Current_Data] then
       call GroupAddUnit (udg_Fusion_Event_Group, GetEnumUnit())
   endif
endfunction

//Subfunction - UnitFusionPulled
//Group Enumeration of Current FusionGroup
//Real1 = Speed
//Real2 = ZSpeed
function UnitFusionPulledPull takes nothing returns nothing
   local integer indexObject = udg_Fusion_System_Pointer[udg_Fusion_Current_Pointer]
   local integer indexData = udg_Fusion_Object_DataIndex[indexObject]
   local unit u = GetEnumUnit()
   local real x
   local real y
   local real angle
   //call BJDebugMsg("Pull")
   //do not move real units if there is an replace.
   if udg_Fusion_Data_Replace[indexData] != 0 and GetUnitTypeId(u) != udg_Fusion_Data_Replace[indexData] then
       return
   endif
   //Flying enabled?
   if udg_Fusion_Object_Real2[indexObject] > 0 then
        call SetUnitFlyHeight( u, ( GetUnitFlyHeight(u) + udg_Fusion_Object_Real2[indexObject] ), 0.00 )
    endif
   //Avoid Moving units over the Location; hidden defusion using an replace do not matter.
    if    IsUnitInRangeLoc(u, udg_Fusion_Object_Loc[indexObject], udg_Fusion_Object_Real1[indexObject]) or ((udg_Fusion_Data_DefuseAfterDur[indexData] or udg_Fusion_Data_DefuseOnKilled[indexData]) and udg_Fusion_Data_Replace[indexData] == 0 and GetUnitTypeId(u) != udg_Fusion_Data_Replace[indexData]) then
       call SetUnitPositionLoc( u, udg_Fusion_Object_Loc[indexObject] )
    else
       set udg_Fusion_Object_Bool[indexObject] = false
       set x = GetUnitX(u)
       set y = GetUnitY(u)
       set angle =  Atan2(GetLocationY(udg_Fusion_Object_Loc[indexObject]) - y, GetLocationX(udg_Fusion_Object_Loc[indexObject]) - x)
       set x = x + udg_Fusion_Object_Real1[indexObject] * Cos(angle)
       set y = y + udg_Fusion_Object_Real1[indexObject] * Sin(angle)
    call SetUnitPosition( u, x,y )
    endif
endfunction

//Group Action to take defusion Material out of play.
function UnitFusionSaveMat takes nothing returns nothing
   call UnitDefusionSaveMatObject(GetEnumUnit(),udg_Fusion_Current_Object)
endfunction

//Spawns the Fusion
//Based on the Fusion Object
//Will fill udg_Fusion_Object_Fusion[indexObject] with the fusion.

function UnitFusionSpawn takes integer indexObject, real x, real y returns nothing
   local integer indexData = udg_Fusion_Object_DataIndex[indexObject]
   local unit u = CreateUnit (GetOwningPlayer(udg_Fusion_Object_Source[indexObject]), udg_Fusion_Data_Result[indexData], x, y, 270 )
   local boolean hasInventory =  (UnitInventorySize(u) != 0)
   local boolean defusion = udg_Fusion_Data_DefuseAfterDur[indexData] or udg_Fusion_Data_DefuseOnKilled[indexData]
   call UnitAddAbility(u, udg_Fusion_Data_SkillGained[indexData])
   set udg_Fusion_Object_Fusion[indexObject] = u
   call  SetHeroLevel (u, udg_Fusion_Object_Int1[indexObject], false)
   
   //Which Statmod, statsmod 0 is default?
   if udg_Fusion_Data_HeroStatsMod[indexData] != 0 then
       call  SetHeroAgi (u, udg_Fusion_Object_Int2[indexObject], true)
       call  SetHeroStr (u, udg_Fusion_Object_Int3[indexObject], true)
       call  SetHeroInt (u, udg_Fusion_Object_Int4[indexObject], true)
   endif
   
   //Load Items.
   if hasInventory then
       set udg_Fusion_Item_Size = 0
       call ForGroup(udg_Fusion_Object_Group[indexObject], function UnitFusionPulledGetItems)
   endif      
   
   //Defusion?
   if defusion then
       call UnitDefusionTransformObject(indexObject)
       set udg_Fusion_Current_Object = indexObject
       call ForGroup(udg_Fusion_Object_Group[indexObject],  function UnitFusionSaveMat)
       set udg_Fusion_System_Pointer_Finished[udg_Fusion_Current_Pointer] = false
       if   hasInventory then
           call UnitFusionGiveItemsSave(u, indexObject)
       endif  
   else
       set udg_Fusion_System_Pointer_Finished[udg_Fusion_Current_Pointer] = true
       if   hasInventory then
           call UnitFusionGiveItems(u)
       endif
   endif
   
   //apply Averrage Life?
   if udg_Fusion_Data_ResultHPAverage[indexData] then
       call SetUnitState(u, UNIT_STATE_LIFE, GetUnitState(u, UNIT_STATE_MAX_LIFE) * udg_Fusion_Object_Real3[indexObject] )
   endif
   //apply Averrage Mana?
   if udg_Fusion_Data_ResultMPAverage[indexData] then
       call SetUnitState(u, UNIT_STATE_MANA, GetUnitState(u, UNIT_STATE_MAX_MANA) * udg_Fusion_Object_Real4[indexObject] )
   endif
   
   //Throw Event
   call GroupClear(udg_Fusion_Event_Group)
   //call ForGroup(udg_Fusion_Object_Group[indexObject], function UnitFusionLoadParts)
   call GroupAddGroup(udg_Fusion_Object_Group[indexObject], udg_Fusion_Event_Group)
   set udg_Fusion_Event_Fusion = u
   set udg_Fusion_Event_Source = udg_Fusion_Object_Source[indexObject]
   set udg_Fusion_Event_SpellData = indexData
   set udg_Fusion_Event_SpellLevel = udg_Fusion_Object_SpellLevel[indexObject]
   set udg_Fusion_Event_SpellObject = indexObject
   if IsUnitType (u, UNIT_TYPE_HERO) then
       set udg_Fusion_Event = UnitFusionEventHero()
   else
       set udg_Fusion_Event = UnitFusionEventNonHero()
   endif  
   set udg_Fusion_Event = 0
   
   //Start FadeIn after pulling?
   if udg_Fusion_Data_FadeIn[indexData] > 0 then
       //Start a new Fusion Object or takeover?
       if udg_Fusion_System_Pointer_Finished[udg_Fusion_Current_Pointer] then
           call UnitFusionStartFadeInTakeOver(indexObject)
           set udg_Fusion_System_Pointer_Finished[udg_Fusion_Current_Pointer] = false
       else
           call UnitFusionStartFadeInTakeOver(UnitFusionCloneObject(indexObject))
       endif
   else
       // Timed Life > 0
       // Constant + Level * Levelboni
       if udg_Fusion_Data_ResultDur[indexData] + ( udg_Fusion_Data_ResultDurPerLevel[indexData]* udg_Fusion_Object_SpellLevel[indexObject]) > 0 then
           call UnitApplyTimedLife( u, 'BTLF', udg_Fusion_Data_ResultDur[indexData] + ( udg_Fusion_Data_ResultDurPerLevel[indexData]* udg_Fusion_Object_SpellLevel[indexObject]) )
       endif
       call DestroyEffect(udg_Fusion_Object_Effect[indexObject])
       set udg_Fusion_Object_Effect[indexObject] = null
       if UnitFusionAutoSelect() then
           call SelectUnitAddForPlayer(u, GetOwningPlayer(udg_Fusion_Object_Source[indexObject]))
       endif
       call DestroyEffect(AddSpecialEffectTarget( udg_Fusion_Data_SFXResult[indexData] , u,udg_Fusion_Data_SFXResultAttacht[indexData] ))
   endif
   
   //Clean mats if no defusion
   if not defusion then
       call ForGroup(udg_Fusion_Object_Group[indexObject], function UnitFusionCleanMats)
   endif
   set u = null
endfunction


//Timer Sub Action Pull Fusion
// Real = Speed      
// Real2 = ZSpeed
// Real3 = life On Fusion
// Real4 = Mana on fusion
// Int1 = heroLevel
// Int2 = heroAgi
// Int3 = heroStr
// Int4 = heroInt
function UnitFusionPulled takes nothing returns nothing
   local integer indexObject = udg_Fusion_System_Pointer[udg_Fusion_Current_Pointer]
   set udg_Fusion_Object_Bool[indexObject] = true
   //Loop All running fusion
   //Used in the Subfunction
   call ForGroup(udg_Fusion_Object_Group[indexObject], function UnitFusionPulledPull)
   //All parts are near Enough?
   if udg_Fusion_Object_Bool[indexObject] then
       call ForGroup(udg_Fusion_Object_Group[indexObject], function UnitFusionPulledClean)
       call UnitFusionSpawn(indexObject, GetLocationX(udg_Fusion_Object_Loc[indexObject]),GetLocationY(udg_Fusion_Object_Loc[indexObject]))
   endif  
endfunction

function UnitFusionIsPart takes unit u, integer indexData returns boolean
   local integer indexEnd = udg_Fusion_System_UnitTypesEnd[indexData]
   local integer indexCurrent = udg_Fusion_System_UnitTypesStart[indexData]
   set udg_Fusion_Current_FilterUnit = u
   //Can Unit be part of Fusion?
   loop
       if udg_Fusion_Data_UnitTypes[indexCurrent] == 0 and udg_Fusion_System_Units[indexCurrent] == null then
           if TriggerEvaluate(udg_Fusion_Data_FilterWild[indexData]) then
               set udg_Fusion_System_Units[indexCurrent] = u
               return true
           endif
       endif
       set indexCurrent = indexCurrent + 1
       exitwhen indexCurrent > indexEnd
   endloop
   return false
endfunction

function UnitFusionIsSpecificPart takes unit u, integer indexData returns boolean
   local integer indexEnd = udg_Fusion_System_UnitTypesEnd[indexData]
   local integer indexCurrent = udg_Fusion_System_UnitTypesStart[indexData]
   local integer uTyp = GetUnitTypeId(u)
   //Can Unit be part of Fusion?
   loop
       if uTyp == udg_Fusion_Data_UnitTypes[indexCurrent] and udg_Fusion_System_Units[indexCurrent] == null  then
           set udg_Fusion_System_Units[indexCurrent] = u
           return true  
       endif
       set indexCurrent = indexCurrent + 1
       exitwhen indexCurrent > indexEnd
   endloop
   return false
endfunction


function UnitFusionPickAny takes nothing returns nothing
   call UnitFusionIsPart(GetEnumUnit(), udg_Fusion_Current_Data)
   call GroupRemoveUnit(udg_Fusion_Object_Group[0], GetEnumUnit())
endfunction

function UnitFusionPickSpecific takes nothing returns nothing
   if UnitFusionIsSpecificPart(GetEnumUnit(), udg_Fusion_Current_Data) then
       call GroupRemoveUnit(udg_Fusion_Object_Group[0], GetEnumUnit())
   endif
endfunction

function UnitFusionPickSelected takes nothing returns nothing
   if IsUnitSelected(GetEnumUnit(), GetTriggerPlayer()) then
       call UnitFusionPickSpecific()
   endif
endfunction

function UnitFusionFilter takes unit u, integer indexData returns boolean
   local integer indexEnd = udg_Fusion_System_UnitTypesEnd[indexData]
   local integer indexCurrent = udg_Fusion_System_UnitTypesStart[indexData]
   local real life = GetWidgetLife(u)
   set udg_Fusion_Current_FilterUnit = u
   //Allowed?
   //Ordercheck;
   //Filter Units if OrderCheck is set and Unit has not the expectedOrder.
   if not (udg_Fusion_Data_OrderCheck[indexData] == "" or udg_Fusion_Data_OrderCheck[indexData] == null ) and OrderId(udg_Fusion_Data_OrderCheck[indexData]) !=  GetUnitCurrentOrder(u)  then
       return false
   endif
   if not TriggerEvaluate(udg_Fusion_Data_FilterPre[indexData]) and udg_Fusion_Data_FilterPre[indexData] != null  then
       return false
   endif  
   
   if not TriggerEvaluate(udg_Fusion_Data_FilterMain[indexData]) and udg_Fusion_Data_FilterMain[indexData] != null then
       return false
   endif  

   //Needed UnitTypes pass
   loop
       if GetUnitTypeId(u) == udg_Fusion_Data_UnitTypes[indexCurrent] or udg_Fusion_Data_UnitTypes[indexCurrent] == 0 then
           return true
       endif
       set indexCurrent = indexCurrent + 1
       exitwhen indexCurrent > indexEnd
   endloop
   //if something goes terrible wrong.
   return false
endfunction

function UnitFusionFilterEnum takes nothing returns boolean
   if IsUnitPaused(GetFilterUnit()) or IsUnitIllusion(GetFilterUnit()) or not IsUnitInRangeLoc(GetFilterUnit(), udg_Fusion_Object_Loc[0], udg_Fusion_Object_Real1[0]) then
       return false
   endif
   return UnitFusionFilter(GetFilterUnit(),udg_Fusion_Current_Data)
endfunction

function UnitFusionFilterMessage takes integer indexData, integer indexCurrent, string s returns string
   local string seperator = "\n"
   set s = s +seperator
   //Specific UnitType?
   if udg_Fusion_Data_UnitTypes[indexCurrent] != null then
       set s = s + " - " + GetObjectName(udg_Fusion_Data_UnitTypes[indexCurrent])
   else
       set s = s + UnitFusionWildCard()
   endif
   set seperator = null
   return s
endfunction

//Generate ErrorWarrinng
function UnitFusionErrorMessage takes integer indexData, string s returns string
   local string seperator = "\n"
   set s = "|cffffcc00"+ GetObjectName(udg_Fusion_Data_Spell[indexData])+"|r"
   if udg_Fusion_Data_FilterPre[indexData]!= null and udg_Fusion_Data_ErrorMsgPre[indexData] != null and udg_Fusion_Data_ErrorMsgPre[indexData] !="" then
       set s = s + seperator
       set s = s + udg_Fusion_Data_ErrorMsgPre[indexData]
   endif
   if udg_Fusion_Data_FilterMain[indexData]!= null and udg_Fusion_Data_ErrorMsgMain[indexData] != null and udg_Fusion_Data_ErrorMsgMain[indexData] !="" then
       set s = s + seperator
       set s = s + udg_Fusion_Data_ErrorMsgMain[indexData]
   endif
   if udg_Fusion_Data_FilterWild[indexData]!= null and udg_Fusion_Data_ErrorMsgWild[indexData] != null and udg_Fusion_Data_ErrorMsgWild[indexData] !=""   then
       set s = s + seperator
       set s = s + udg_Fusion_Data_ErrorMsgWild[indexData]
   endif
   set s = s + seperator + UnitFusionErrorMsg()
   set seperator = null
   return s
endfunction


function UnitFusionLoadGroup takes integer indexCurrent, integer indexEnd, integer indexObject returns nothing
   loop
       call GroupAddUnit(udg_Fusion_Object_Group[indexObject], udg_Fusion_System_Units[indexCurrent])
       set   indexCurrent = indexCurrent + 1
       exitwhen indexCurrent > indexEnd
   endloop  
endfunction

function UnitFusionFuse takes integer indexData, location loc returns nothing
   local integer indexEnd = udg_Fusion_System_UnitTypesEnd[indexData]
   local integer indexCurrent = udg_Fusion_System_UnitTypesStart[indexData]
   local integer amount = ( udg_Fusion_System_UnitTypesEnd[indexData] - udg_Fusion_System_UnitTypesStart[indexData] ) + 1
   local real x = 0
   local real y = 0
   local real x2 = 0
   local real y2 = 0
   local boolean isValidFusion = true
   local unit u
   local integer level = GetUnitAbilityLevel(GetTriggerUnit(), udg_Fusion_Data_Spell[indexData])
   local real life = 0
   local real mana = 0
   local string s
   local boolean defusion = udg_Fusion_Data_DefuseAfterDur[indexData] or udg_Fusion_Data_DefuseOnKilled[indexData]
   local integer heroLevel = 0
   local integer heroAgi = 0
   local integer heroStr = 0
   local integer heroInt = 0
   local integer indexEnter
   local boolean isResultHero = IsUnitIdType(udg_Fusion_Data_Result[indexData], UNIT_TYPE_HERO)
   set udg_Fusion_Current_Data = indexData
   //clear old data
   call GroupClear(udg_Fusion_Object_Group[0])
   loop
       set udg_Fusion_System_Units[indexCurrent] = null
       exitwhen indexCurrent == indexEnd
       set indexCurrent = indexCurrent + 1
   endloop
   
   //Index 0 is never used, so one can use it here.
   set udg_Fusion_Object_Real1[0] = udg_Fusion_Data_AoE[indexData] + ( level * udg_Fusion_Data_AoEPerLevel[indexData])
   
   if udg_Fusion_Object_Real1[0] > 0 then
       set udg_Fusion_Object_Loc[0] = loc
       call GroupEnumUnitsInRangeOfLoc(udg_Fusion_Object_Group[0], loc, udg_Fusion_Object_Real1[0] + UnitMaxColison() , udg_Fusion_System_Filter)
       set udg_Fusion_Object_Loc[0] = null
   endif  
   //AutoAddCaster?
   if udg_Fusion_Data_AutoAddCaster[indexData] and UnitFusionFilter(GetTriggerUnit(),indexData ) then
       if   UnitFusionIsSpecificPart(GetTriggerUnit(), udg_Fusion_Current_Data) then
           call GroupRemoveUnit(udg_Fusion_Object_Group[0], GetTriggerUnit())
       endif
   endif
   //AutoAddTarget?
   if udg_Fusion_Data_AutoAddTarget[indexData] and UnitFusionFilter(GetSpellTargetUnit(),indexData ) then
       if UnitFusionIsSpecificPart(GetSpellTargetUnit(), udg_Fusion_Current_Data) then
           call GroupRemoveUnit(udg_Fusion_Object_Group[0], GetSpellTargetUnit())
       endif
   endif
   //First check selected
   call ForGroup(udg_Fusion_Object_Group[0], function UnitFusionPickSelected)
   //then check for defined unittypes
   call ForGroup(udg_Fusion_Object_Group[0], function UnitFusionPickSpecific)
   
   //then use wildcard unittypes
   set indexCurrent = udg_Fusion_System_UnitTypesStart[indexData]
   
   //spell has wildcards?
   loop
       if udg_Fusion_Data_UnitTypes[indexCurrent] == 0 then
           call ForGroup(udg_Fusion_Object_Group[0], function UnitFusionPickAny)
           exitwhen true
       endif  
       set indexCurrent = indexCurrent + 1
       exitwhen indexCurrent > indexEnd
   endloop
   
   //All MergingParts found?
   set indexCurrent = udg_Fusion_System_UnitTypesStart[indexData]
   set s = UnitFusionErrorMessage(indexData,"")
   loop
       if udg_Fusion_System_Units[indexCurrent] == null then
           set isValidFusion = false
           set s = UnitFusionFilterMessage(indexData,indexCurrent,s)
       else
           set x = x + GetUnitX(udg_Fusion_System_Units[indexCurrent])
           set y = y + GetUnitY(udg_Fusion_System_Units[indexCurrent])
           set life = life + GetUnitStatePercent(udg_Fusion_System_Units[indexCurrent] , UNIT_STATE_LIFE, UNIT_STATE_MAX_LIFE)
           set mana = mana + GetUnitStatePercent(udg_Fusion_System_Units[indexCurrent] , UNIT_STATE_MANA, UNIT_STATE_MAX_MANA)
           //HeroStuf
           if IsUnitType(udg_Fusion_System_Units[indexCurrent] ,UNIT_TYPE_HERO) and isResultHero then
               set heroLevel = heroLevel +  GetHeroLevel (udg_Fusion_System_Units[indexCurrent])
               set heroAgi = heroAgi + GetHeroAgi(udg_Fusion_System_Units[indexCurrent], udg_Fusion_Data_HeroAllowBoniStats[indexData])
               set heroStr = heroStr + GetHeroStr(udg_Fusion_System_Units[indexCurrent], udg_Fusion_Data_HeroAllowBoniStats[indexData])
               set heroInt = heroInt + GetHeroInt(udg_Fusion_System_Units[indexCurrent], udg_Fusion_Data_HeroAllowBoniStats[indexData])
           endif
       endif
       set indexCurrent = indexCurrent + 1
       exitwhen indexCurrent > indexEnd
   endloop
   
   if isValidFusion then
       set x= x/amount
       set y = y/amount
       set life = (life/amount)*0.01
       set mana = (mana/amount) *0.01
           
       set indexCurrent = udg_Fusion_System_UnitTypesStart[indexData]
       if udg_Fusion_Data_SpawnAtTargetPoint[indexData] then
           set x = GetLocationX(loc)
           set y = GetLocationY(loc)  
       endif
       
       
       //Gives an free spot in the Object Arrays.
       set indexEnter = UnitFusionInserObject()
       set udg_Fusion_Current_Pointer = udg_Fusion_System_Pointer_Last
       set udg_Fusion_Current_Object = indexEnter
       set udg_Fusion_Object_DataIndex[indexEnter] = indexData
       set udg_Fusion_Object_Source[indexEnter] = GetTriggerUnit()
       set udg_Fusion_Object_Fusion[indexEnter] = null
       set udg_Fusion_Object_SpellLevel[indexEnter] = level
       set udg_Fusion_Object_Real3[indexEnter] = life
       set udg_Fusion_Object_Real4[indexEnter] = mana
       
       if isResultHero then
           if not udg_Fusion_Data_HeroSumLevel[indexData] then
               set heroLevel = heroLevel / amount
           endif
           if udg_Fusion_Data_HeroStatsMod[indexData] == 1 then
               set heroAgi = heroAgi / amount
               set heroStr = heroStr / amount
               set heroInt = heroInt / amount
           endif
           set udg_Fusion_Object_Int1[indexEnter] = heroLevel
           set udg_Fusion_Object_Int2[indexEnter] = heroAgi
           set udg_Fusion_Object_Int3[indexEnter] = heroStr
           set udg_Fusion_Object_Int4[indexEnter] = heroInt
       endif
       
       
       if udg_Fusion_Object_Group[indexEnter] == null then
           set udg_Fusion_Object_Group[indexEnter] = CreateGroup()
       else
           call GroupClear (udg_Fusion_Object_Group[indexEnter])
       endif  
       
       call UnitFusionLoadGroup(indexCurrent,indexEnd,indexEnter)
       
       if udg_Fusion_Object_Loc[indexEnter] == null then
           set udg_Fusion_Object_Loc[indexEnter] = Location(x,y)
       else
           call MoveLocation(udg_Fusion_Object_Loc[indexEnter],x,y)
       endif
       //Mark the Object as finished?
       //Pulled Fusions / Defusions / Fadeins will take over this object.
       //set udg_Fusion_System_Pointer_Finished[udg_Fusion_System_Pointer_Last] = not (udg_Fusion_Data_Speed[indexData] > 0 or udg_Fusion_Data_FadeIn[indexData] > 0 or defusion)
               
       // Pull together:
       if udg_Fusion_Data_Speed[indexData] > 0 then
           set udg_Fusion_Object_Effect[indexEnter] = AddSpecialEffect( udg_Fusion_Data_SFX[indexData],x,y )
           set udg_Fusion_Object_Type[indexEnter] = UnitFusionTypePull()
           //For Pull Real 1 is Speed.
           set udg_Fusion_Object_Real1[indexEnter] = udg_Fusion_Data_Speed[indexData] * UnitFusionTimerSpeed()
           //For Pull Real2 is ZSpeed
           set udg_Fusion_Object_Real2[indexEnter] = udg_Fusion_Data_SpeedZ[indexData] * UnitFusionTimerSpeed()

           //Pull orginal units?
           if udg_Fusion_Data_Replace[indexData] == 0 then
               loop
                   call SetUnitFacing(udg_Fusion_System_Units[indexCurrent],bj_RADTODEG * Atan2(y - GetUnitY(udg_Fusion_System_Units[indexCurrent]), x - GetUnitX(udg_Fusion_System_Units[indexCurrent])))
                   call SetUnitVertexColor(udg_Fusion_System_Units[indexCurrent], 255, 255, 255, UnitFusionFade())
                   call DestroyEffect(AddSpecialEffectTarget( udg_Fusion_Data_SFXUnit[indexData] , udg_Fusion_System_Units[indexCurrent], udg_Fusion_Data_SFXUnitAttacht[indexData] ))
                   call UnitAddAbility(udg_Fusion_System_Units[indexCurrent], 'Arav' )
                   if not defusion then
                       call UnitAddAbility(udg_Fusion_System_Units[indexCurrent] , 'Aloc')
                   else
                       call SetUnitInvulnerable(udg_Fusion_System_Units[indexCurrent], true )
                       call  SetUnitPathing (udg_Fusion_System_Units[indexCurrent], false)
                   endif
                   call PauseUnit(udg_Fusion_System_Units[indexCurrent], true )
                   set   indexCurrent = indexCurrent + 1
                   exitwhen indexCurrent > indexEnd
               endloop
           else
           //Pull substitutes
               loop
                   set x2 =GetUnitX(udg_Fusion_System_Units[indexCurrent])
                   set y2 =GetUnitY(udg_Fusion_System_Units[indexCurrent])
                   call DestroyEffect(AddSpecialEffect( udg_Fusion_Data_SFXUnit[indexData],x2,y2 ))
                   if not defusion then
                       if udg_Fusion_Data_Remove[indexData] then
                           //Hide and Pause until pull is finished.
                           call ShowUnit(udg_Fusion_System_Units[indexCurrent], false)
                           call PauseUnit(udg_Fusion_System_Units[indexCurrent], true)
                       else
                           call KillUnit(udg_Fusion_System_Units[indexCurrent])
                       endif
                   else
                       call SetUnitInvulnerable(udg_Fusion_System_Units[indexCurrent], true )
                       call PauseUnit(udg_Fusion_System_Units[indexCurrent], true )
                       call  SetUnitPathing (udg_Fusion_System_Units[indexCurrent], false)
                       call  ShowUnit (udg_Fusion_System_Units[indexCurrent], false)
                   endif  
                   //Substitudes should flying
                   set u = CreateUnit(GetTriggerPlayer(), udg_Fusion_Data_Replace[indexData], x2, y2, bj_RADTODEG * Atan2(y - y2, x - x2) )                  
                   call GroupAddUnit( udg_Fusion_Object_Group[indexEnter], u )
                   call PauseUnit(u, true )
                   set   indexCurrent = indexCurrent + 1
                   exitwhen indexCurrent > indexEnd
               endloop  
               set u = null
           endif
           call UnitFusionTimerStart()
       else
           
           //Instant Fusion
           
           //Spawn Grafic Supstitudes
           loop
               set x2 =GetUnitX(udg_Fusion_System_Units[indexCurrent])
               set y2 =GetUnitY(udg_Fusion_System_Units[indexCurrent])
               call DestroyEffect(AddSpecialEffect( udg_Fusion_Data_SFXUnit[indexData],x2,y2 ))
               //Spawn extra Units, if wanted.
               //that is actually a hidden feature:
               //if one does not set speed but uses replaces it will summon units, where the old units were standing.
               //This summons have the same duration as the fusion.
               if  udg_Fusion_Data_Replace[indexData] != 0 then
                   set u = CreateUnit(GetTriggerPlayer(), udg_Fusion_Data_Replace[indexData], x2, y2, bj_RADTODEG * Atan2(y - y2, x - x2) )
                   // Timed Life > 0
                   // Constant + Level * Levelboni
                   if udg_Fusion_Data_ResultDur[indexData] + ( udg_Fusion_Data_ResultDurPerLevel[indexData]*level) > 0 then
                       call UnitApplyTimedLife(u, 'BTLF', udg_Fusion_Data_ResultDur[indexData] + ( udg_Fusion_Data_ResultDurPerLevel[indexData]*level))
                   endif
               endif  
               set   indexCurrent = indexCurrent + 1
               exitwhen indexCurrent > indexEnd
           endloop  
           call UnitFusionSpawn(indexEnter,x,y)
           set u = null
       endif  
   else
       call DisplayTimedTextToPlayer(GetTriggerPlayer(), 0, 0, UnitFusionErrorDur(), s)
       call DisplayTimedTextToPlayer(GetTriggerPlayer(), 0, 0, UnitFusionErrorDur(), ( "---------------" ))
   endif
   set s = null
   set u = null
endfunction

function UnitFusionCasting takes nothing returns nothing
   local integer indexData = 0
   local integer Id = GetSpellAbilityId()
   local location loc
   if IsUnitHidden(GetTriggerUnit()) then
       return
   endif
   //Find Casted Skill
   loop
       exitwhen indexData == udg_Fusion_CreationIndex
       if Id == udg_Fusion_Data_Spell[indexData]   then
           //Has TargetUnit
           if GetSpellTargetUnit() != null then
               set loc = GetUnitLoc(GetSpellTargetUnit())
           else
               //Has TargetLoc? not 100% correct, but its pretty unlikly to cast something exactly at 0/0.
               if GetSpellTargetX() == 0.0 and GetSpellTargetY() == 0.0 then
                   set loc = GetUnitLoc(GetTriggerUnit())
               else
                   set loc = GetSpellTargetLoc()
               endif  
           endif
           call UnitFusionFuse(indexData, loc)
           call RemoveLocation(loc)
           set loc = null
           return
       endif
       set indexData = indexData + 1
   endloop
endfunction

//On First Execution of this System
//Preload Skills
//Enable Fusion
//Enable Defusion death detecion
//Preload Specialeffects
//Autogenerate missing Atttachmentpoints
//Printout Warnings for using wildcard units but having no FilterWild
function UnitFusionPreload takes nothing returns nothing
   local unit u
   local integer LoopA = 0
   local integer LoopB
   local real x = GetRectMaxX (bj_mapInitialPlayableArea)
   local real y = GetRectMaxY (bj_mapInitialPlayableArea)
   call TriggerClearActions(gg_trg_UnitFusion)
   call TriggerAddAction( gg_trg_UnitFusion, function UnitFusionCasting )
   call TriggerRegisterAnyUnitEventBJ( gg_trg_UnitFusion, EVENT_PLAYER_UNIT_SPELL_EFFECT )
    set u = CreateUnit(Player(PLAYER_NEUTRAL_PASSIVE), 'hfoo', 0,0, 270 )
    call UnitAddAbility(u, 'Arav')
    call UnitAddAbility(u, 'Aloc')
    call RemoveUnit( u )
   set udg_Fusion_System_DefusionTrigger = CreateTrigger()
   call TriggerRegisterAnyUnitEventBJ( udg_Fusion_System_DefusionTrigger, EVENT_PLAYER_UNIT_DEATH )
   call TriggerAddAction(udg_Fusion_System_DefusionTrigger, function UnitDefusionDeath)
   set u = null
   set udg_Fusion_Item_DefSize = UnitDefusionItemOffset()
   
   //Define Filter for finding Mats.
   set udg_Fusion_System_Filter = Condition(function UnitFusionFilterEnum)
   
   //Preload specialeffects
   //Autofills Attachmentpoints, if needed
   loop
       exitwhen LoopA == udg_Fusion_CreationIndex

       call DestroyEffect(AddSpecialEffect( udg_Fusion_Data_SFXUnit[LoopA],x,y ))
       call DestroyEffect(AddSpecialEffect( udg_Fusion_Data_SFX[LoopA],x,y ))
       call DestroyEffect(AddSpecialEffect( udg_Fusion_Data_SFXResult[LoopA],x,y ))
       
       //Use default attachment point?
       if udg_Fusion_Data_SFXUnit[LoopA] != "" and StringIsEmpty(udg_Fusion_Data_SFXUnitAttacht[LoopA]) then
           set udg_Fusion_Data_SFXUnitAttacht[LoopA] = "chest"
       endif
       //Use default attachment point?
       if udg_Fusion_Data_SFXResult[LoopA] != "" and StringIsEmpty(udg_Fusion_Data_SFXResultAttacht[LoopA]) then
           set udg_Fusion_Data_SFXResultAttacht[LoopA] = "origin"
       endif
       
       set LoopA = LoopA + 1
   endloop
   
   //Printout Warnings for using Wildcards but not using Wildcard Filters.
   set LoopA = 0
   loop
       exitwhen LoopA == udg_Fusion_CreationIndex
       set LoopB = udg_Fusion_System_UnitTypesStart[LoopA]
       loop
           exitwhen LoopB > udg_Fusion_System_UnitTypesEnd[LoopA]
           if udg_Fusion_Data_UnitTypes[LoopB] == 0 then
               if udg_Fusion_Data_FilterWild[LoopA] == null then
                   call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,30,"|cffff0000Warning|r: "+ GetObjectName(udg_Fusion_Data_Spell[LoopA])+" uses Wildcards but has no Wildcard Filter.")
                   exitwhen true
               endif
           endif
           set LoopB = LoopB + 1
       endloop
       set LoopA = LoopA + 1
   endloop
endfunction
//===============

function InitTrig_UnitFusion takes nothing returns nothing
    set gg_trg_UnitFusion = CreateTrigger(  )
    call TriggerAddAction( gg_trg_UnitFusion, function UnitFusionPreload )
endfunction

 

V8a)
  • now uses an constant boolexpress for filtering units.
  • now catches avaible material touching the AoE Indikator's edge with their hitbox.
  • SpecialEffects are now displayed on map start with maxium x & y of playablemap.
  • one can now select Specialeffect-models with the default World Editor drop down Menu.
    • ^When updating a old version you need to delete the SFX Variables inside variable Editor and copy the Unit Fusion Folder again or the specific variables from the fusion init file.
V8)
  • Merged Fusion Spawning into an own Function
  • Displays all SFX-Effects at MapCenter to preload them
  • AttachmentPoints-Now changeable, If unset autochoose Result=Origin Unit=Chest
  • Uses now GetObjectName
  • Some Improvments for Fusions without Wildcards and Without autoadd Caster/Target
  • Now Drops all Items before removing an Unit.
  • One can now stop further Fusion Progress by stopping "Fusion_System_Timer", if you use "Fusion_System_TimerDisabled=true" new casts won't restart the timer onitself. To restart the timer one can now use call UnitFusionTimerStart() but you have to make sure that "Fusion_System_TimerDisabled=False"
  • Deathcheck in Fadein 0.5 -> 0.405
  • Replaced bj_MAX_INVENTORY with UnitInventorySize(u)
  • Skips hero stuff, if the result is no hero.
  • Removed saving Condition as local and placed it directly into enumerate group.
  • Included some Document into the map
  • One can now change the output String for missing Wildcard Units.
V7)
Variables are now better structed:
Data, Current, System, Object, Item, Event .​
Combined Fusion-Events into 1 and improved the events.
Removed the Hardcoded allow Filters and instead one can now set 3 Filter-Triggers (Pre, Main, Wild)
Removed the global Fusion FadeIn Immunity, can be set per spell.
One can now preset an skill to be auto added to the fusion.
Now uses dynamic Pointers instead of dynamic indexing.
Autoselection is now deactivadeable with an constant.​
V6)
Fusions now takeover items from their mats.
Defusions adresses:
Passing Gained Exp, if wanted
Auras of waiting Units
dispell buffs of waiting units, if wanted
some bug with defusions, if beeing removed from the game​
Fixed an critcal bug with Defusions without Mana.
Insert an optional Ordercheck, if set units don't performing this Order will not pass.​
V5a) now calling Defusion with an index will correctly destroy the fusion unit instantly
V5)
Supports HeroFusions alot better.
Supports now defusion.
Added two Events to catch: FusionFadeInEvent = 1, FusionHeroEvent = 1
Missing mats Message overworked:
Supporting single target 2 unit fusions alot better.​
V4)
There is now the option to set the % hp/MP of the fusion to the average % of the used material, default off.
The Fusion Spells are now in another Folder called Fusion Spells.
removed an further weak bj.
Upadated missing Unit messages.
Fixed a bug Fusionparts using wrong speedZ​
V3a)
Replaced UnitApplyTimedLifeBJ with UnitApplyTimedLife
V3)
Allows to use wildcards now by using an bigger Amounts than setting unittypes.
This wildcard uses the new Allowed ones: Hero, Structure, Mech.
Specific Mats are first filled before filling wildcards.​
Inluded an new default filter mechanic
AllowDead/AllowLiving which has to be set.​
Fixed a bug with fadingIn playing wrong sfxes on finish if spamming fusions
FadingIn Units are now constanly paused to disallow unpausing them with other actions.
FadeIn Supports now an wanted %transparenzy using called Data_Hidden.
TargetUnit/Selfcasting will now check the unit for beeing an specificmaterial on first check.
added Fusion_Data_AoEPerLevel to make this more useable for hero skills/upgrades.
added Fusion_Data_ResultDur/PerLevel this adds a timed life effect after finishing the fusion
only if set above 0​

  • Creating an new fusion is quite simple you copy an Fusion Spell Trigger change the Data_Spell additional you could change data.
    Here you should know that only Fusion_Data_.... variables should be written.

    Let's have a look on the basic Variables and there effect:
    I do skip some with simlear naming and the perLevel Variables.
    Variable Info
    Fusion_CreationIndex this is the index on which your Data is saved on. [Fusion_CreationIndex]
    Fusion_Data_AmountOfMergers tells the System how many Units will fuse.
    Fusion_Data_Spell is the spell which will use this fusion, they have to be unique inside the system.
    Fusion_Data_Result is the UnitType one Gains
    Fusion_Data_UnitTypes starting with [creationindex + 1] are specific Fusion Member Types, if you have not set the same number of specific members as Fusion_Data_AmountOfMergers, your spell will take wildcards. This is the only variable you create this way [Fusion_CreationIndex + 1/2/3/4]
    Fusion_Data_ResultHPAverage if set the fusion will have only the average % HP/MP of the units having mergered
    Fusion_Data_ResultDur the fusion will only hold for this amount of seconds.
    Fusion_Data_SFX this will be player while the Fusion is still building up
    Fusion_Data_SFXResult this will be displayed on the fusion when finished. using the death animation tag
    Fusion_Data_SFXUnit this will be displayed at the units having mergered. using the death animation tag
    Fusion_Data_Speed if set the Merging members will be pulled to the fusion point using this speed
    Fusion_Data_Replace if you set speed the merging members will not be pulled the spawn each a replace which will be pulled. You can only set 1 Replacetype on each spell
    Fusion_Data_AoE in which area around the Target Units will be considered for the fusion.
    Fusion_Data_AutoAddCaster ignoring the AoE and TargetLocation the Caster will be considered for Fusing if he passes the filters.
    Fusion_Data_SpawnAtTargetPoint if set the fusion will take place at the target, else it will be the average of cordinates of merging units
    Fusion_Data_Remove the merging Units will removed if set, default they die.
    Fusion_Data_ErrorMsgMain The Error Message for the MainFilter
    Fusion_Data_FilterMain The Main Filter units have to pass to be used for a fusion.
    Fusion_Data_SkillGained This Ability will be added to the Fusion

  • Fadein is an option you can use to let the Fusion starting hidden and then become more and more material.
    If you use FadingIn Fusion_Data_SFXResult will be played first after finishing fadingIn.

    While FadingIn the Fusion is paused and on default invulnerable.
    The FadingIn Unit becomes repaused constantly.
    After the FadingIn ended, the Event FadingInEvent becomes 1.0 to catch.

    Fadingin can be combined with Pulled Fusion by setting speed and FadeIn
    Variable Info
    Fusion_Data_FadeIn How long it takes to fadeIn, and beeing able to act, in seconds.
    Fusion_Data_FadeInHidden this variable allows you to keep the FadedIn Unit hidden by that %.
    Fusion_Data_FadeVulnerable When true the unit can be hit while the process.

    One can use Fadein on any unit with this jassfunction
    hiddenStateAfter is an value from 0 to 100.
    Code (vJASS):

    function UnitFusionStartFadeIn
    takes unit u, real dur, real hiddenStateAfter, string sfx, boolean immunDuringFade
    returns nothing
     

    You can access the started Fadin Object by using udg_Fusion_Current_CreatedObject as Index to change Fusion_Object_x or attach an own custom Variable right after starting the fadein.
    (changing Fusion_Object_Pointer or Fusion_System_Pointer is not recommended.)

    If you start an Fadein Manually the used Fusion_Event_SpellData on the thrown Event is -1 and has no source, on default.

  • Defusion saves the Merged Units and restores them as soon the Fusion ends, what will happen with the units is choosen by setting the two Defusion Mods.
    There are two versions of Defusion both can be set at the same time.
    If the merged Units have items the Fusion will pick the highest Level Items and get equiped with them. As soon the Merged Units restore, they will regain their Items if the Fusion still had them.

    DefusionOnKilled


    The Fusion will defuse, if killed from someone.
    Merged Units will use Fusion_Data_DefuseOnKilledHP/MP, beaware that if not set they are 0 and the merged units will die.

    DefusionAfterDur


    The Fusion defuses, if killed/Removed without a killer.

    the Data_Remove variable will affect the Fusion.
    While waiting for Defusion the Merged Units wait hidden/paused/invulnerable on an specific place on the map.
    If an unallowed Defusion would appear the waiting Units will be restored and instantly removed.

    Variable Info
    Fusion_Data_DefuseDispellMat on Defuse take away all buffs from the restored Units
    Fusion_Data_DefuseDistance how far away the units will be restored from the Defusion, they spawn in an circle form
    Fusion_Data_DefuseSFX played when defusion triggers, uses death animation tag.
    Fusion_Data_DefusionEXPMulti how much of gained exp will be transfered to the Merged Units. It shares it equaly between all Units no matter if they are hero or not. 1 = 50% for each in a 2 unit fusion.
    Fusion_Data_DefuseAfterDur Will defusie, if dies/Removed without killer.
    Fusion_Data_DefuseAfterDurHP how much % the merged units will have. If you set -1 the take over the fusions one. 1 = 100%; 0 = 0% 0.2 = 20%
    Fusion_Data_DefuseOnKilled Will defuse, if killed with an killer
    Fusion_Data_DefuseOnKilledHP how much % the merged units will have. -1 is not working here. 1 = 100%; 0 = 0%
    FusionSaveLoc is the Location which the waiting Merged Units will be sent to, is set inside UnitFusion Init.
    Defusion can be initiated by using an jass call using this function:
    Code (vJASS):

    function UnitDefusion takes unit u, boolean killed, integer indexFusion returns nothing
         //This function will defusion an fusion unit.
         //call it with index -1, if you don't know the Defusion index.
         //call it with null unit if you know the index.
         //killed do this Fusion's OnKilled = true / AfterDur = false
     



  • Hero Fusions are supported. I recomment to always set both defusionMods to avoid removing Heroes.
    Fusions for heroes are not so different from other Fusions.

    Variable Info
    Fusion_Data_HeroSumLevel on default the fusionresult beeing an hero will have the average Level of merged heroes, if you set this the Levels will be summed up.
    Fusion_Data_HeroStatsMod is an integer expecting 3 aviable mods: 0/1/2. 0 default Stats, 1 average Stats of merged Units, 2 sum of Merged Heroes.
    Fusion_Data_HeroAllowBoniStats ^^influences mod 1 and 2, if true green numbers will be taken in account
    Fusion_Data_DefusionEXPMulti how much of gained exp will be transfered to the Merged Units. It shares it equaly between all Units no matter if they are hero or not. 1 = 50% for each in a 2 unit fusion.


  • By using the filters right you will only fuse the units you want.

    The System offers 2 Filters and 1 Wildcard Filter you can setup for each Fusion spell individual.
    Filters don't have to be used but there might something wierd happen if yon do not use one.
    Pre,Main,Wild

    Pre and main are Filters Units have to pass to be accepted overall.
    Wild is only needed if your Spell uses Wildcard material.

    one could use only Pre or Main, but in my opinion there are often repeated conditions like:
    • living ally
    • living enemy
    • Dead
    • Own 50% or more HP
    Most Spells will contain 1 of the ^ filters above. But still have some special rule. That's why there is pre and main.

    This filter will run for each Unit beeing considered and is addressed with Fusion_Current_FilterUnit.

    Such Filters are inside the Spellcasting event therefore one can use any Spell-Event variable one likes to use.


    Pre: Regard Ownership, Lifestate.
    Main: Regard UnitType/ other things.
    Wild: exclude not wanted units.

    A Filter is an Trigger only containing an Condition.
    Only living Own units will pass.
    • Fusion Filter Own n Alive
      • Events
      • Conditions
        • (Owner of Fusion_Current_FilterUnit) Equal to (Triggering player)
        • (Fusion_Current_FilterUnit is alive) Equal to True
      • Actions


    Filters need an ErrorMessage which can be setuped at the FusionSpell creation. The printout is:

    Spellname in gold automaticly done
    Pre-Msg
    Main-Msg
    Wild-Msg
    Misses: automaticly added.
    -Unit List automaticly added.




  • Events allow you to interact when an Fusion is summoned/Faded in or defuses.

    All Fusion-Events using the same Variables, beeing different is the Event Value.

    What one could do with an Fusion-Event?
    This one will Slow the defused Units from the Captain Fusion which is based on the Spell 2 for 1.
    • Captain DeFusion
      • Events
        • Game - Fusion_Event becomes Equal to -1.00
      • Conditions
        • Fusion_Data_Spell[Fusion_Event_SpellData] Equal to 2 for 1
      • Actions
        • Unit - Create 1 Dummy Caster for Neutral Passive at Fusion_System_SaveLoc facing Default building facing degrees
        • Unit - Add a 0.60 second Generic expiration timer to (Last created unit)
        • Unit - Add Slow to (Last created unit)
        • Unit Group - Pick every unit in Fusion_Event_Group and do (Actions)
          • Loop - Actions
            • Unit - Order (Last created unit) to Human Sorceress - Slow (Picked unit)


    The Event Variables
    Variable Info
    Fusion_Event Tells you what happened
    Fusion_Event_Fusion The Unit beeing Fused/Fadedin/Defused
    Fusion_Event_Group The merged units.
    Fusion_Event_Source The Spellcaster who started the Fusion.
    Fusion_Event_SpellData Which Fusion Data is used.
    Fusion_Event_SpellLevel The Spell Level this fusion was called.
    Fusion_Event_SpellObject The Fusion Object Handeling the Fusion/Defusion/Fadein


    Event Info
    Fusion_Event == 1 A non-Hero Fusion was summoned
    Fusion_Event == 2 A Hero Fusion was summoned
    Fusion_Event == 3 A Fusion Ended Fadein.
    Fusion_Event == -1 A Fusion defuses.





Credits

Seavalan Legend
Daffa the Mage

IcemanBo
Previews
Contents

Unit Fusion V8a (Map)

Reviews
Dr Super Good
Useful, flexible and easy to use unit fusion/splitting system. Could be used for a variety of purposes ranging from fusion mechanics in a DBZ themed map to merging Templars into Archons in a StarCraft themed map. Very GUI friendly to use. Feedback:...
  1. Daffa the Mage

    Daffa the Mage

    Map Moderator

    Joined:
    Jan 30, 2013
    Messages:
    7,477
    Resources:
    26
    Packs:
    1
    Maps:
    8
    Spells:
    16
    Tutorials:
    1
    Resources:
    26
    Interesting. How about spam the section w/ unit merging everyone? :p
     
  2. Tasyen

    Tasyen

    Joined:
    Jul 18, 2010
    Messages:
    1,031
    Resources:
    11
    Tools:
    2
    Maps:
    2
    Spells:
    5
    Tutorials:
    1
    JASS:
    1
    Resources:
    11
    Nice answer to my comment on your spell :).
     
  3. Daffa the Mage

    Daffa the Mage

    Map Moderator

    Joined:
    Jan 30, 2013
    Messages:
    7,477
    Resources:
    26
    Packs:
    1
    Maps:
    8
    Spells:
    16
    Tutorials:
    1
    Resources:
    26
    Don't take that comment as serious. Here are some thoughts :
    1. How about take HP and MP value and get the avg amount to apply at new unit (addon)?
    2. What happens to timed fusion? Do the units die after it end?
    3. You might want to separate samples from the core, just to make it easier to import.
     
  4. Tasyen

    Tasyen

    Joined:
    Jul 18, 2010
    Messages:
    1,031
    Resources:
    11
    Tools:
    2
    Maps:
    2
    Spells:
    5
    Tutorials:
    1
    JASS:
    1
    Resources:
    11
    Thanks for your feedback.
    1. dat is a nice idea will add this one as chooseable option
    2. Timed fusions currently die as soon the time ends.
    3. Will do that.
     
  5. Daffa the Mage

    Daffa the Mage

    Map Moderator

    Joined:
    Jan 30, 2013
    Messages:
    7,477
    Resources:
    26
    Packs:
    1
    Maps:
    8
    Spells:
    16
    Tutorials:
    1
    Resources:
    26
    2. If possible, how about revert them back to original separate form with addon (1) split into their health? Reminds me of Dragonballs.
     
  6. Tasyen

    Tasyen

    Joined:
    Jul 18, 2010
    Messages:
    1,031
    Resources:
    11
    Tools:
    2
    Maps:
    2
    Spells:
    5
    Tutorials:
    1
    JASS:
    1
    Resources:
    11
    It should be possible.
    But I ask myself what is if an fusion is killed:
    • should it defuse into dead parts
    • keep dead as fused unit
    • or defuse into living parts?
    or simply address all and let the spell choose, yes gueess that i'll do.
     
  7. IcemanBo

    IcemanBo

    Joined:
    Sep 6, 2013
    Messages:
    5,990
    Resources:
    22
    Maps:
    3
    Spells:
    11
    Template:
    1
    Tutorials:
    4
    JASS:
    3
    Resources:
    22
    Maybe user can have powers to read fusioned units (or unit type) of which a unit exists, and if needed he can catch onDeath event and re-create them with reading from dyingunit(), for example.
     
  8. Tasyen

    Tasyen

    Joined:
    Jul 18, 2010
    Messages:
    1,031
    Resources:
    11
    Tools:
    2
    Maps:
    2
    Spells:
    5
    Tutorials:
    1
    JASS:
    1
    Resources:
    11
    Thanks for the idea input.

    The goal is that one only has to define data in an fusion init.

    Recreating fusion mats would sadly destroy old states/customizes.
    Heroes, added abilities etc​

    But now I realize that auto removing/killing fusions parts might be bad for defusions, better would be to hide/pause them and later regain them, but that would bite with (beeing convertered to aloc units or death animation). hmm there is surely an solution without dozens of tricks.
    Well, defusion will take a while.
     
    Last edited: Jul 20, 2017
  9. IcemanBo

    IcemanBo

    Joined:
    Sep 6, 2013
    Messages:
    5,990
    Resources:
    22
    Maps:
    3
    Spells:
    11
    Template:
    1
    Tutorials:
    4
    JASS:
    3
    Resources:
    22
    Could you explain me closer, please; not sure I got why it would be a problem.
     
  10. Tasyen

    Tasyen

    Joined:
    Jul 18, 2010
    Messages:
    1,031
    Resources:
    11
    Tools:
    2
    Maps:
    2
    Spells:
    5
    Tutorials:
    1
    JASS:
    1
    Resources:
    11
    If you recreate an unit it will get an new handle (all datas of the unit saved in hashtables would have to be taken over) and an new index in some likely used Unit Indexers too ( that would be easier by seting custom Value).
    If one adds abilities with Code they would have to be taken over too.
    The bigger problem is actually a hero, which I want to support. A hero gets a new name.
    ^^ not automatable:
    solution is either like you suggest throw an event and let the mapper do the job (which can be alot of work for him)
    or not creating new units.
    Edit: Updated to V4 defusion will be part of V5.
     
    Last edited: Jul 20, 2017
  11. IcemanBo

    IcemanBo

    Joined:
    Sep 6, 2013
    Messages:
    5,990
    Resources:
    22
    Maps:
    3
    Spells:
    11
    Template:
    1
    Tutorials:
    4
    JASS:
    3
    Resources:
    22
    Holding old units hidden and invul is probably really best. and giving user access to this list. Then he can create defusion spells, or custom events himself in use cases, or just use the info somewhere else, in a multiboard or in what ever way.
     
  12. Rheiko

    Rheiko

    Joined:
    Aug 27, 2013
    Messages:
    2,942
    Resources:
    7
    Icons:
    2
    Spells:
    3
    Tutorials:
    2
    Resources:
    7
    Hurray!
    Something
    [​IMG]


    looks kewl :D
     
  13. Tasyen

    Tasyen

    Joined:
    Jul 18, 2010
    Messages:
    1,031
    Resources:
    11
    Tools:
    2
    Maps:
    2
    Spells:
    5
    Tutorials:
    1
    JASS:
    1
    Resources:
    11
    Updated to V5V5a.


    Edit: There is currently a bug, Fusions Units with active defusion and without mana kill monitoring -> therefore defusionAfterDur overall, will be fixed in next version.


    Edit: Updated to V6
     
    Last edited: Jul 22, 2017
  14. Tasyen

    Tasyen

    Joined:
    Jul 18, 2010
    Messages:
    1,031
    Resources:
    11
    Tools:
    2
    Maps:
    2
    Spells:
    5
    Tutorials:
    1
    JASS:
    1
    Resources:
    11
    Updated to V7.
    V7 offers better Events, the allowed states were replaced by Triggers beeing conditions (more freedom).
    Variables are now better structed:
    Data, Current, System, Object, Item, Event .
    Data/current/Event are for users the important ones.

    Data for creation.
    Current for Filters / different usage
    Event​

    and is pretty hard to update.
     
  15. _Guhun_

    _Guhun_

    Joined:
    Jun 12, 2010
    Messages:
    294
    Resources:
    4
    Spells:
    3
    Tutorials:
    1
    Resources:
    4
    Definitely an interesting and well put together system. It is unique, could be useful and has an extensive API that would take very long to replicate (thus making the system useful). Since I can't immediately think of anything that the system is missing, I will give it a 5/5 :)

    EDIT: Did not test if there were any bugs with ver 7, but there weren't any when I tested it before.
     
  16. IcemanBo

    IcemanBo

    Joined:
    Sep 6, 2013
    Messages:
    5,990
    Resources:
    22
    Maps:
    3
    Spells:
    11
    Template:
    1
    Tutorials:
    4
    JASS:
    3
    Resources:
    22
    I am sorry, I can not test the map at the moment, but I took a quite long look at the code.

    • Hashtable can be used to:
      • Bind instance to SpellTypeId.
      • Bind UnitType(s) of registerable units for an instance.
      • Bind Instance to Fusioned unit.

    • function UnitFusionUse
      • Filter can be static/global instead of being dynamicly created and destroyed.
      • SpellTarget() seems always tried to be added to Fusion_Object_Group, even if it would not exist.
      • One FoG + counter for validated units could be used instead of 3 seperated ForGroup actions.

    • Some functions could be stored into locals, for performance.

    • Attachment point -> configurable.

    • Amount of required/merged units for a fusion can be stored/tracked of. It would simplify some calculations.

    • Could you please elaborate this code part a bit:
      Code (vJASS):

      loop
              if udg_Fusion_Data_UnitTypes[indexCurrent] == 0 then
                  set hasWildcard = true
                  exitwhen true
              endif  
              set indexCurrent = indexCurrent + 1
              exitwhen indexCurrent > indexEnd
          endloop



    • GetAbilityName() -> GetObjectName()

    • I guess that logics of direct fusion creation can be merged with logics from the function where pulled units timer finished, and the fusion gets created. -> 1 function maybe. Is this possible?

    • Death check for 0.5 life is not idea. Google! ;) ^^

    • I'm not biggest fan from including each logics inside one system that might be avoided, such like those timed features/effects, like transparance. But I guess you want to keep it compact in your system, it's your good choice.

    • The systems looks like it does include some good default features which can be used, such like the onDeath, or timed effect. It makes it simpler to use those features, which is good. On the other side, providing all information, like list of fusioned units, etc + events would be more modular, and user would need to/could define such features himself, if needed.

    • I guess MAX_INVENTORY could be replaced by current max size of unit inventory.

    • The function to care for "best items" of a unit seems like a good idea.

    The resource size pretty much increased, and got also harder to review. Not sure I could spot everything, if some other reviewer could practicaly test it, next to the theory approach, it would be cool, too. But I guess it should work pretty much and good.

    The system looks good, I like it definitly more than old/other approaches.
     
    Last edited: Sep 8, 2017
  17. Kyrbi0

    Kyrbi0

    Joined:
    Jul 29, 2008
    Messages:
    7,648
    Resources:
    1
    Models:
    1
    Resources:
    1
    Very cool!

    "GUI-friendly", but it's in vJass (and so does it need WEX or whatever)?
     
  18. IcemanBo

    IcemanBo

    Joined:
    Sep 6, 2013
    Messages:
    5,990
    Resources:
    22
    Maps:
    3
    Spells:
    11
    Template:
    1
    Tutorials:
    4
    JASS:
    3
    Resources:
    22
    I believe it can be used with default WorldEditor!:)
     
  19. KILLCIDE

    KILLCIDE

    Administrator

    Joined:
    Jul 22, 2015
    Messages:
    3,479
    Resources:
    20
    Models:
    2
    Icons:
    10
    Spells:
    7
    Tutorials:
    1
    Resources:
    20
    I don't see any vJass o: