//TESH.scrollpos=0
//TESH.alwaysfold=0
Name | Type | is_array | initial_value |
Map_FacingAngle | real | Yes | |
Map_LoopInt | integer | No | |
Map_MaxInt | integer | No | |
Map_Owner | player | Yes | |
Map_Player | player | No | |
Map_SpawnLoc | location | Yes | |
Map_TempGroup | group | No | |
Map_TempLoc | location | No | |
Map_Unit | unit | No | |
Map_UnitHP | real | Yes | |
Map_UnitID | integer | No | |
Map_UnitType | unitcode | Yes | |
Spell__Ability | abilcode | 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__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__InRangePoint | location | No | |
Spell__InRangeUnits | unit | Yes | |
Spell__Interval | real | No | |
Spell__Level | integer | No | |
Spell__LevelMultiplier | real | No | |
Spell__Running | boolean | No | |
Spell__Target | unit | No | |
Spell__TargetGroup | group | No | |
Spell__TargetPoint | location | No | |
Spell__Time | real | 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_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_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_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 | |
VL_Ability | abilcode | No | |
VL_AbilityCurse | abilcode | No | |
VL_AbilityHeal | abilcode | No | |
VL_AbilityLvl | integer | Yes | |
VL_AoE | real | Yes | |
VL_Buff | buffcode | No | |
VL_C_Amount | integer | No | |
VL_C_Even | real | No | |
VL_C_GrowRate | real | Yes | |
VL_C_GrowTime | real | No | |
VL_C_MoveRate | real | Yes | |
VL_C_SFX | string | No | |
VL_C_Speed | real | No | |
VL_Caster | unit | Yes | |
VL_CounterDuration | real | Yes | |
VL_CurrentAoE | real | Yes | |
VL_Debuff | buffcode | No | |
VL_Degree | real | No | |
VL_Dummy | unitcode | No | |
VL_DummyCaster | unit | No | |
VL_Duration | real | Yes | |
VL_GroupEnemy | group | Yes | |
VL_L | lightning | Yes | |
VL_L_Amount | integer | No | |
VL_L_CheckSFX | boolean | Yes | |
VL_L_Counter | real | Yes | |
VL_L_CreateLoop | integer | No | |
VL_L_Direction | real | No | |
VL_L_Distance | real | No | |
VL_L_Duration | real | No | |
VL_L_Height | real | No | |
VL_L_ID | integer | No | |
VL_L_SFX | lightningtype | No | |
VL_L_SFX_EndPoint | string | No | |
VL_LoopInt | integer | No | |
VL_MaxIndex | integer | No | |
VL_MaxLevel | integer | No | |
VL_NodeNext | integer | Yes | |
VL_NodePrev | integer | Yes | |
VL_Owner | player | Yes | |
VL_PeriodicTimer | real | No | |
VL_RecycledSize | integer | No | |
VL_RecycledStack | integer | Yes | |
VL_SFX | string | No | |
VL_Spell_ID | integer | No | |
VL_SpellCount | integer | No | |
VL_TargetLoc | location | Yes | |
VL_TempInt | integer | No | |
VL_TempLoc | location | No | |
VL_TempReal | real | No | |
VL_TempUnit | unit | No |
//TESH.scrollpos=0
//TESH.alwaysfold=0
/*
Volatile Light
v2.01
By KILLCIDE
Making this spell gave me so many problems ._. this spell went through A LOT (an understatement) of changes
Requirements:
--------
- dummy.mdx
Credits:
-------
- Vexorian for dummy.mdx
How to Install:
--------------
1. Under Preferences, make sure you have "Automatically create unknown variables while pasting trigger data" checked
2. Import dummy.mdx, then copy and paste the dummy unit, three abilities, and two buffs into your map
NOTE: If you already have dummy.mdx imported into your map, you DO NOT have to reimport it
If you already have a global dummy unit in your map, you can skip this step
3. Copy and paste the Volatile Light folder into your map
4. Go to the VL Config trigger, and change the Ability, Dummy, AbilityCurse, AbilityHeal, Debuff, & Buff variables to the
corresponding objects you just imported
NOTE: Make sure that AbilityCurse & AbilityHeal have the correct buff data fields!
Changelog:
---------
- v2.01 (March 18, 2016): Added an optional Volatile Light folder that is integrated with GUI Spell System
Fixed inaccuracy of GrowRate incrementing inside the circle creation loop
Removed unnecesary NodeLast[] variable for linked list; last spell instance now stores into NodePrev[0]
Removed If/Then/Else that would set NodeLast = NodePrev[Spell_ID] if NodeLast == Spell_ID
- v2.00 (January 25, 2016): Changed data structure to linked listing
Fixed bug of debuff effect not being removed on dead enemy units until the end of the duration
- v1.03 (December 04, 2015): Changed Owner[] variable to now use Triggering Player instead of Owner of (Unit)
Changed spell to now use one global dummy caster instead of one dummy caster per spell instance
Changed loop to check if it is time to deindex before starting
Changed name of VL Init trigger to VL Cast
Removed unnecessary function call when turning off VL Loop (Turn off (This trigger) -> (Turn off VL Loop))
- v1.02 (November 26, 2015): Changed the way the lightning effects are created
Changed names of some variables
Removed the Lightning Effects ability
Removed unneccesary variables
- v1.01 (October 1, 2015): Added a configurable to change the origin and angle of the lightning effects
Fixed GrowSpeed to GrowTime (lets you decide how long it will take for effects to reach max radius)
Removed KillUnit function and replaced it with RemoveUnit
Removed VL Dummy Cleaner trigger
- v1.00 (September 29, 2015): Uploaded onto Hive
//TESH.scrollpos=0
//TESH.alwaysfold=0
/*
Volatile Light w/ GUI Spell System
v2.01
By KILLCIDE
Making this spell gave me so many problems ._. this spell went through A LOT (an understatement) of changes
Requirements:
--------
- dummy.mdx
- GUI Spell System
Credits:
-------
- Bribe for GUI Spell System
- Vexorian for dummy.mdx
How to Install:
--------------
1. Under Preferences, make sure you have "Automatically create unknown variables while pasting trigger data" checked
2. Import dummy.mdx, then copy and paste the dummy unit, three abilities, and two buffs into your map
NOTE: If you already have dummy.mdx imported into your map, you DO NOT have to reimport it
If you already have a global dummy unit in your map, you can skip this step
3. Copy and paste the VL w/ GUI Spell System folder into your map
NOTE: You DO NOT have to reimport GUI Spell System if you already have it in your map
If this is your first time importing GUI Spell System, make sure the DummyType variable has the corresponding global dummy
unit in your map
4. Go to the VL Config trigger, and change the Ability, AbilityCurse, AbilityHeal, Debuff, & Buff variables to the
corresponding objects you just imported
5. Right click on each VL trigger (excluding VL readme) and click on "Initially on"
NOTE: Make sure there are no disabled actions in any of the VL triggers
NOTE: Make sure that AbilityCurse & AbilityHeal have the correct buff data fields!
Changelog:
---------
- v2.01 (March 18, 2016): Added an optional Volatile Light folder that is integrated with GUI Spell System
Fixed inaccuracy of GrowRate incrementing inside the circle creation loop
Removed unnecesary NodeLast[] variable for linked list; last spell instance now stores into NodePrev[0]
Removed If/Then/Else that would set NodeLast = NodePrev[Spell_ID] if NodeLast == Spell_ID
- v2.00 (January 25, 2016): Changed data structure to linked listing
Fixed bug of debuff effect not being removed on dead enemy units until the end of the duration
- v1.03 (December 04, 2015): Changed Owner[] variable to now use Triggering Player instead of Owner of (Unit)
Changed spell to now use one global dummy caster instead of one dummy caster per spell instance
Changed loop to check if it is time to deindex before starting
Changed name of VL Init trigger to VL Cast
Removed unnecessary function call when turning off VL Loop (Turn off (This trigger) -> (Turn off VL Loop))
- v1.02 (November 26, 2015): Changed the way the lightning effects are created
Changed names of some variables
Removed the Lightning Effects ability
Removed unneccesary variables
- v1.01 (October 1, 2015): Added a configurable to change the origin and angle of the lightning effects
Fixed GrowSpeed to GrowTime (lets you decide how long it will take for effects to reach max radius)
Removed KillUnit function and replaced it with RemoveUnit
Removed VL Dummy Cleaner trigger
- v1.00 (September 29, 2015): Uploaded onto Hive
//TESH.scrollpos=49
//TESH.alwaysfold=0
function SpellIndexGetVars takes integer i returns nothing
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]
//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[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]
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
if udg_Spell__Duration > 0.00 then
set d = udg_Spell__Duration
set udg_Spell__Duration = 0.00
elseif udg_Spell__Expired then
return udg_Spell__Time
endif
if udg_Spell__Time == 0.00 then
if udg_Spell_i_LastTime[i] == 0.00 then
//If this is the first time the spell has been given a
//duration, set the spell time to the minimum.
set udg_Spell__Time = udg_Spell__Interval
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.
set udg_Spell_i_Duration[i] = d - udg_Spell__Time //Subtract the time from the duration.
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
//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 any customized filter variables:
call SpellSetFilters(head)
//Tell the system to automatically create target groups, if needed
set udg_Spell_i_UseTG[head] = udg_Spell__UseTargetGroup
//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__UseTargetGroup = false
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 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]
if udg_Spell__WakeTargets and UnitIsSleeping(u) then
call UnitWakeUp(u)
endif
set j = j + 1
set udg_Spell__InRangeUnits[j] = u
exitwhen true
endloop
endloop
set udg_Spell__InRange = 0.00
set udg_Spell__InRangeCount = j
loop
exitwhen j == 0
call GroupAddUnit(udg_Spell__InRangeGroup, udg_Spell__InRangeUnits[j])
set j = j - 1
endloop
return false
endfunction
//===========================================================================
function InitTrig_Spell_System takes nothing returns nothing
local integer i = 16
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.
set udg_Spell_i_PreloadDummy = CreateUnit(udg_Spell__DummyOwner, udg_Spell__DummyType, 0, 0, 0)
call UnitApplyTimedLife(udg_Spell_i_PreloadDummy, 'BTLF', 0.01)
endfunction