• 🏆 Texturing Contest #33 is OPEN! Contestants must re-texture a SD unit model found in-game (Warcraft 3 Classic), recreating the unit into a peaceful NPC version. 🔗Click here to enter!
  • 🏆 Hive's 6th HD Modeling Contest: Mechanical is now open! Design and model a mechanical creature, mechanized animal, a futuristic robotic being, or anything else your imagination can tinker with! 📅 Submissions close on June 30, 2024. Don't miss this opportunity to let your creativity shine! Enter now and show us your mechanical masterpiece! 🔗 Click here to enter!

Spell System

GUI Spell System
version 1.0.0.0

A powerful spell system for GUI users to automate most of the mundane tasks of creating spells.

Features:
  • Automatic event handling of spells. The system runs your triggers for you once you have configured your spell with a few variables.
  • Automatic variable setting: retrieves the cast ability, the ability level, caster, target, caster position and target position for you.
  • You no longer remove the casting position/target position as the system uses static locations and coordinates instead of dynamic locations. If you create any additional locations, you'll still need to remove them.
  • Automatically indexes those key variables for you into arrays to make indexing less tedious and distracting.
  • Automatically runs each spell instance periodically if you specify an OnLoop trigger when you configure the spell.

Inspiration:

  • SpellEvent by Anitarf - One set of events for all spells, as opposed to 16 events per spell. It is exponentially faster than normal events. Automatic assignment of event variables and was the inspiration for me to write SpellEffectEvent as a much more generic tool.
  • vJass structs by Vexorian - Create a unique integer variable which will act as an array index. Has OnDestroy functionality which is run automatically and is double-free safe.
  • Timer32 by Jesus4Lyf - One timer for all periodic events; handles iteration of instances for you behind-the-scenes.
  • Constant Timer Loop 32 by Nestharus - A combination of Timer32 and vJass struct creation/destruction which pauses timers/removes system triggers when completed.


  • Big Dipper Config
    • Events
      • Map initialization
    • Conditions
    • Actions
      • -------- Configuration for spell The Big Dipper --------
      • -------- --------
      • Set Spell__Ability = The Big Dipper
      • -------- --------
      • Set Dipper_DummyModel = Abilities\Weapons\FaerieDragonMissile\FaerieDragonMissile.mdl
      • -------- --------
      • Set Dipper_FinisherFX = Abilities\Spells\Human\Thunderclap\ThunderClapCaster.mdl
      • -------- --------
      • Set Dipper_StarCount = 7
      • -------- At these values, the radius per level breakdown is 350, 400, 450 --------
      • Set Dipper_RadiusBase = 300.00
      • Set Dipper_RadiusPerLvl = 50.00
      • -------- At these values, the damage per level breakdown is 150, 200, 250 --------
      • Set Dipper_DamageBase = 100.00
      • Set Dipper_DamagePerLvl = 50.00
      • -------- --------
      • Set Dipper_AttackType = Spells
      • Set Dipper_DamageType = Normal
      • -------- --------
      • -------- This is a 5-phase spell. Assign the duration of each phase here. --------
      • -------- - Phase 1: knock dummy units from center of target point --------
      • -------- - Phase 2: have them bounce into the air --------
      • -------- - Phase 3: have them come back down --------
      • -------- - Phase 4: send nearby enemies and all dummies to the caster's position --------
      • -------- - Phase 5: knock all enemies away from the caster's position --------
      • -------- There is also a time to wait posted in between each phase before moving onto the next phase. --------
      • -------- --------
      • Set Dipper_PhaseDur[0] = 0.90
      • Set Dipper_PhaseWait[0] = 0.20
      • Set Dipper_PhaseDur[1] = 0.50
      • Set Dipper_PhaseWait[1] = 0.10
      • Set Dipper_PhaseDur[2] = 0.20
      • Set Dipper_PhaseWait[2] = 0.00
      • Set Dipper_PhaseDur[3] = 0.90
      • Set Dipper_PhaseWait[3] = 0.00
      • Set Dipper_PhaseDur[4] = 0.70
      • -------- --------
      • -------- Preload special effects --------
      • -------- --------
      • Game - Preload Dipper_DummyModel
      • Game - Preload Dipper_FinisherFX
      • -------- --------
      • -------- These will instruct the system to create dummy and target unit groups for each spell instance --------
      • -------- --------
      • Set Spell__UseDummyGroup = True
      • Set Spell__UseTargetGroup = True
      • -------- --------
      • -------- Specify an OnCast and OnLoop trigger which will be run automatically by the system --------
      • -------- --------
      • Set Spell__Trigger_OnCast = Big Dipper Cast <gen>
      • Set Spell__Trigger_OnLoop = Big Dipper Loop <gen>
      • -------- --------
      • -------- Now that everything is configured the way I want with GUI Spell System, run Spell System Registry <gen> --------
      • Trigger - Run Spell System Registry <gen> (ignoring conditions)
  • Big Dipper Cast
    • Events
    • Conditions
    • Actions
      • -------- These Spell__ variables are already set by GUI Spell System --------
      • -------- --------
      • Set Dipper_Angle = (Angle from Spell__CastPoint to Spell__TargetPoint)
      • Set Dipper_AngleDelta = (360.00 / (Real(Dipper_StarCount)))
      • Set Dipper_Radius = (Dipper_RadiusBase + (Dipper_RadiusPerLvl x (Real(Spell__Level))))
      • -------- --------
      • -------- This instructs the system to run the OnLoop trigger after Spell__Time seconds --------
      • -------- --------
      • Set Spell__Time = (Dipper_PhaseDur[0] + Dipper_PhaseWait[0])
      • -------- --------
      • Set Dipper_Phase = 0
      • Set Dipper_Phases[Spell__Index] = 0
      • -------- --------
      • -------- Create 1 star per angle and "knock" them back at StarCount angles --------
      • For each (Integer LoopInt) from 1 to Dipper_StarCount, do (Actions)
        • Loop - Actions
          • Unit - Create 1 Spell__DummyType for Spell__CasterOwner at Spell__TargetPoint facing Dipper_Angle degrees
          • -------- --------
          • -------- Set knockback variables --------
          • -------- --------
          • Set Knockback2DUnit = (Last created unit)
          • Set Knockback2DAngle = Dipper_Angle
          • Set Knockback2DDistance = Dipper_Radius
          • Set Knockback2DHeight = 200.00
          • Set Knockback2DGravity = 0.67
          • -------- --------
          • -------- Handle remaining features --------
          • -------- --------
          • Unit Group - Add Knockback2DUnit to Spell__DummyGroup
          • Unit - Pause Knockback2DUnit
          • Special Effect - Create a special effect attached to the origin of Knockback2DUnit using Dipper_DummyModel
          • Set Dipper_StarFX[(Custom value of Knockback2DUnit)] = (Last created special effect)
          • -------- --------
          • -------- Setup the dummy to be "knocked back" --------
          • -------- --------
          • Trigger - Run Big Dipper Movement <gen> (ignoring conditions)
          • -------- --------
          • -------- Increase the angle for the next loop iteration --------
          • Set Dipper_Angle = ((Dipper_Angle + Dipper_AngleDelta) mod 360.00)
  • Big Dipper Loop
    • Events
    • Conditions
    • Actions
      • Set Dipper_Phase = (Dipper_Phases[Spell__Index] + 1)
      • Set Dipper_Phases[Spell__Index] = Dipper_Phase
      • Set Spell__Time = (Dipper_PhaseDur[Dipper_Phase] + Dipper_PhaseWait[Dipper_Phase])
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • Dipper_Phase Equal to 1
        • Then - Actions
          • -------- Lift the stars into the air --------
          • Unit Group - Pick every unit in Spell__DummyGroup and do (Actions)
            • Loop - Actions
              • Animation - Change (Picked unit) flying height to 140.00 at (140.00 / Dipper_PhaseDur[1])
        • Else - Actions
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • Dipper_Phase Equal to 2
            • Then - Actions
              • -------- Have the stars land back on the ground --------
              • Unit Group - Pick every unit in Spell__DummyGroup and do (Actions)
                • Loop - Actions
                  • Animation - Change (Picked unit) flying height to 0.00 at (140.00 / Dipper_PhaseDur[2])
            • Else - Actions
              • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                • If - Conditions
                  • Dipper_Phase Equal to 3
                • Then - Actions
                  • -------- Pick all enemies in the area and knock them back to the caster --------
                  • Custom script: set bj_wantDestroyGroup = true
                  • Unit Group - Pick every unit in (Units within (Dipper_RadiusBase + (Dipper_RadiusPerLvl x (Real(Spell__Level)))) of Spell__TargetPoint) and do (Actions)
                    • Loop - Actions
                      • Set Knockback2DUnit = (Picked unit)
                      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                        • If - Conditions
                          • (Knockback2DUnit belongs to an enemy of Spell__CasterOwner) Equal to True
                          • (Life of Knockback2DUnit) Greater than (0.81 / 2.00)
                          • (Knockback2DUnit is Magic Immune) Equal to False
                        • Then - Actions
                          • Unit Group - Add Knockback2DUnit to Spell__TargetGroup
                          • Set TempPoint = (Position of Knockback2DUnit)
                          • Set Knockback2DAngle = (Angle from TempPoint to Spell__CastPoint)
                          • Set Knockback2DDistance = (Distance between TempPoint and Spell__CastPoint)
                          • Custom script: call RemoveLocation(udg_TempPoint)
                          • Set Knockback2DTime = Dipper_PhaseDur[3]
                          • Set Knockback2DCollision = -1.00
                          • Set Knockback2DPause = True
                          • Set Knockback2DSimple = True
                          • Set Knockback2DLoopFX = Dipper_DummyModel
                          • Set Knockback2DFXRate = 0.25
                          • -------- --------
                          • -------- Run the knockback trigger --------
                          • Trigger - Run Knockback 2D <gen> (ignoring conditions)
                        • Else - Actions
                  • -------- Have all dummies return to the caster --------
                  • Unit Group - Pick every unit in Spell__DummyGroup and do (Actions)
                    • Loop - Actions
                      • Set Knockback2DUnit = (Picked unit)
                      • Set TempPoint = (Position of Knockback2DUnit)
                      • Set Knockback2DAngle = (Angle from TempPoint to Spell__CastPoint)
                      • Set Knockback2DDistance = (Distance between TempPoint and Spell__CastPoint)
                      • Custom script: call RemoveLocation(udg_TempPoint)
                      • Trigger - Run Big Dipper Movement <gen> (ignoring conditions)
                • Else - Actions
                  • Special Effect - Create a special effect at Spell__CastPoint using Dipper_FinisherFX
                  • Special Effect - Destroy (Last created special effect)
                  • Set Dipper_Radius = (Dipper_RadiusBase + (Dipper_RadiusPerLvl x (Real(Spell__Level))))
                  • Unit Group - Pick every unit in Spell__TargetGroup and do (Actions)
                    • Loop - Actions
                      • Set Knockback2DUnit = (Picked unit)
                      • Set Knockback2DAngle = (Random angle)
                      • Set Knockback2DDistance = Dipper_Radius
                      • Set Knockback2DTime = Dipper_PhaseDur[4]
                      • Set Knockback2DLoopFX = Dipper_DummyModel
                      • Set Knockback2DCollision = -1.00
                      • Set Knockback2DPause = True
                      • Set Knockback2DFXRate = 0.25
                      • -------- --------
                      • -------- Run the knockback trigger --------
                      • -------- --------
                      • Trigger - Run Knockback 2D <gen> (ignoring conditions)
                      • -------- --------
                      • -------- Damage the unit only after the knockback in order to avoid their movement getting displaced --------
                      • Unit - Cause Spell__Caster to damage Knockback2DUnit, dealing (Dipper_DamageBase + (Dipper_DamagePerLvl x (Real(Spell__Level)))) damage of attack type Dipper_AttackType and damage type Dipper_DamageType
                  • Unit Group - Pick every unit in Spell__DummyGroup and do (Actions)
                    • Loop - Actions
                      • Special Effect - Destroy Dipper_StarFX[(Custom value of (Picked unit))]
                      • Unit - Remove (Picked unit) from the game
                  • -------- --------
                  • -------- The spell is finished! Destroy the spell index so the system can be prepared for more spells --------
                  • -------- --------
                  • Trigger - Run Spell Index Destroy <gen> (ignoring conditions)
  • Big Dipper Movement
    • Events
    • Conditions
    • Actions
      • -------- One common set settings trigger for handling dummy movement. --------
      • Set Knockback2DCollision = -1.00
      • Set Knockback2DFriction = 0.00
      • Set Knockback2DTime = Dipper_PhaseDur[Dipper_Phase]
      • Set Knockback2DPause = True
      • Set Knockback2DSimple = True
      • Set Knockback2DLoopFX = <Empty String>
      • -------- --------
      • -------- Run the knockback trigger --------
      • Trigger - Run Knockback 2D <gen> (ignoring conditions)



  • 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 Passive
      • Set Spell__Interval = (1.00 / 32.00)
      • -------- --------
      • -------- Do not change the following integers which represent different events by this system. --------
      • -------- If you don't use these, your spell event defaults to "starts the effect of an ability" --------
      • -------- If you want to use a different one, set Spell_e_Event to whichever of these you need before running Spell System Register <gen>. --------
      • -------- --------
      • Set Spell_e_BeginsChannel = 272
      • Set Spell_e_BeginsCast = 273
      • Set Spell_e_StartsEffect = 274
      • Set Spell_e_FinishesCast = 275
      • Set Spell_e_StopsCast = 276
      • -------- --------
      • -------- Do not enable the following lines as they are variable declarations which make copying this system easier --------
      • -------- --------
      • Set Spell_i_Level[(Player number of Spell_i_Player[0])] = (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_DummyGroup[(Number of units in Spell_i_TargetGroup[(Number of units in Spell__DummyGroup)])] to Spell__TargetGroup
JASS:
//Called automatically before running OnLoop triggers. Can be called manually
//by the user if needed at a different time.
function SpellIndexGetVars takes nothing returns nothing
    set udg_Spell__Caster = udg_Spell_i_Caster[udg_Spell__Index]
    set udg_Spell__CasterOwner = udg_Spell_i_Player[udg_Spell__Index]
    set udg_Spell__Level = udg_Spell_i_Level[udg_Spell__Index]
    set udg_Spell__Target = udg_Spell_i_Target[udg_Spell__Index]
    
    //Assign the saved coordinates to the static locations
    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[udg_Spell__Index], udg_Spell_i_TargetY[udg_Spell__Index])
    else
        call MoveLocation(udg_Spell__TargetPoint, GetUnitX(udg_Spell__Target), GetUnitY(udg_Spell__Target))
    endif
    set udg_Spell__DummyGroup = udg_Spell_i_DummyGroup[udg_Spell__Index]
    set udg_Spell__TargetGroup = udg_Spell_i_TargetGroup[udg_Spell__Index]
endfunction

//Purges unit group array slots
function SpellSystemDestroyGroups takes integer i returns nothing
    if udg_Spell_i_DummyGroup[i] != null then
        call DestroyGroup(udg_Spell_i_DummyGroup[i])
        set udg_Spell_i_DummyGroup[i] = null
    endif
    if udg_Spell_i_TargetGroup[i] != null then
        call DestroyGroup(udg_Spell_i_TargetGroup[i])
        set udg_Spell_i_TargetGroup[i] = null
    endif
endfunction

//Runs every Spell__Interval seconds.
function SpellTimerLoop takes nothing returns nothing
    local integer i = udg_Spell_i_TimerN
    local integer node
    
    //Run stack top to bottom to avoid skipping slots when destroying.
    loop
        set i = i - 1
        exitwhen i < 0
        set udg_Spell_i_Index_Head = udg_Spell_i_TimerHeadStack[i]
        set node = udg_Spell_i_Index_Head
        
        //This inner loop is a linked list.
        loop
            set node = udg_Spell_i_Index_Next[node]
            exitwhen node == udg_Spell_i_Index_Head
            
            //Set Spell__Index so the user can access it.
            set udg_Spell__Index = node
            
            set udg_Spell_i_Time[node] = udg_Spell_i_Time[node] - udg_Spell__Interval
            if udg_Spell_i_Time[node] <= 0.00 then
            
                call SpellIndexGetVars()
                
                //Run the user's trigger.
                call TriggerExecute(udg_Spell_i_OnLoopStack[udg_Spell_i_Index_Head])
                
                //In case the user set these variables from the callback trigger,
                //store them into the array
                set udg_Spell_i_Time[node] = udg_Spell__Time
                set udg_Spell__Time = 0.00
            endif
        endloop
    endloop
endfunction

//This function is called automatically before running the OnCast trigger if
//you specified an OnLoop trigger. Otherwise, it could be called manually if
//you need to keep track of your indexing in a different way. I don't call it
//automatically in case the user doesn't need indexing and just wants a simple
//spell event.
function CreateSpellIndex takes nothing returns nothing
    if udg_Spell_i_Index_LastRecycled == 0 then
        //Create a new, unique index
        set udg_Spell_i_Index_Gen = udg_Spell_i_Index_Gen + 1
        set udg_Spell__Index = udg_Spell_i_Index_Gen
    else
        //Use a recycled one
        set udg_Spell__Index = udg_Spell_i_Index_LastRecycled
        set udg_Spell_i_Index_LastRecycled = udg_Spell_i_Index_RecycleList[udg_Spell_i_Index_LastRecycled]
    endif
    set udg_Spell_i_Caster[udg_Spell__Index] = udg_Spell__Caster
    set udg_Spell_i_Player[udg_Spell__Index] = udg_Spell__CasterOwner
    set udg_Spell_i_Level[udg_Spell__Index] = udg_Spell__Level
    set udg_Spell_i_Target[udg_Spell__Index] = udg_Spell__Target
    
    //Only store coordinates so as to never need to create or remove those locations
    set udg_Spell_i_TargetX[udg_Spell__Index] = GetLocationX(udg_Spell__TargetPoint)
    set udg_Spell_i_TargetY[udg_Spell__Index] = GetLocationY(udg_Spell__TargetPoint)
    
    if udg_Spell_i_UseDG[udg_Spell_i_Index_Head] then
        set udg_Spell__DummyGroup = CreateGroup()
        set udg_Spell_i_DummyGroup[udg_Spell__Index] = udg_Spell__DummyGroup
    endif
    if udg_Spell_i_UseTG[udg_Spell_i_Index_Head] then
        set udg_Spell__TargetGroup = CreateGroup()
        set udg_Spell_i_TargetGroup[udg_Spell__Index] = udg_Spell__TargetGroup
    endif
    
    // Index the head node of this ability ID
    set udg_Spell_i_Index_Ref[udg_Spell__Index] = udg_Spell_i_Index_Head
    
    if udg_Spell_i_OnLoopStack[udg_Spell_i_Index_Head] != null then
        if udg_Spell_i_Index_Next[udg_Spell_i_Index_Head] == udg_Spell_i_Index_Head then
        
            // If the list is empty, allocate the loop trigger.
            set udg_Spell_i_TimerHeadStack[udg_Spell_i_TimerN] = udg_Spell_i_Index_Head
            set udg_Spell_i_TimerHeadRef[udg_Spell_i_Index_Head] = udg_Spell_i_TimerN
            set udg_Spell_i_TimerN = udg_Spell_i_TimerN + 1
            if udg_Spell_i_TimerN == 1 then
                // If this is the only OnLoop trigger activated, start the OnLoop system timer
                call TimerStart(udg_Spell_i_Timer, udg_Spell__Interval, true, function SpellTimerLoop)
            endif
        endif
        
        // Add the new index to the linked list of the head node
        set udg_Spell_i_Index_Prev[udg_Spell__Index] = udg_Spell_i_Index_Prev[udg_Spell_i_Index_Head]
        set udg_Spell_i_Index_Next[udg_Spell_i_Index_Prev[udg_Spell_i_Index_Head]] = udg_Spell__Index
        set udg_Spell_i_Index_Prev[udg_Spell_i_Index_Head] = udg_Spell__Index
        set udg_Spell_i_Index_Next[udg_Spell__Index] = udg_Spell_i_Index_Head
    endif
    
    // Set the following variable to -1 to let the system know this index is safe to recycle later on
    set udg_Spell_i_Index_RecycleList[udg_Spell__Index] = -1
endfunction

function SpellSystemEvent takes nothing returns boolean
    set udg_Spell__Ability = GetSpellAbilityId()
    set udg_Spell_i_Index_Head = LoadInteger(udg_Spell_i_Hash, GetHandleId(GetTriggerEventId()), udg_Spell__Ability)
    if udg_Spell_i_Index_Head > 0 then

        //Recover event response values
        set udg_Spell__Caster = GetTriggerUnit()
        set udg_Spell__CasterOwner = GetTriggerPlayer()
        set udg_Spell__Level = GetUnitAbilityLevel(udg_Spell__Caster, udg_Spell__Ability)
        call MoveLocation(udg_Spell__CastPoint, GetUnitX(udg_Spell__Caster), GetUnitY(udg_Spell__Caster))
        
        set udg_Spell__Target = GetSpellTargetUnit()
        if udg_Spell__Target != null then
            call MoveLocation(udg_Spell__TargetPoint, GetUnitX(udg_Spell__Target), GetUnitY(udg_Spell__Target))
        else
            call MoveLocation(udg_Spell__TargetPoint, GetSpellTargetX(), GetSpellTargetY())
        endif
        
        if udg_Spell_i_OnLoopStack[udg_Spell_i_Index_Head] != null then
            call CreateSpellIndex()
        endif
        
        //Run the user's OnCast trigger.
        call TriggerExecute(udg_Spell_i_OnCastStack[udg_Spell_i_Index_Head])
        
        //If you use indexing and a Spell__Time was specified, remember that time.
        if udg_Spell__Time > 0.00 then
            set udg_Spell_i_Time[udg_Spell__Index] = udg_Spell__Time
            set udg_Spell__Time = 0.00
        endif
    endif
    return false
endfunction

//===========================================================================
function InitTrig_Spell_System takes nothing returns nothing
    local integer i = 0
    
    //This runs before map init events so the hashtable is ready before then.
    set udg_Spell_i_Hash = InitHashtable()
    
    //Default event: EVENT_PLAYER_UNIT_SPELL_EFFECT
    set udg_Spell_e_Event = 274
    
    //Initialize these two locations which will never get removed
    set udg_Spell__CastPoint = Location(0, 0)
    set udg_Spell__TargetPoint = Location(0, 0)
    
    //Destroy all system unit groups as they will be overwritten.
    call DestroyGroup(udg_Spell__DummyGroup)
    call DestroyGroup(udg_Spell__TargetGroup)
    set udg_Spell__DummyGroup = null
    set udg_Spell__TargetGroup = null
    call SpellSystemDestroyGroups(0)
    call SpellSystemDestroyGroups(1)
    
    //Create a dummy unit for preloading abilities.
    set udg_Spell_i_PreloadDummy = CreateUnit(udg_Spell__DummyOwner, udg_Spell__DummyType, 0, 0, 0)
    call UnitApplyTimedLife(udg_Spell_i_PreloadDummy, 'BTLF', 0.01)
    
    //I am using this global trigger to give users the ability to disable or
    //enable all spell events at once if they desire it.
    set gg_trg_Spell_System = CreateTrigger()
    call TriggerRegisterAnyUnitEventBJ(gg_trg_Spell_System, EVENT_PLAYER_UNIT_SPELL_CHANNEL)
    call TriggerRegisterAnyUnitEventBJ(gg_trg_Spell_System, EVENT_PLAYER_UNIT_SPELL_CAST)
    call TriggerRegisterAnyUnitEventBJ(gg_trg_Spell_System, EVENT_PLAYER_UNIT_SPELL_EFFECT)
    call TriggerRegisterAnyUnitEventBJ(gg_trg_Spell_System, EVENT_PLAYER_UNIT_SPELL_ENDCAST)
    call TriggerRegisterAnyUnitEventBJ(gg_trg_Spell_System, EVENT_PLAYER_UNIT_SPELL_FINISH)
    call TriggerAddCondition(gg_trg_Spell_System, Filter(function SpellSystemEvent))
    
    //Run the configuration trigger so its variables are ready before the
    //map initialization events run.
    call TriggerExecute(gg_trg_Spell_System_Config)
endfunction

  • Spell System Registry
    • Events
    • Conditions
    • Actions
      • -------- --------
      • -------- Set Spell__Ability to your spell's ability --------
      • -------- Set Spell__Trigger_OnCast to the trigger you want to run when that ability is used --------
      • -------- When those variables are set, run this trigger: Spell System Registry <gen> (Ignoring Conditions) --------
      • -------- --------
      • Set Spell_i_Index_Gen = (Spell_i_Index_Gen + 1)
      • Set Spell_i_Index_Head = Spell_i_Index_Gen
      • -------- --------
      • Set Spell_i_OnCastStack[Spell_i_Index_Head] = Spell__Trigger_OnCast
      • -------- --------
      • -------- Save the spell ability in a hashtable so the trigger can be referenced when it is cast. --------
      • -------- --------
      • Custom script: set udg_Spell_i_AbilAsInt = udg_Spell__Ability
      • Hashtable - Save Spell_i_Index_Head as Spell_i_AbilAsInt of Spell_e_Event in Spell_i_Hash
      • Set Spell_e_Event = Spell_e_StartsEffect
      • -------- --------
      • -------- Optional variables: you can assign an OnDestroy trigger and an OnLoop trigger which are called automatically. --------
      • -------- Spell__Trigger_OnDestroy, Spell__Trigger_OnLoop --------
      • -------- --------
      • Set Spell_i_OnDestroyStack[Spell_i_Index_Head] = Spell__Trigger_OnDestroy
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • Spell__Trigger_OnLoop Not equal to Spell_i_OnLoopStack[0]
        • Then - Actions
          • -------- If a loop trigger is specified, create a linked list to keep track of all instances of the spell --------
          • Set Spell_i_Index_Next[Spell_i_Index_Head] = Spell_i_Index_Head
          • Set Spell_i_Index_Prev[Spell_i_Index_Head] = Spell_i_Index_Head
          • -------- --------
          • Set Spell_i_OnLoopStack[Spell_i_Index_Head] = Spell__Trigger_OnLoop
          • Set Spell__Trigger_OnLoop = Spell_i_OnLoopStack[0]
        • Else - Actions
      • -------- --------
      • -------- Tell the system to automatically create dummy groups, if needed --------
      • -------- --------
      • Set Spell_i_UseDG[Spell_i_Index_Head] = Spell__UseDummyGroup
      • Set Spell_i_UseTG[Spell_i_Index_Head] = Spell__UseTargetGroup
      • Set Spell__UseDummyGroup = False
      • Set Spell__UseTargetGroup = False
      • -------- --------
      • -------- Preload the ability on dummy unit to help prevent first-instance lag --------
      • Unit - Add Spell__Ability to Spell_i_PreloadDummy
  • Spell Index Destroy
    • Events
    • Conditions
    • Actions
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • Spell_i_Index_RecycleList[Spell__Index] Equal to -1
        • Then - Actions
          • Set Spell_i_Index_RecycleList[Spell__Index] = Spell_i_Index_LastRecycled
          • Set Spell_i_Index_LastRecycled = Spell__Index
          • -------- --------
          • Set Spell_i_Index_Head = Spell_i_Index_Ref[Spell__Index]
          • -------- --------
          • -------- Destroy any associated unit groups --------
          • -------- --------
          • Custom script: call SpellSystemDestroyGroups(udg_Spell__Index)
          • -------- --------
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • Spell_i_OnLoopStack[Spell_i_Index_Head] Not equal to Spell_i_OnLoopStack[0]
            • Then - Actions
              • -------- Unlink the index from the list --------
              • Set Spell_i_Index_Next[Spell_i_Index_Prev[Spell__Index]] = Spell_i_Index_Next[Spell__Index]
              • Set Spell_i_Index_Prev[Spell_i_Index_Next[Spell__Index]] = Spell_i_Index_Prev[Spell__Index]
              • -------- --------
              • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                • If - Conditions
                  • Spell_i_Index_Next[Spell_i_Index_Head] Equal to Spell_i_Index_Head
                • Then - Actions
                  • -------- If the list is empty, deallocate the loop trigger. --------
                  • Set Spell_i_TimerN = (Spell_i_TimerN - 1)
                  • Set Spell_i_Index_Node = Spell_i_TimerHeadRef[Spell_i_Index_Head]
                  • Set Spell_i_TimerHeadRef[Spell_i_TimerHeadStack[Spell_i_TimerN]] = Spell_i_Index_Node
                  • Set Spell_i_TimerHeadStack[Spell_i_Index_Node] = Spell_i_TimerHeadStack[Spell_i_TimerN]
                  • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                    • If - Conditions
                      • Spell_i_TimerN Equal to 0
                    • Then - Actions
                      • -------- If no more spells require the spell timer, pause it. --------
                      • Countdown Timer - Pause Spell_i_Timer
                    • Else - Actions
                • Else - Actions
            • Else - Actions
          • -------- Run the on-destroy behavior of the spell, if the user requested it --------
          • Trigger - Run Spell_i_OnDestroyStack[Spell_i_Index_Head] (ignoring conditions)
        • Else - Actions

Attachments

  • GUI Spell System.w3x
    57.6 KB · Views: 9
  • GUI Spell System.png
    GUI Spell System.png
    180.4 KB · Views: 10
Last edited:
Top