1. Are you planning to upload your awesome spell or system to Hive? Please review the rules here.
    Dismiss Notice
  2. The mythological era has spawned some interesting characters around. Check them out and be sure to vote for them in the 30th Poll of the Texturing Contest.
    Dismiss Notice
  3. The 20th iteration of the Terraining Contest is upon us! Join and create exquisite Water Structures for it.
    Dismiss Notice
  4. Hivers united and created a bunch of 2v2 melee maps. Vote for the best in our Melee Mapping Contest #4 - Poll!
    Dismiss Notice
  5. Check out the Staff job openings thread.
    Dismiss Notice

Trigger Viewer

Amaterasu.w3x
Variables
Testmap
Revive
GUI Spell System
Spell System Config
Spell System
Spell System Sample Config
Spell System Sample Trigger
Spell System Sample Filter
Spell System All In One Template
Amaterasu
Amaterasu Config
Amaterasu Cast
Amaterasu Loop
Amaterasu End
Enter map-specific custom script code below. This text will be included in the map script after variables are declared and before any trigger code.

		
Name Type Is Array Initial Value
Amaterasu_AT attacktype No
Amaterasu_Backlash real Yes
Amaterasu_Base_Radius real Yes
Amaterasu_BurnSFX string No
Amaterasu_Damage real Yes
Amaterasu_DamageIncPerSecond real Yes
Amaterasu_Dissipation boolean Yes
Amaterasu_DissipationFactor real No
Amaterasu_DissipationTime real No
Amaterasu_DT damagetype No
Amaterasu_Dummy unit Yes
Amaterasu_Expand_Radius real Yes
Amaterasu_FinalDamage real Yes
Amaterasu_PainSFX string No
Amaterasu_PainSFXAttach string No
Amaterasu_Radius real Yes
Amaterasu_SFX_Form effect Yes
Amaterasu_Target unit No
Dipper_Phases integer Yes
Spell__Ability abilcode No
Spell__AutoAddTargets boolean No
Spell__BuffAbility abilcode No
Spell__BuffOrder ordercode No
Spell__Caster unit No
Spell__CasterOwner player No
Spell__CastPoint location No
Spell__Channeling boolean No
Spell__Completed boolean No
Spell__DummyOwner player No
Spell__DummyType unitcode No
Spell__Duration real No
Spell__DurationPerLevel real No
Spell__Expired boolean No
Spell__Filter_AllowAlly boolean No
Spell__Filter_AllowDead boolean No
Spell__Filter_AllowEnemy boolean No
Spell__Filter_AllowFlying boolean No
Spell__Filter_AllowHero boolean No
Spell__Filter_AllowLiving boolean No
Spell__Filter_AllowMagicImmune boolean No
Spell__Filter_AllowMechanical boolean No
Spell__Filter_AllowNonHero boolean No
Spell__Filter_AllowStructure boolean No
Spell__Hash hashtable No
Spell__Index integer No
Spell__InRange real No
Spell__InRangeCount integer No
Spell__InRangeGroup group No
Spell__InRangeMax integer No
Spell__InRangePoint location No
Spell__InRangeUnit unit No
Spell__InRangeUnits unit Yes
Spell__Interval real No
Spell__Level integer No
Spell__LevelMultiplier real No
Spell__Running boolean No
Spell__StartDuration boolean No
Spell__Target unit No
Spell__TargetGroup group No
Spell__TargetPoint location No
Spell__Time real No
Spell__Trigger_InRangeFilter trigger No
Spell__Trigger_OnCast trigger No
Spell__Trigger_OnChannel trigger No
Spell__Trigger_OnEffect trigger No
Spell__Trigger_OnFinish trigger No
Spell__Trigger_OnLoop trigger No
Spell__UseTargetGroup boolean No
Spell__WakeTargets boolean No
Spell_i_Abil abilcode Yes
Spell_i_AllowAlly boolean Yes
Spell_i_AllowDead boolean Yes
Spell_i_AllowEnemy boolean Yes
Spell_i_AllowFlying boolean Yes
Spell_i_AllowHero boolean Yes
Spell_i_AllowLiving boolean Yes
Spell_i_AllowMagicImmune boolean Yes
Spell_i_AllowMechanical boolean Yes
Spell_i_AllowNonHero boolean Yes
Spell_i_AllowStructure boolean Yes
Spell_i_AutoAddTargets boolean Yes
Spell_i_BuffAbil abilcode Yes
Spell_i_BuffOrder ordercode Yes
Spell_i_Caster unit Yes
Spell_i_Channeling boolean Yes
Spell_i_Completed boolean Yes
Spell_i_Duration real Yes
Spell_i_EventType integer Yes
Spell_i_GroupN integer No
Spell_i_GroupStack group Yes
Spell_i_Head integer Yes
Spell_i_InRangeFilter trigger Yes
Spell_i_Instances integer No
Spell_i_LastTime real Yes
Spell_i_Level integer Yes
Spell_i_Linked boolean Yes
Spell_i_OnCastStack trigger Yes
Spell_i_OnChannelStack trigger Yes
Spell_i_OnEffectStack trigger Yes
Spell_i_OnFinishStack trigger Yes
Spell_i_OnLoopStack trigger Yes
Spell_i_PreloadDummy unit No
Spell_i_Recycle integer No
Spell_i_RecycleList integer Yes
Spell_i_Stack integer Yes
Spell_i_StackN integer No
Spell_i_StackRef integer Yes
Spell_i_Target unit Yes
Spell_i_TargetGroup group Yes
Spell_i_TargetX real Yes
Spell_i_TargetY real Yes
Spell_i_Time real Yes
Spell_i_Timer timer No
Spell_i_UseTG boolean Yes
TempLoc location No
TempUnit unit No
Revive
  Events
    Unit - A unit owned by Player 2 (Blue) Dies
  Conditions
  Actions
    Set TempUnit = (Triggering unit)
    Set TempLoc = (Position of TempUnit)
    Unit - Create 1 (Unit-type of (Triggering unit)) for Player 2 (Blue) at TempLoc facing Default building facing degrees
    Custom script: call RemoveLocation(udg_TempLoc)
Spell System Config
  Events
  Conditions
  Actions
    -------- Only one dummy unit type is needed as you can attach an effect to it of any kind --------
    -------- --------
    Set Spell__DummyType = Dummy (Vexorian, Anitarf, Infrane)
    Set Spell__DummyOwner = Neutral Extra
    Set Spell__Interval = (1 / 32.00)
    -------- --------
    -------- Configure default values for the unit filter: --------
    -------- --------
    Set Spell__Filter_AllowEnemy = True
    Set Spell__Filter_AllowLiving = True
    Set Spell__Filter_AllowHero = True
    Set Spell__Filter_AllowNonHero = True
    Set Spell__Filter_AllowAlly = False
    Set Spell__Filter_AllowDead = False
    Set Spell__Filter_AllowFlying = False
    Set Spell__Filter_AllowMechanical = False
    Set Spell__Filter_AllowStructure = False
    -------- --------
    -------- Magic immunity is a great thing to block, as it also discludes invulnerable units from being picked --------
    -------- --------
    Set Spell__Filter_AllowMagicImmune = False
    -------- --------
    -------- Normal WC3 abilities, like Channel, wake sleeping creeps - even if they don't deal damage or apply buffs. --------
    -------- Because of this, I provided an option to wake up creeps when they are enumerated by an InRange command. --------
    -------- --------
    Set Spell__WakeTargets = True
    -------- --------
    -------- Do not enable the following lines as they are variable declarations which make copying this system easier --------
    -------- --------
    Set Spell_i_Level[(Integer(Spell__LevelMultiplier))] = (Spell__Level + (Player number of Spell__CasterOwner))
    Set Spell_i_TargetX[(Integer(Spell_i_TargetY[(Integer(Spell_i_Time[(Integer(Spell__Time))]))]))] = ((X of Spell__CastPoint) + (X of Spell__TargetPoint))
    Set Spell__Caster = Spell_i_Caster[(Custom value of Spell_i_Target[(Custom value of Spell__Target)])]
    Unit Group - Add all units of Spell_i_TargetGroup[0] to Spell__TargetGroup
    Set Spell__Running = Spell__UseTargetGroup
    Set Spell__Completed = Spell_i_UseTG[Spell_i_Level[(Integer((Elapsed time for Spell_i_Timer)))]]
    Set Spell_i_Completed[0] = Spell_i_Linked[Spell_i_EventType[0]]
    Set Spell__Trigger_OnLoop = Spell_i_OnLoopStack[(Load 0 of 0 from Spell__Hash)]
    Set Spell__Trigger_OnFinish = Spell_i_OnFinishStack[Spell__Index]
    Set Spell__Trigger_OnEffect = Spell_i_OnEffectStack[0]
    Set Spell__Trigger_OnChannel = Spell_i_OnChannelStack[0]
    Set Spell__Trigger_OnCast = Spell_i_OnCastStack[Spell_i_Recycle]
    Set Spell_i_Instances = Spell_i_Head[Spell_i_RecycleList[Spell_i_Stack[Spell_i_StackRef[Spell_i_StackN]]]]
    Set Spell_i_PreloadDummy = No unit
    Set Spell__Ability = Spell_i_Abil[0]
    Set Spell__InRangeGroup = (Units within Spell__InRange of Spell__InRangePoint)
    Set Spell_i_AllowAlly[0] = Spell__Filter_AllowAlly
    Set Spell_i_AllowDead[0] = Spell__Filter_AllowDead
    Set Spell_i_AllowEnemy[0] = Spell__Filter_AllowEnemy
    Set Spell_i_AllowFlying[0] = Spell__Filter_AllowFlying
    Set Spell_i_AllowHero[0] = Spell__Filter_AllowHero
    Set Spell_i_AllowMagicImmune[0] = Spell__Filter_AllowMagicImmune
    Set Spell_i_AllowMechanical[0] = Spell__Filter_AllowMechanical
    Set Spell_i_AllowNonHero[0] = Spell__Filter_AllowNonHero
    Set Spell_i_AllowStructure[0] = Spell__Filter_AllowStructure
    Set Spell_i_AllowLiving[0] = Spell__Filter_AllowLiving
    Set Spell__Channeling = Spell_i_Channeling[0]
    Set Spell_i_GroupN = (Number of units in Spell_i_GroupStack[0])
    Set Spell__InRangeUnits[Spell__InRangeCount] = No unit
    Set Spell__Duration = (Spell_i_Duration[(Integer(Spell__DurationPerLevel))] + Spell_i_LastTime[0])
    Set Spell__Expired = Spell__StartDuration
    Set Spell__InRangeMax = ((Supply used by Spell__InRangeUnit) + ((Evaluation count of Spell__Trigger_InRangeFilter) + (Evaluation count of Spell_i_InRangeFilter[0])))
    Set Spell__AutoAddTargets = Spell_i_AutoAddTargets[0]
    Set Spell__BuffOrder = Spell_i_BuffOrder[0]
    Set Spell__BuffAbility = Spell_i_BuffAbil[0]
function SpellIndexGetVars takes integer i returns nothing
    set udg_Spell__Ability = udg_Spell_i_Abil[udg_Spell_i_Head[i]]
    set udg_Spell__Index = i
    set udg_Spell__Caster = udg_Spell_i_Caster[i]
    set udg_Spell__CasterOwner = GetOwningPlayer(udg_Spell__Caster)
    set udg_Spell__Level = udg_Spell_i_Level[i]
    set udg_Spell__LevelMultiplier = udg_Spell__Level //Spell__LevelMultiplier is a real variable.
    set udg_Spell__Target = udg_Spell_i_Target[i]
   
    //Magic to ensure the locations never leak.
    call MoveLocation(udg_Spell__CastPoint, GetUnitX(udg_Spell__Caster), GetUnitY(udg_Spell__Caster))
    if udg_Spell__Target == null then
        call MoveLocation(udg_Spell__TargetPoint, udg_Spell_i_TargetX[i], udg_Spell_i_TargetY[i])
    else
        call MoveLocation(udg_Spell__TargetPoint, GetUnitX(udg_Spell__Target), GetUnitY(udg_Spell__Target))
    endif
    set udg_Spell__TargetGroup = udg_Spell_i_TargetGroup[i]
    set udg_Spell__Completed = udg_Spell_i_Completed[i]
    set udg_Spell__Channeling = udg_Spell_i_Channeling[i]
endfunction
function SpellSetFilters takes integer i returns nothing
    set udg_Spell_i_AllowEnemy[i]       = udg_Spell__Filter_AllowEnemy
    set udg_Spell_i_AllowAlly[i]        = udg_Spell__Filter_AllowAlly
    set udg_Spell_i_AllowDead[i]        = udg_Spell__Filter_AllowDead
    set udg_Spell_i_AllowLiving[i]      = udg_Spell__Filter_AllowLiving
    set udg_Spell_i_AllowMagicImmune[i] = udg_Spell__Filter_AllowMagicImmune
    set udg_Spell_i_AllowMechanical[i]  = udg_Spell__Filter_AllowMechanical
    set udg_Spell_i_AllowStructure[i]   = udg_Spell__Filter_AllowStructure
    set udg_Spell_i_AllowFlying[i]      = udg_Spell__Filter_AllowFlying
    set udg_Spell_i_AllowHero[i]        = udg_Spell__Filter_AllowHero
    set udg_Spell_i_AllowNonHero[i]     = udg_Spell__Filter_AllowNonHero
endfunction
function SpellIndexDestroy takes integer i returns nothing
    local integer indexOf
    local integer index
    if udg_Spell_i_RecycleList[i] >= 0 then
        return
    endif
    //If the caster is still channeling on the spell, don't destroy until it's finished:
    if not udg_Spell_i_Channeling[i] then
        set index = udg_Spell_i_Head[i]
        set udg_Spell_i_RecycleList[i] = udg_Spell_i_Recycle
        set udg_Spell_i_Recycle = i
       
        //Reset things to defaults:
        set udg_Spell_i_Time[i] = 0.00
        set udg_Spell_i_LastTime[i] = 0.00
        set udg_Spell_i_Duration[i] = 0.00
        set udg_Spell_i_Completed[i] = false
        set udg_Spell_i_Caster[i] = null
        set udg_Spell_i_Target[i] = null
        set udg_Spell_i_OnLoopStack[i] = null
       
        //Recycle any applicable target unit group.
        if udg_Spell_i_TargetGroup[i] != null then
            call GroupClear(udg_Spell_i_TargetGroup[i])
            set udg_Spell_i_GroupStack[udg_Spell_i_GroupN] = udg_Spell_i_TargetGroup[i]
            set udg_Spell_i_GroupN = udg_Spell_i_GroupN + 1
            set udg_Spell_i_TargetGroup[i] = null
        endif
       
        //Clear any user-specified data in the hashtable:
        call FlushChildHashtable(udg_Spell__Hash, i)
        //call BJDebugMsg("Destroying index: " + I2S(i))
    endif
   
    set indexOf = udg_Spell_i_StackRef[i]
    if indexOf >= 0 then
        set index = udg_Spell_i_StackN - 1
        set udg_Spell_i_StackN = index
       
        set udg_Spell_i_StackRef[udg_Spell_i_Stack[index]] = indexOf
        set udg_Spell_i_Stack[indexOf] = udg_Spell_i_Stack[index]
        if index == 0 then
            //If no more spells require the timer, pause it.
            call PauseTimer(udg_Spell_i_Timer)
        endif
        set udg_Spell_i_StackRef[i] = -1
    endif
endfunction
function SpellTriggerExecute takes integer i, trigger t returns real
    local real d = udg_Spell_i_Duration[i]
    local boolean b = false
    set udg_Spell__Duration = d
    set udg_Spell__Time = 0.00
    if t != null then
        set udg_Spell__Trigger_OnLoop = null
        set udg_Spell__Expired = d <= 0.00 //If the duration is <= 0, the spell has expired.
        call SpellIndexGetVars(i)
        if TriggerEvaluate(t) then
            call TriggerExecute(t)
        endif
        if udg_Spell__Trigger_OnLoop != null then
            set udg_Spell_i_OnLoopStack[i] = udg_Spell__Trigger_OnLoop
        endif
        //The remaining lines in this function process the duration specified by the user.
        if udg_Spell__StartDuration then
            set udg_Spell__StartDuration = false
            set udg_Spell__Duration = udg_Spell_i_Duration[udg_Spell_i_Head[i]] + udg_Spell_i_LastTime[udg_Spell_i_Head[i]]*udg_Spell__LevelMultiplier
        elseif (udg_Spell__Expired and d > 0.00) or (udg_Spell__Duration <= 0.00) then
            set udg_Spell__Duration = 0.00
            return udg_Spell__Time
            //The user manually expired the spell or the spell duration ended on its own.
        endif
        if d != udg_Spell__Duration then
            //A new duration has been assigned
            set d = udg_Spell__Duration
            set b = true
        endif
        set udg_Spell__Duration = 0.00
        if udg_Spell__Time == 0.00 then
            if udg_Spell_i_LastTime[i] == 0.00 then
                if udg_Spell_i_Time[udg_Spell_i_Head[i]] > 0.00 then
                    //The user specified a default interval to follow:
                    set udg_Spell__Time = udg_Spell_i_Time[udg_Spell_i_Head[i]]
                else
                    //Set the spell time to the minimum.
                    set udg_Spell__Time = udg_Spell__Interval
                endif
            else
                //Otherwise, set it to what it was before.
                set udg_Spell__Time = udg_Spell_i_LastTime[i]
            endif
        //else, the user is specifying a new time for the spell.
        endif
        set udg_Spell_i_LastTime[i] = udg_Spell__Time //Whatever the case, remember this time for next time.
        if b then
            //The duration was just assigned
            set udg_Spell_i_Duration[i] = d
        else
            //The duration has been ongoing
            set udg_Spell_i_Duration[i] = d - udg_Spell__Time
        endif
    endif
    return udg_Spell__Time
endfunction
//===========================================================================
// Runs every Spell__Interval seconds and handles all of the timed events.
//
function SpellTimerLoop takes nothing returns nothing
    local integer i = udg_Spell_i_StackN
    local integer node
    local real time
    set udg_Spell__Running = true
   
    //Run stack top to bottom to avoid skipping slots when destroying.
    loop
        set i = i - 1
        exitwhen i < 0
        set node = udg_Spell_i_Stack[i]
        set time = udg_Spell_i_Time[node] - udg_Spell__Interval
        if time <= 0.00 then
            set time = SpellTriggerExecute(node, udg_Spell_i_OnLoopStack[node])
        endif
        if time <= 0.00 then
            call SpellIndexDestroy(node)
        else
            set udg_Spell_i_Time[node] = time
        endif
    endloop
    set udg_Spell__Running = false
endfunction
//===========================================================================
// This is the meat of the system as it handles the event responses.
//
function RunSpellEvent takes nothing returns boolean
    local boolean b
    local integer aid = GetSpellAbilityId()
    local integer head = LoadInteger(udg_Spell__Hash, 0, aid)
    local integer i
    local integer id
    local trigger t
    local playerunitevent eid
    if head == 0 then
        //Nothing for this ability has been registered. Skip the sequence.
        return false
    endif
    set eid = ConvertPlayerUnitEvent(GetHandleId(GetTriggerEventId()))
    set udg_Spell__Caster = GetTriggerUnit()
    set id = GetHandleId(udg_Spell__Caster)
    set i = LoadInteger(udg_Spell__Hash, aid, id)
    if i == 0 then
        //This block will almost always happen with the OnChannel event. In the
        //case of Charge Gold and Lumber, only an OnEffect event will run.
        set i = udg_Spell_i_Recycle
        if i == 0 then
            //Create a new, unique index
            set i = udg_Spell_i_Instances + 1
            set udg_Spell_i_Instances = i
        else
            //Repurpose an existing one
            set udg_Spell_i_Recycle = udg_Spell_i_RecycleList[i]
        endif
        //call BJDebugMsg("Creating index: " + I2S(i))
        set udg_Spell_i_RecycleList[i] = -1
        set udg_Spell_i_StackRef[i] = -1
        set udg_Spell_i_Head[i] = head
       
        if eid == EVENT_PLAYER_UNIT_SPELL_CHANNEL then
            set udg_Spell_i_Channeling[i] = true
            call SaveInteger(udg_Spell__Hash, aid, id, i)
            set t = udg_Spell_i_OnChannelStack[head]
        else //eid == EVENT_PLAYER_UNIT_SPELL_EFFECT
            set t = udg_Spell_i_OnEffectStack[head]
        endif
        set udg_Spell_i_Caster[i] = udg_Spell__Caster
        set udg_Spell_i_Level[i] = GetUnitAbilityLevel(udg_Spell__Caster, aid)
        set udg_Spell_i_Target[i] = GetSpellTargetUnit()
        set udg_Spell_i_TargetX[i] = GetSpellTargetX()
        set udg_Spell_i_TargetY[i] = GetSpellTargetY()
       
        set udg_Spell_i_OnLoopStack[i] = udg_Spell_i_OnLoopStack[head]
        if udg_Spell_i_UseTG[head] then
            //Get a recycled unit group or create a new one.
            set id = udg_Spell_i_GroupN - 1
            if id >= 0 then
                set udg_Spell_i_GroupN = id
                set udg_Spell_i_TargetGroup[i] = udg_Spell_i_GroupStack[id]
            else
                set udg_Spell_i_TargetGroup[i] = CreateGroup()
            endif
        endif
    elseif eid == EVENT_PLAYER_UNIT_SPELL_CAST then
        set t = udg_Spell_i_OnCastStack[head]
    elseif eid == EVENT_PLAYER_UNIT_SPELL_EFFECT then
        set t = udg_Spell_i_OnEffectStack[head]
    elseif eid == EVENT_PLAYER_UNIT_SPELL_FINISH then
        set udg_Spell_i_Completed[i] = true
        return true
    else //eid == EVENT_PLAYER_UNIT_SPELL_ENDCAST
        set udg_Spell_i_Channeling[i] = false
        call RemoveSavedInteger(udg_Spell__Hash, aid, id)
        set t = udg_Spell_i_OnFinishStack[head]
    endif
    if SpellTriggerExecute(i, t) > 0.00 then
        //Set the spell time to the user-specified one.
        set udg_Spell_i_Time[i] = udg_Spell__Time
        if udg_Spell_i_StackRef[i] < 0 then
            //Allocate the spell index onto the loop stack.
            set aid = udg_Spell_i_StackN
            set udg_Spell_i_Stack[aid] = i
            set udg_Spell_i_StackRef[i] = aid
            set udg_Spell_i_StackN = aid + 1
            if aid == 0 then
                //If this is the first spell index using the timer, start it up:
                call TimerStart(udg_Spell_i_Timer, udg_Spell__Interval, true, function SpellTimerLoop)
            endif
        endif
    elseif (not udg_Spell_i_Channeling[i]) and (t != null or udg_Spell_i_Time[i] <= 0.00) then
        call SpellIndexDestroy(i)
    endif
    set t = null
    return true
endfunction
//This function is invoked if an event was launched recursively by another event's callback.
function RunPreSpellEvent takes nothing returns nothing
    local integer i = udg_Spell__Index
    local real time = udg_Spell__Time
    local real d = udg_Spell__Duration
    local boolean expired = udg_Spell__Expired
    if udg_Spell__Trigger_OnLoop != null then
        set udg_Spell_i_OnLoopStack[i] = udg_Spell__Trigger_OnLoop
    endif
    if RunSpellEvent() then
        set udg_Spell__Time = time
        set udg_Spell__Duration = d
        set udg_Spell__Expired = expired
        call SpellIndexGetVars(i)
    endif
endfunction
//===========================================================================
// Base function of the system: runs when an ability event does something.
//
function SpellSystemEvent takes nothing returns boolean
    if udg_Spell__Running then
        call RunPreSpellEvent()
    else
        set udg_Spell__Running = true
        call RunSpellEvent()
        set udg_Spell__Running = false
    endif
    return false
endfunction
//===========================================================================
// Set Spell__Ability to your spell's ability
// Set Spell__Trigger_OnChannel/Cast/Effect/Finish/Loop to any trigger(s) you
// want to automatically run.
//
// GUI-friendly: Run Spell System <gen> (ignoring conditions)
//
function SpellSystemRegister takes nothing returns nothing
    local integer aid = udg_Spell__Ability
    local integer head = udg_Spell_i_Instances + 1
   
    if HaveSavedInteger(udg_Spell__Hash, 0, aid) or aid == 0 then
        //The system rejects duplicate or unassigned abilities.
        return
    endif
    set udg_Spell_i_Instances = head
    set udg_Spell_i_Abil[head] = aid
   
    //Preload the ability on dummy unit to help prevent first-instance lag
    call UnitAddAbility(udg_Spell_i_PreloadDummy, aid)
   
    //Save head index to the spell ability so it be referenced later.
    call SaveInteger(udg_Spell__Hash, 0, aid, head)
   
    //Set any applicable event triggers.
    set udg_Spell_i_OnChannelStack[head]= udg_Spell__Trigger_OnChannel
    set udg_Spell_i_OnCastStack[head]   = udg_Spell__Trigger_OnCast
    set udg_Spell_i_OnEffectStack[head] = udg_Spell__Trigger_OnEffect
    set udg_Spell_i_OnFinishStack[head] = udg_Spell__Trigger_OnFinish
    set udg_Spell_i_OnLoopStack[head]   = udg_Spell__Trigger_OnLoop
    set udg_Spell_i_InRangeFilter[head] = udg_Spell__Trigger_InRangeFilter
   
    //Set any customized filter variables:
    call SpellSetFilters(head)
   
    //Tell the system to automatically create target groups, if needed
    set udg_Spell_i_AutoAddTargets[head] = udg_Spell__AutoAddTargets
    set udg_Spell_i_UseTG[head] = udg_Spell__UseTargetGroup or udg_Spell__AutoAddTargets
   
    //Handle automatic buff assignment
    set udg_Spell_i_BuffAbil[head] = udg_Spell__BuffAbility
    set udg_Spell_i_BuffOrder[head] = udg_Spell__BuffOrder
   
    //Set the default time sequences if a duration is used:
    set udg_Spell_i_Time[head]     = udg_Spell__Time
    set udg_Spell_i_Duration[head] = udg_Spell__Duration
    set udg_Spell_i_LastTime[head] = udg_Spell__DurationPerLevel
   
    //Set variables back to their defaults:
    set udg_Spell__Trigger_OnChannel    = null
    set udg_Spell__Trigger_OnCast       = null
    set udg_Spell__Trigger_OnEffect     = null
    set udg_Spell__Trigger_OnFinish     = null
    set udg_Spell__Trigger_OnLoop       = null
    set udg_Spell__Trigger_InRangeFilter= null
    set udg_Spell__AutoAddTargets       = false
    set udg_Spell__UseTargetGroup       = false
    set udg_Spell__Time                 = 0.00
    set udg_Spell__Duration             = 0.00
    set udg_Spell__DurationPerLevel     = 0.00
    set udg_Spell__BuffAbility          = 0
    set udg_Spell__BuffOrder            = 0
   
    set udg_Spell__Filter_AllowEnemy        = udg_Spell_i_AllowEnemy[0]
    set udg_Spell__Filter_AllowAlly         = udg_Spell_i_AllowAlly[0]
    set udg_Spell__Filter_AllowDead         = udg_Spell_i_AllowDead[0]
    set udg_Spell__Filter_AllowMagicImmune  = udg_Spell_i_AllowMagicImmune[0]
    set udg_Spell__Filter_AllowMechanical   = udg_Spell_i_AllowMechanical[0]
    set udg_Spell__Filter_AllowStructure    = udg_Spell_i_AllowStructure[0]
    set udg_Spell__Filter_AllowFlying       = udg_Spell_i_AllowFlying[0]
    set udg_Spell__Filter_AllowHero         = udg_Spell_i_AllowHero[0]
    set udg_Spell__Filter_AllowNonHero      = udg_Spell_i_AllowNonHero[0]
    set udg_Spell__Filter_AllowLiving       = udg_Spell_i_AllowLiving[0]
endfunction
function SpellFilterCompare takes boolean is, boolean yes, boolean no returns boolean
    return (is and yes) or ((not is) and no)
endfunction
//===========================================================================
// Before calling this function, set Spell__InRangePoint to whatever point
// you need, THEN set Spell__InRange to the radius you need. The system will
// enumerate the units matching the configured filter and fill them into
// Spell_InRangeGroup.
//
function SpellGroupUnitsInRange takes nothing returns boolean
    local integer i = udg_Spell_i_Head[udg_Spell__Index]
    local integer j = 0
    local unit u
    local real padding = 64.00
    if udg_Spell_i_AllowStructure[i] then
        //A normal unit can only have up to size 64.00 collision, but if the
        //user needs to check for structures we need a padding big enough for
        //the "fattest" ones: Tier 3 town halls.
        set padding = 197.00
    endif
    call GroupEnumUnitsInRangeOfLoc(udg_Spell__InRangeGroup, udg_Spell__InRangePoint, udg_Spell__InRange + padding, null)
    loop
        set u = FirstOfGroup(udg_Spell__InRangeGroup)
        exitwhen u == null
        call GroupRemoveUnit(udg_Spell__InRangeGroup, u)
        loop
            exitwhen udg_Spell_i_AutoAddTargets[i] and IsUnitInGroup(u, udg_Spell__TargetGroup)
            exitwhen not IsUnitInRangeLoc(u, udg_Spell__InRangePoint, udg_Spell__InRange)
            exitwhen not SpellFilterCompare(IsUnitType(u, UNIT_TYPE_DEAD), udg_Spell_i_AllowDead[i], udg_Spell_i_AllowLiving[i])
            exitwhen not SpellFilterCompare(IsUnitAlly(u, udg_Spell__CasterOwner), udg_Spell_i_AllowAlly[i], udg_Spell_i_AllowEnemy[i])
            exitwhen not SpellFilterCompare(IsUnitType(u, UNIT_TYPE_HERO) or IsUnitType(u, UNIT_TYPE_RESISTANT), udg_Spell_i_AllowHero[i], udg_Spell_i_AllowNonHero[i])
            exitwhen IsUnitType(u, UNIT_TYPE_STRUCTURE) and not udg_Spell_i_AllowStructure[i]
            exitwhen IsUnitType(u, UNIT_TYPE_FLYING) and not udg_Spell_i_AllowFlying[i]
            exitwhen IsUnitType(u, UNIT_TYPE_MECHANICAL) and not udg_Spell_i_AllowMechanical[i]
            exitwhen IsUnitType(u, UNIT_TYPE_MAGIC_IMMUNE) and not udg_Spell_i_AllowMagicImmune[i]
            set udg_Spell__InRangeUnit = u
            //Run the user's designated filter, if one exists.
            exitwhen udg_Spell_i_InRangeFilter[i] != null and not TriggerEvaluate(udg_Spell_i_InRangeFilter[i])
            set j = j + 1
            set udg_Spell__InRangeUnits[j] = u
            exitwhen true
        endloop
    endloop
    if j > udg_Spell__InRangeMax and udg_Spell__InRangeMax > 0 then
        //The user has defined a maximum number of units allowed in the group.
        //Remove a random unit until the total does not exceed capacity.
        loop
            set i = GetRandomInt(1, j)
            set udg_Spell__InRangeUnits[i] = udg_Spell__InRangeUnits[j]
            set j = j - 1
            exitwhen j == udg_Spell__InRangeMax
        endloop
    endif
    set udg_Spell__InRangeCount = j
    set udg_Spell__InRangeMax = 0
    set udg_Spell__InRange = 0.00
    set i = udg_Spell_i_Head[udg_Spell__Index]
    loop
        exitwhen j == 0
        set u = udg_Spell__InRangeUnits[j]
        call GroupAddUnit(udg_Spell__InRangeGroup, u)
        if udg_Spell_i_AutoAddTargets[i] then
            call GroupAddUnit(udg_Spell__TargetGroup, u)
        endif
        if udg_Spell__WakeTargets and UnitIsSleeping(u) then
            call UnitWakeUp(u)
        endif
        if udg_Spell_i_BuffAbil[i] != 0 and udg_Spell_i_BuffOrder[i] != 0 then
            //Auto-buff units added to group:
            call UnitAddAbility(udg_Spell_i_PreloadDummy, udg_Spell_i_BuffAbil[i])
            call IssueTargetOrderById(udg_Spell_i_PreloadDummy, udg_Spell_i_BuffOrder[i], u)
            call UnitRemoveAbility(udg_Spell_i_PreloadDummy, udg_Spell_i_BuffAbil[i])
        endif
        set j = j - 1
    endloop
    set u = null
    return false
endfunction
function SpellPreloadEnd takes nothing returns nothing
    local integer i = udg_Spell_i_Instances
    loop
        exitwhen i == 0
        //Remove preloaded abilities so they don't interfere with orders
        call UnitRemoveAbility(udg_Spell_i_PreloadDummy, udg_Spell_i_Abil[udg_Spell_i_Head[i]])
        set i = i - 1
    endloop
endfunction
//===========================================================================
function InitTrig_Spell_System takes nothing returns nothing
    local integer i = bj_MAX_PLAYER_SLOTS
    local player p
    local trigger t
   
    if gg_trg_Spell_System != null then
        //A JASS function call already initialized the system.
        return
    endif
   
    //This runs before map init events so the hashtable is ready before then.
    set udg_Spell__Hash = InitHashtable()
   
    //Initialize these two locations which will never get removed
    set udg_Spell__CastPoint = Location(0, 0)
    set udg_Spell__TargetPoint = Location(0, 0)
   
    //Recycle existing unit groups into the recycle stack to avoid needing to destroy any extras.
    set udg_Spell_i_GroupStack[2] = udg_Spell__TargetGroup
    set udg_Spell_i_GroupStack[3] = udg_Spell_i_TargetGroup[0]
    set udg_Spell_i_GroupStack[4] = udg_Spell_i_TargetGroup[1]
    set udg_Spell_i_GroupN = 5 //There are already five valid unit groups thanks to Variable Editor.
   
    set t = CreateTrigger()
    call TriggerRegisterVariableEvent(t, "udg_Spell__InRange", GREATER_THAN, 0.00)
    call TriggerAddCondition(t, Filter(function SpellGroupUnitsInRange))
   
    set t = CreateTrigger()
    call TriggerAddCondition(t, Filter(function SpellSystemEvent))
    loop
        set i = i - 1
        set p = Player(i)
        call TriggerRegisterPlayerUnitEvent(t, p, EVENT_PLAYER_UNIT_SPELL_CHANNEL, null)
        call TriggerRegisterPlayerUnitEvent(t, p, EVENT_PLAYER_UNIT_SPELL_CAST, null)
        call TriggerRegisterPlayerUnitEvent(t, p, EVENT_PLAYER_UNIT_SPELL_EFFECT, null)
        call TriggerRegisterPlayerUnitEvent(t, p, EVENT_PLAYER_UNIT_SPELL_FINISH, null)
        call TriggerRegisterPlayerUnitEvent(t, p, EVENT_PLAYER_UNIT_SPELL_ENDCAST, null)
        exitwhen i == 0
    endloop
    set p = null
    set t = null
   
    //Run the configuration trigger so its variables are ready before the
    //map initialization events run.
    call TriggerExecute(gg_trg_Spell_System_Config)
    call SpellSetFilters(0)
   
    //Create this trigger so it's GUI-friendly.
    set gg_trg_Spell_System = CreateTrigger()
    call TriggerAddAction(gg_trg_Spell_System, function SpellSystemRegister)
    set gg_trg_Spell_System_Config = gg_trg_Spell_System //In case the user accidentally picks this one
   
    //Create a dummy unit for preloading abilities and casting buffs.
    set udg_Spell_i_PreloadDummy = CreateUnit(udg_Spell__DummyOwner, udg_Spell__DummyType, 0, 0, 0)
   
    //Start the timer to remove its abilities:
    call TimerStart(udg_Spell_i_Timer, 0.00, false, function SpellPreloadEnd)
    call UnitRemoveAbility(udg_Spell_i_PreloadDummy, 'Amov') //Force it to never move to cast spells
endfunction
Spell System Sample Config
  Events
    Map initialization
  Conditions
  Actions
    -------- --------
    -------- I have created this trigger as a means to show users what can (or must) be configured for each spell --------
    -------- --------
    -------- You must assign an ability ID to let the system know which spell you're using: --------
    -------- --------
    Set Spell__Ability = (Ability being cast)
    -------- --------
    -------- Next, you must pick at least one of the following types of triggers to run at a phase of the spell: --------
    -------- --------
    Set Spell__Trigger_OnChannel = (This trigger)
    Set Spell__Trigger_OnCast = (This trigger)
    Set Spell__Trigger_OnEffect = (This trigger)
    Set Spell__Trigger_OnFinish = (This trigger)
    -------- --------
    -------- Next, you can specify a trigger to run periodically, if you want that type of behavior. --------
    -------- --------
    Set Spell__Trigger_OnLoop = (This trigger)
    -------- --------
    -------- Added 28 Feb 2016: You can now specify Spell__Time, Spell__Duration and Spell__DurationPerLevel from the Config trigger. --------
    -------- NOTE: With these settings, the OnLoop trigger will run every 1 second for 4/5/6 seconds --------
    -------- --------
    Set Spell__Time = 1.00
    Set Spell__Duration = 3.00
    Set Spell__DurationPerLevel = 1.00
    -------- --------
    -------- The next ones are for the InRange filter, if you use it. You don't have to include any of these for many typical spells. --------
    -------- TIPS: --------
    -------- > For healing spells, you'll want to set AllowAllies to True and AllowEnemies to False. --------
    -------- > If you are creating a "kill unit" spell, you'll want to set AllowHero to False. --------
    -------- > If you are making a custom "Resurrect", you'll want to set AllowDead to True and AllowLiving to False. --------
    -------- > AllowMagicImmune as False also prevents invulnerable units from being picked, which is a plus in my opinion. --------
    -------- --------
    Set Spell__Filter_AllowEnemy = True
    Set Spell__Filter_AllowLiving = True
    Set Spell__Filter_AllowHero = True
    Set Spell__Filter_AllowNonHero = True
    Set Spell__Filter_AllowAlly = False
    Set Spell__Filter_AllowDead = False
    Set Spell__Filter_AllowFlying = False
    Set Spell__Filter_AllowMechanical = False
    Set Spell__Filter_AllowStructure = False
    Set Spell__Filter_AllowMagicImmune = False
    -------- --------
    -------- NEW: Added 17 May 2016 - you can specify your own trigger conditions to add to the InRange check --------
    -------- The trigger conditions reference the unit "Spell__InRangeUnit" --------
    -------- --------
    Set Spell__Trigger_InRangeFilter = Spell_System_Sample_Filter <gen>
    -------- --------
    -------- If you want to keep track of which units have already been hit by the spell, set UseTargetGroup to True --------
    -------- TIPS: --------
    -------- > The group is called Spell__TargetGroup. It starts empty and will destroy itself when the spell is finished --------
    -------- > After using a Spell__InRange check, you can use "Add all units in Spell__InRangeGroup to Spell__TargetGroup" --------
    -------- --------
    Set Spell__UseTargetGroup = True
    -------- --------
    -------- When everything is set the way you want it, run Spell System <gen>: --------
    -------- --------
    Trigger - Run Spell_System <gen> (ignoring conditions)
    -------- --------
    -------- To recap, you MUST set Spell__Ability and you MUST have an OnChannel/Cast/Effect or Finish trigger --------
    -------- --------
Spell System Sample Trigger
  Events
  Conditions
  Actions
    -------- --------
    -------- I have created this sample to show what you can do from Spell__Trigger_OnEffect/Loop/Channel/Cast/Finish. --------
    -------- --------
    -------- The following variables are set so you can see what they represent, but in a real spell they will already be set to these values --------
    -------- TIPS: --------
    -------- > Spell__CastPoint and Spell__TargetPoint should never be removed as they do not leak --------
    -------- > Spell__CasterOwner will change if the caster changes ownership during the spell due to "Charm" or "Possession" --------
    -------- > Spell__Level will stay the same even if the ability was leveled up during the spell --------
    -------- > Unlike in normal WC3 events, Spell__Target and Spell__TargetPoint actually work from an OnFinish event. --------
    -------- --------
    Set Spell__Caster = (Casting unit)
    Set Spell__CastPoint = (Position of Spell__Caster)
    Set Spell__CasterOwner = (Owner of Spell__Caster)
    Set Spell__Level = (Level of (Ability being cast) for Spell__Caster)
    Set Spell__LevelMultiplier = (Real(Spell__Level))
    Set Spell__Target = (Target unit of ability being cast)
    Set Spell__TargetPoint = (Target point of ability being cast)
    -------- --------
    -------- I present to you the unique integer index for this particular cast of the spell: Spell__Index --------
    -------- TIPS: --------
    -------- > Spell__Index is used as an array index so that you can store your spell data using it --------
    -------- > This number is unique per-spell, making everything which uses this fully-MUI. --------
    -------- > This number is automatically recycled when the spell is finished or the Spell__Time has expired. --------
    -------- --------
    Set Dipper_Phases[Spell__Index] = 0
    -------- --------
    -------- Specify how long to wait before the OnLoop trigger runs (or runs again, if reset from an OnLoop trigger) --------
    -------- TIPS: --------
    -------- > This is only required if you use the OnLoop trigger --------
    -------- > If you want a spell index to not be destroyed when the OnFinish event runs, you will need to set a Spell__Time to an above-0 value --------
    -------- > If you don't use an OnLoop trigger but want Spell__Index around longer than the channel time, set Spell__Time to how long you'll need that index --------
    -------- --------
    Set Spell__Time = 2.00
    -------- --------
    -------- Alternatively (or additionally), you can set the Spell__Duration to how long the OnLoop trigger should repeat --------
    -------- TIPS: --------
    -------- > If you don't specify a Spell__Time, the OnLoop trigger will run every Spell__Interval (0.03125) seconds --------
    -------- > From the OnLoop trigger, you can check if the spell is about to end via the condition "Spell__Expired Equal to True". --------
    -------- --------
    Set Spell__Duration = 10.00
    -------- --------
    -------- Alternatively, if you set the Spell__Duration (or at least Spell__DurationPerLevel) from the Config trigger, --------
    -------- you can tell the system to start the duration with the Spell__StartDuration boolean: --------
    -------- --------
    Set Spell__StartDuration = True
    -------- --------
    -------- You can change (or even add, if it wasn't yet assigned) your periodic trigger during any phase of the spell, like so: --------
    -------- --------
    Set Spell__Trigger_OnLoop = (This trigger)
    -------- --------
    -------- If you set a Spell__Duration and want to know if it's about to expire, check if Spell__Duration is less than or equal to 0.00 --------
    -------- --------
    If (All Conditions are True) then do (Then Actions) else do (Else Actions)
      If - Conditions
        Spell__Duration Less than or equal to 0.00
      Then - Actions
        -------- The loop trigger will no longer run at this point, unless you specify a new spell time --------
      Else - Actions
        -------- The loop trigger will keep going, as the duration hasn't yet ended --------
    -------- --------
    -------- You can even force the duration to come to a premature end by setting Spell__Duration to 0.00, yourself. --------
    -------- --------
    Set Spell__Duration = 0.00
    -------- --------
    -------- Spell__Completed lets you know if the spell was interrupted (False) or the unit completed channeling it (True) --------
    -------- Spell__Channeling lets you know if the spell is still being channelled (True) or the caster has stopped (False). --------
    -------- NOTE: These booleans should be used only from Spell__Trigger_OnFinish or Spell__Trigger_OnLoop. --------
    -------- --------
    If (All Conditions are True) then do (Then Actions) else do (Else Actions)
      If - Conditions
        Spell__Channeling Equal to False
      Then - Actions
        -------- The unit is no longer channeling the spell --------
        If (All Conditions are True) then do (Then Actions) else do (Else Actions)
          If - Conditions
            Spell__Completed Equal to True
          Then - Actions
            -------- The spell finished normally --------
          Else - Actions
            -------- The spell was interrupted --------
      Else - Actions
        -------- The unit is still working on it --------
    -------- --------
    -------- Spell__TargetGroup is a nice one to have if you're keeping track of different units hit by this spell instance --------
    -------- NOTE: This group is unique per spell instance, but you must first Set Spell__UseTargetGroup = True from your config trigger --------
    -------- --------
    Unit Group - Add Spell__Target to Spell__TargetGroup
    -------- --------
    -------- The Spell__InRange feature picks all units in range and adds them to Spell__InRangeGroup --------
    -------- NOTE: Spell__InRangePoint must be set first, then the Spell__InRange real value. --------
    -------- Additionally, Spell__InRangeGroup does not leak and should never be destroyed. --------
    -------- --------
    -------- NEW: Added 17 May 2016, you can also set Spell__InRangeMax to limit the group to that many units --------
    -------- - Extra units are removed from the group at random --------
    -------- - Make sure to still set Spell__InRange after setting the first two. --------
    -------- --------
    Set Spell__InRangePoint = Spell__CastPoint
    Set Spell__InRangeMax = 5
    Set Spell__InRange = 300.00
    Unit Group - Add all units of Spell__InRangeGroup to Spell__TargetGroup
    -------- --------
    -------- Just to show how much time that saves, those four lines are a replacement to the following tedious stuff: --------
    -------- --------
    Custom script: set bj_wantDestroyGroup = true
    Unit Group - Pick every unit in (Units within 300.00 of Spell__CastPoint) and do (Actions)
      Loop - Actions
        -------- --------
        -------- The following conditions should have the same output as the default filter that Spell System uses. --------
        -------- However, (Unit is Alive) does not have guaranteed accuracy in GUI as a corpse's HP can be above 0. --------
        -------- Additionally, these conditions are buried within the code instead of made available in the configuration trigger. --------
        -------- --------
        If (All Conditions are True) then do (Then Actions) else do (Else Actions)
          If - Conditions
            ((Picked unit) is A structure) Equal to False
            ((Picked unit) is A ground unit) Equal to True
            ((Picked unit) is Mechanical) Equal to False
            ((Picked unit) is Magic Immune) Equal to False
            ((Picked unit) is alive) Equal to True
            ((Picked unit) belongs to an enemy of Spell__CasterOwner) Equal to True
          Then - Actions
            Unit Group - Add (Picked unit) to Spell__InRangeGroup
          Else - Actions
    Custom script: set bj_wantDestroyGroup = true
    Unit Group - Pick every unit in (Random 5 units from Spell__InRangeGroup) and do (Actions)
      Loop - Actions
        If (All Conditions are True) then do (Then Actions) else do (Else Actions)
          If - Conditions
            ((Picked unit) is sleeping) Equal to True
          Then - Actions
            -------- This is something I added to Spell System as units targeted by object editor spells are also awoken. --------
            Unit - Wake up (Picked unit)
          Else - Actions
        Unit Group - Add (Picked unit) to Spell__TargetGroup
    -------- --------
    -------- Alternatively, instead of (or in addition to) using Spell__InRangeGroup, --------
    -------- you have access to Spell__InRangeUnits and Spell__InRangeCount. --------
    -------- --------
    -------- To loop through the unit list instead of picking them, loop from 1 to (Spell__InRangeCount) --------
    -------- NOTE: I skip index 0 on purpose to make it easier to loop through it in GUI --------
    -------- --------
    For each (Integer A) from 1 to Spell__InRangeCount, do (Actions)
      Loop - Actions
        -------- --------
        Game - Display to (All players) the text: (Name of Spell__InRangeUnits[(Integer A)])
        -------- --------
    -------- --------
    -------- Having it in array format, you can easily pick a random unit, like so: --------
    -------- --------
    Unit - Kill Spell__InRangeUnits[(Random integer number between 1 and Spell__InRangeCount)]
    -------- --------
    -------- And, finally, I've made it so you have access to Spell__Hash --------
    -------- NOTE: Only save as (anything you need) of (Spell__Index) into Spell__Hash. --------
    -------- Additionally, the child hashtable of Spell__Index will be flushed when the spell is over, so you don't have to worry about that, either --------
    -------- --------
    Hashtable - Save 9000.10 as 1 of Spell__Index in Spell__Hash
    Hashtable - Save Pi as 2 of Spell__Index in Spell__Hash
    -------- --------
    -------- When the unit is finished channeling the spell and you haven't set a Spell__Time nor Spell__Duration, --------
    -------- the trigger will no longer be run. This means all the indexing and deindexing is done behind the scenes. --------
    -------- --------
Spell System Sample Filter
  Events
  Conditions
    (Spell__InRangeUnit is in Spell__TargetGroup) Equal to False
  Actions
    -------- The above condition makes it so only units who weren't already added to Spell__TargetGroup are picked --------
    -------- The unit being filtered is Spell__InRangeUnit --------
Spell System All In One Template
  Events
    Map initialization
  Conditions
  Actions
    -------- --------
    -------- Making configuration and OnEffect in one trigger for simplicity --------
    -------- This is intended for very simple spells which don't require an OnLoop trigger. --------
    -------- I don't recommend this way if you have a lot of configurables, as they are easier to track in a separate trigger --------
    -------- --------
    If (All Conditions are True) then do (Then Actions) else do (Else Actions)
      If - Conditions
        Spell__Running Equal to False
      Then - Actions
        -------- --------
        -------- If Spell__Running is true, the spell has been cast. --------
        -------- If it is false, then the original event - map initialization - for this trigger has run --------
        -------- Spell__Trigger_OnEffect will point to (This trigger) --------
        -------- --------
        Set Spell__Ability = Acid Bomb
        Set Spell__Trigger_OnEffect = (This trigger)
        Trigger - Run Spell_System <gen> (ignoring conditions)
        -------- Don't do anything else --------
        Skip remaining actions
      Else - Actions
    -------- --------
    -------- The spell has been cast normally; do what you need to do from this point on. --------
    -------- --------
Amaterasu Config
  Events
    Map initialization
  Conditions
  Actions
    -------- Amaterasu Ability --------
    Set Spell__Ability = Amaterasu
    -------- Put Amaterasu Cast here --------
    Set Spell__Trigger_OnCast = Amaterasu_Cast <gen>
    -------- Put Amaterasu End here --------
    Set Spell__Trigger_OnFinish = Amaterasu_End <gen>
    -------- Put Amaterasu Loop here --------
    Set Spell__Trigger_OnLoop = Amaterasu_Loop <gen>
    -------- With these settings, the OnLoop trigger will run every 1 second for 5 seconds --------
    Set Spell__Time = 1.00
    Set Spell__Duration = 5.00
    Set Spell__DurationPerLevel = 0.00
    -------- Amaterasu damage --------
    Set Amaterasu_Damage[1] = 100.00
    Set Amaterasu_Damage[2] = 200.00
    Set Amaterasu_Damage[3] = 300.00
    -------- Amaterasu user damage --------
    Set Amaterasu_Backlash[1] = 100.00
    Set Amaterasu_Backlash[2] = 200.00
    Set Amaterasu_Backlash[3] = 300.00
    -------- Amaterasu base radius --------
    Set Amaterasu_Base_Radius[1] = 500.00
    Set Amaterasu_Base_Radius[2] = 500.00
    Set Amaterasu_Base_Radius[3] = 500.00
    -------- Amaterasu expansion radius --------
    Set Amaterasu_Expand_Radius[1] = 0.00
    Set Amaterasu_Expand_Radius[2] = 0.00
    Set Amaterasu_Expand_Radius[3] = 0.00
    -------- Amaterasu damage increase --------
    Set Amaterasu_DamageIncPerSecond[1] = 0.00
    Set Amaterasu_DamageIncPerSecond[2] = 0.00
    Set Amaterasu_DamageIncPerSecond[3] = 0.00
    -------- Amaterasu burn SFX --------
    Set Amaterasu_BurnSFX = Abilities\Spells\Human\FlameStrike\FlameStrike1.mdl
    -------- Amaterasu backlash damage SFX and it's attachment point --------
    Set Amaterasu_PainSFX = Objects\Spawnmodels\Undead\UCancelDeath\UCancelDeath.mdl
    Set Amaterasu_PainSFXAttach = origin
    -------- Amaterasu AT/DT --------
    Set Amaterasu_AT = Spells
    Set Amaterasu_DT = Fire
    -------- Amaterasu Premature Dissipation Factor --------
    Set Amaterasu_DissipationFactor = 0.60
    Set Amaterasu_DissipationTime = 3.00
    -------- END MAIN CONFIGURATION --------
    -------- Below are advanced settings, relying on knowledge of Spell System --------
    -------- --------
    -------- The next ones are for the InRange filter, if you use it. You don't have to include any of these for many typical spells. --------
    -------- TIPS: --------
    -------- > For healing spells, you'll want to set AllowAllies to True and AllowEnemies to False. --------
    -------- > If you are creating a "kill unit" spell, you'll want to set AllowHero to False. --------
    -------- > If you are making a custom "Resurrect", you'll want to set AllowDead to True and AllowLiving to False. --------
    -------- > AllowMagicImmune as False also prevents invulnerable units from being picked, which is a plus in my opinion. --------
    -------- --------
    Set Spell__Filter_AllowEnemy = True
    Set Spell__Filter_AllowLiving = True
    Set Spell__Filter_AllowHero = True
    Set Spell__Filter_AllowNonHero = True
    Set Spell__Filter_AllowAlly = True
    Set Spell__Filter_AllowDead = False
    Set Spell__Filter_AllowFlying = False
    Set Spell__Filter_AllowMechanical = False
    Set Spell__Filter_AllowStructure = False
    Set Spell__Filter_AllowMagicImmune = False
    -------- --------
    -------- When everything is set the way you want it, run Spell System <gen>: --------
    -------- --------
    Trigger - Run Spell_System <gen> (ignoring conditions)
Amaterasu Cast
  Events
  Conditions
  Actions
    Set Spell__StartDuration = True
    Set Amaterasu_FinalDamage[Spell__Index] = Amaterasu_Damage[Spell__Level]
    Unit - Create 1 Spell__DummyType for Spell__DummyOwner at Spell__TargetPoint facing Default building facing degrees
    Set Amaterasu_Radius[Spell__Index] = Amaterasu_Base_Radius[Spell__Level]
    Set Amaterasu_Dummy[Spell__Index] = (Last created unit)
    Special Effect - Create a special effect attached to the origin of Amaterasu_Dummy[Spell__Index] using Amaterasu_BurnSFX
    Animation - Change Amaterasu_Dummy[Spell__Index]'s size to (Amaterasu_Radius[Spell__Index]%, Amaterasu_Radius[Spell__Index]%, Amaterasu_Radius[Spell__Index]%) of its original size
    Set Amaterasu_SFX_Form[Spell__Index] = (Last created special effect)
    Set Amaterasu_Dissipation[Spell__Index] = False
Amaterasu Loop
  Events
  Conditions
  Actions
    If (All Conditions are True) then do (Then Actions) else do (Else Actions)
      If - Conditions
        Spell_i_Channeling[Spell__Index] Equal to True
      Then - Actions
        Set Spell__InRangePoint = Spell__TargetPoint
        Set Spell__InRange = Amaterasu_Radius[Spell__Index]
        Set Amaterasu_FinalDamage[Spell__Index] = (Amaterasu_FinalDamage[Spell__Index] + Amaterasu_DamageIncPerSecond[Spell_i_Level[Spell__Index]])
        Unit Group - Pick every unit in Spell__InRangeGroup and do (Actions)
          Loop - Actions
            Set Amaterasu_Target = (Picked unit)
            Unit - Cause Spell_i_Caster[Spell__Index] to damage Amaterasu_Target, dealing Amaterasu_FinalDamage[Spell__Index] damage of attack type Amaterasu_AT and damage type Amaterasu_DT
        Set Amaterasu_Radius[Spell__Index] = (Amaterasu_Radius[Spell__Index] + Amaterasu_Expand_Radius[Spell_i_Level[Spell__Index]])
        Animation - Change Amaterasu_Dummy[Spell__Index]'s size to (Amaterasu_Radius[Spell__Index]%, Amaterasu_Radius[Spell__Index]%, Amaterasu_Radius[Spell__Index]%) of its original size
      Else - Actions
        If (All Conditions are True) then do (Then Actions) else do (Else Actions)
          If - Conditions
            Spell_i_Duration[Spell__Index] Less than or equal to 0.00
          Then - Actions
            Special Effect - Destroy Amaterasu_SFX_Form[Spell__Index]
            Unit - Remove Amaterasu_Dummy[Spell__Index] from the game
          Else - Actions
            If (All Conditions are True) then do (Then Actions) else do (Else Actions)
              If - Conditions
                Amaterasu_Dissipation[Spell__Index] Equal to False
              Then - Actions
                Set Amaterasu_Dissipation[Spell__Index] = True
                Set Spell__Duration = Amaterasu_DissipationTime
              Else - Actions
            Set Amaterasu_Radius[Spell__Index] = (Amaterasu_Radius[Spell__Index] x Amaterasu_DissipationFactor)
            Animation - Change Amaterasu_Dummy[Spell__Index]'s size to (Amaterasu_Radius[Spell__Index]%, Amaterasu_Radius[Spell__Index]%, Amaterasu_Radius[Spell__Index]%) of its original size
Amaterasu End
  Events
  Conditions
  Actions
    Set Amaterasu_Target = Spell_i_Caster[Spell__Index]
    Set Amaterasu_FinalDamage[Spell__Index] = 0.00
    Unit - Cause Spell_i_Caster[Spell__Index] to damage Amaterasu_Target, dealing Amaterasu_Backlash[Spell_i_Level[Spell__Index]] damage of attack type Amaterasu_AT and damage type Amaterasu_DT
    Special Effect - Create a special effect attached to the Amaterasu_PainSFXAttach of Spell_i_Caster[Spell__Index] using Amaterasu_PainSFX
    Special Effect - Destroy (Last created special effect)