/********************************************************************************************
* Zephyr Challenge #6 Entry by xD.Schurke
*
* Ritual of Vengeance
*
* Requires:
* - JassHelper 0.9.Z.5 by Vexorian
* - Table 3.0 by Vexorian
* - Intuitive Damage Detection System 1.13 by Rising_Dusk
*
* How to implement the spell?
*
* Copy this trigger into your map and check if also Table and IDDS are in your
* map. Then make sure u change all ID variables to your map specific spell/unit
* rawcodes (You also can copy the spells/units from the object editor to your
* map).
* If you want to change some variables, you can do this in the global variable
* declaration part, they are all well descriped, so you will fast find the
* variables you may want to edit. The same you can do with the different
* formulas: Just change them as needed. The core of the spell shouldn't be
* edited unless you know what you do, but you can read through it to learn
* something about my coding style and vJass, hence they are well commented.
*
* Some additional information
*
* Why do I use Table for storing the units affected by the Lyrium Shield
* instead of an array?
*
* Well, I just could use a hashtable but I like the userfriendly style of
* Table. In addition it has a better performance for many instances, because
* I don't have to look up the stored units/structs in a linear loop,
* but I just can get the table entry by going to the hash related entry.
* So the spell will still have a good performance if one uses it some thousand
* times.
*
* Content
*
* 1. Global - Variable Block
* 1.1 ID - Variable Block
* 1.2 Int - Variable Block
* 1.3 Real - Variable Block
* 1.4 String - Variable Block
* 1.5 Group - Variable Block
* 2. Functions
* 2.1 Formulas
* 2.2 Filter
* 3. Core - Part
* 3.1 Shield Struct
* 3.2 Missile Struct
* 3.3 Spirit Struct
* 4. Initialization - Part
* 4.1 Condition
* 4.2 Action
* 4.3 Initializer
*
********************************************************************************************/
scope SpellScope initializer onInit
/****************************
* 1.Global - Variable Block*
****************************/
globals
/****************************
* 1.1 ID - Variable Block *
****************************/
//The DUMMY_ID variable is the one which represents the raw code of your dummy unit
private constant integer DUMMY_ID = 'n001'
//The SPELL_ID variable is the one which represents the raw code of the hero/unit spell which is used by the player
private constant integer SPELL_ID = 'A000'
//The DMG_BUFF_ID variable is the one which represents the raw code of the ability which grants extra attack damage to the Lyrium Spirit.
//I used a item ability with 50 levels which just increases attack damage by increasing the level (more at 3.3 Spirit Struct)
private constant integer DMG_BUFF_ID = 'A001'
//The UNIT_ID variable is the one which represents the raw code of the summoned Lyrium Spirit
private constant integer UNIT_ID = 'n000'
//The SHIELD_SPELL_ID is the one which represents the spell which is casted on the player owned hero which summoned the spirit.
//This "shield" protects the hero (more at 3.1 Shield Struct)
private constant integer SHIELD_SPELL_ID = 'A002'
//The SHIELD_BUFF_ID is the one which represents the buff created by the SHIELD_SPELL_ID spell it's used in 3.1 Shield Struct
private constant integer SHIELD_BUFF_ID = 'B000'
/****************************
* 1.2 Int - Variable Block *
****************************/
//All integer variables are used in 2.1 Formulas, you can find more information there.
//UNIT_COUNT is a integer variable representing the maximum units from which the summoned spirit profits
private constant integer UNIT_COUNT = 12
//UNIT_COUNT_INC is used for the multi-level supporting and represents the additional units per ability level
private constant integer UNIT_COUNT_INC = 0
//DAMAGE_BOOST is used for the damage gained by the spirit for each unit sorrounding it.
private constant integer DAMAGE_BOOST = 2
//UNIT_BOOST_INC is used for the multi-level supporting and represents the additional damage per ability level
private constant integer DAMAGE_BOOST_INC = 1
/*****************************
* 1.3 Real - Variable Block *
*****************************/
//The INTERVAL variable is used by timers. Those timers are executed each INTERVAL seconds
private constant real INTERVAL = 0.03125
//THE DURATION variable is used by the 2.1 Formuals to calculate the spirit duration
private constant real DURATION = 25.0
//THE DURATION_INC variable is used by the 2.1 Formuals to calculate the spirit duration
private constant real DURATION_INC = 10.0
//THE SHIELD_DUR variable is used by the 2.1 Formuals to calculate the shield duration
private constant real SHIELD_DUR = 15.0
//THE SHIELD_DUR_INC variable is used by the 2.1 Formuals to calculate the shield duration
private constant real SHIELD_DUR_INC = 0.0
//THE COIL_DURATION variable is used for the coil missile duration, which are send to the units
private constant real COIL_DURATION = 0.50
//After SUMON_TIME seconds, which always has to be 2 x COIL_DURATION the Lyrium Spirit is summoned
private constant real SUMMON_TIME = COIL_DURATION*2
//The MISSILE_DURATION is used for the missiles send to sorrounding hostile units
private constant real MISSILE_DURATION = 1.5
//Each DAMAGE_INTERVAL the Lyrium Spirit creates new missiles and damages all nearby foes
private constant real DAMAGE_INTERVAL = 1.5
//The DAMAGE_RADIUS is the radius where all hostile units are damage
private constant real DAMAGE_RADIUS = 250.0
//Each new level the damage radius is increased by DAMAGE_RADIUS_INC
private constant real DAMAGE_RADIUS_INC = 50.0
//Each DAMAGE_INTERVAL the spirit deals AOE_DAMAGE to foes
private constant real AOE_DAMAGE = 2.0
//AOE_DAMAGE_INC is used for multi-level support
private constant real AOE_DAMAGE_INC = 1.0
//COIL_DAMAGE is dealt as damage to units in the beginning of the spell
private constant real COIL_DAMAGE = 10.0
//COIL_DAMAGE_INC is used in 2.1 formuals to calculate the damage of each spell level
private constant real COIL_DAMAGE_INC = 10.0
//SHIELD_FACTOR represents the factor with which the sucked energy is devided
private constant real SHIELD_FACTOR = 2.0
/*******************************
* 1.4 String - Variable Block *
*******************************/
//All following variables represent model pathes for special effects
//SHIELD_SUMMON_GFX is used on the creation of the shield
private constant string SHIELD_SUMMON_GFX = "Abilities\\Spells\\Undead\\DeathPact\\DeathPactTarget.mdl"
//SUMMON_EFFECT is used on the summon of the spirit
private constant string SUMMON_EFFECT = "Abilities\\Spells\\Undead\\Darksummoning\\DarkSummonTarget.mdl"
//COIL_EFFECT represents the model, which is used to visualize the missile
private constant string COIL_EFFECT = "Abilities\\Spells\\Undead\\DeathCoil\\DeathCoilMissile.mdl"
//COIL_DEATH_EFFECT is shown when a missile dies
private constant string COIL_DEATH_EFFECT = "Abilities\\Spells\\Undead\\DeathCoil\\DeathCoilSpecialArt.mdl"
//MISSILE_EFFECT is for the missiles spawned each DAMAGE_INTERVAL
private constant string MISSILE_EFFECT = "Abilities\\Weapons\\AvengerMissile\\AvengerMissile.mdl"
/*******************************
* 1.5 Group - Variable Block *
*******************************/
//The following variables shouldn't be touched, they are nessesary for group issues
//TMPG is a group which is allways only used temporaly see more 4.3 Initializer for the CreateGroup()
private group TMPG = null
//Always before TMPG is defined the TMPP variable should be set to the owning player
private player TMPP = null
//COND is used for the filter see more 2.2 Filter
private boolexpr COND = null
endglobals
/********************
* 2. Functions *
********************/
//The functions part contains all nessessary stuff which is used for multi level supporting and group issues filter
/********************
* 2.1 Formulas *
********************/
//Change following formulas if you want to have other results
private function getDuration takes integer lvl returns real
return (lvl-1)*DURATION_INC+DURATION
endfunction
private function getShieldDuration takes integer lvl returns real
return (lvl-1)*SHIELD_DUR_INC+SHIELD_DUR
endfunction
private function getMaximumUnitCount takes integer lvl returns integer
return (lvl-1)*UNIT_COUNT_INC+UNIT_COUNT
endfunction
private function getDamageBoost takes integer lvl returns integer
return (lvl-1)*DAMAGE_BOOST_INC+DAMAGE_BOOST
endfunction
private function getAoeDmg takes integer lvl returns real
return (lvl-1)*AOE_DAMAGE_INC+AOE_DAMAGE
endfunction
private function getCoilDmg takes integer lvl returns real
return (lvl-1)*COIL_DAMAGE_INC+COIL_DAMAGE
endfunction
private function getDamageRadius takes integer lvl returns real
return (lvl-1)*DAMAGE_RADIUS_INC+DAMAGE_RADIUS
endfunction
/********************
* 2.2 Filter *
********************/
//The filter is used for group issues. Units are put in the group variable if following conditions are true
private function filter takes nothing returns boolean
return IsUnitEnemy(GetFilterUnit(),TMPP) and (GetUnitState(GetFilterUnit(),UNIT_STATE_LIFE)>0) and IsUnitType(GetFilterUnit(),UNIT_TYPE_GROUND) and (GetUnitTypeId(GetFilterUnit())!=DUMMY_ID)
endfunction
/********************
* 3. Core - Part *
********************/
/**********************
* 3.1 Shield Struct *
**********************/
//Everytime a Lyrium Spirit dies it releases a power which protects the caster from physical damage.
//Here we use a HandleTable and the Intuitive Damage Detection System for absorbing the dealt damage.
private struct shieldStruct
//The following variables are set in the create method
private unit target = null //The target of the shield
private real duration = 0.0 //How long the shield lasts
private real absorb = 0.0 //How much should the shield absorb
private static HandleTable table //The table stores all units affected by a shield. Why we use table? (see more introduction)
private static timer tim //This static timer loops through all instances of this struct to do some things
private static integer total = 0 //The maximum number of current instances
private static integer array data //All instances are stored here for loop through it
//This method is called each INTERVAL by the static timer tim
private static method callback takes nothing returns nothing
local thistype this
local integer i = 0
loop
exitwhen i >= thistype.total
set this = thistype.data[i] //get the struct instance at data[i]
set this.duration = this.duration - INTERVAL
//If following conditions are true we should destroy the instance
if this.duration <= 0 or this.absorb <= 0 or GetUnitState(this.target,UNIT_STATE_LIFE) <= 0.406 or GetUnitAbilityLevel(this.target,SHIELD_BUFF_ID) <= 0 then
set this.total = this.total - 1
set this.data[i] = this.data[this.total]
set i = i - 1
call this.destroy()
endif
set i = i + 1
endloop
//If there are no instances left, why should the timer still be active?
if thistype.total == 0 then
call PauseTimer(thistype.tim)
endif
endmethod
//The following method allocates a new instance of this struct for later usage. In addtition all nessesary variables are set
static method create takes unit target, real absorb, real duration returns thistype
local thistype this = thistype.allocate()
//Lets create a dummy which casts a buff on our target, so that also dispell spells can work with this spell
local unit dummy = CreateUnit(GetOwningPlayer(target),DUMMY_ID,GetUnitX(target),GetUnitY(target),0)
call UnitAddAbility(dummy,SHIELD_SPELL_ID)
call IssueTargetOrder(dummy,"innerfire",target)
call UnitApplyTimedLife(dummy,'BTLF',1.0)
//Set the variables
set this.target = target
set this.absorb = absorb
set this.duration = duration
set this.table[target] = this
//We also need some eye-candy
call DestroyEffect(AddSpecialEffectTarget(SHIELD_SUMMON_GFX,target,"origin"))
//If there is no instance of this struct we should start the timer, 'cause just created an instance
if this.total == 0 then
call TimerStart(this.tim,INTERVAL,true,function thistype.callback)
endif
set this.data[this.total] = this
set this.total = this.total + 1
set dummy = null
return this
endmethod
//When we destroy an instance this method is called and does the things we want it to do
private method onDestroy takes nothing returns nothing
call UnitRemoveAbility(this.target,SHIELD_BUFF_ID)
call this.table.flush(this.target)
set this.target = null
endmethod
//The following methods are used to get to know of all incoming physical damage and if the attacked units has a shield
private static method condition takes nothing returns boolean
return GetTriggerDamageType() == DAMAGE_TYPE_ATTACK and thistype.table.exists(GetTriggerDamageTarget())
endmethod
private static method action takes nothing returns nothing
local thistype this = thistype.table[GetTriggerDamageTarget()]
local real life = GetUnitState(this.target,UNIT_STATE_LIFE)
set this.absorb = this.absorb - GetTriggerDamage()
call SetUnitState(this.target,UNIT_STATE_LIFE,life+GetTriggerDamage())
endmethod
private static method onInit takes nothing returns nothing
local trigger trig = CreateTrigger()
call TriggerAddCondition(trig,Condition(function thistype.condition))
call TriggerAddAction(trig,function thistype.action)
call TriggerRegisterDamageEvent(trig,0)
set trig = null
set thistype.table = HandleTable.create()
set thistype.tim = CreateTimer()
endmethod
endstruct
/**********************
* 3.2 Missile Struct *
**********************/
//The missile struct is just an object which represents some moving effects but with no more ususage
private struct missileStruct
private unit missile = null //The missile itself should be an unit
private unit target = null //Where should the missile move to
private effect gfx = null //The effect of the missile
private real duration = 0.0 //How long the missile lasts
private real damage = 0.0 //How much damage on impact
private static timer tim //This static timer loops through all instances of this struct to do some things
private static integer total = 0 //The maximum number of current instances
private static integer array data //All instances are stored here for loop through it
//This method is called each INTERVAL by the static timer tim
private static method callback takes nothing returns nothing
local thistype this
local integer i = 0
//The real variables are needed fore some mathematical calculations
local real x1 = 0.0
local real x2 = 0.0
local real x3 = 0.0
local real y1 = 0.0
local real y2 = 0.0
local real y3 = 0.0
local real distance = 0.0
local real angle = 0.0
loop
exitwhen i >= thistype.total
set this = thistype.data[i]
//This part is used to calculate the movement of the missile
set x1 = GetUnitX(this.missile)
set y1 = GetUnitY(this.missile)
set x2 = GetUnitX(this.target)
set y2 = GetUnitY(this.target)
set distance = SquareRoot((x2-x1)*(x2-x1)+(y2-y1)*(y2-y1))/(this.duration/INTERVAL)
set angle = Atan2(y2-y1,x2-x1)
set x3 = x1 + distance * Cos(angle)
set y3 = y1 + distance * Sin(angle)
call SetUnitPosition(this.missile,x3,y3)
//***********************************************************
//Destroy the missile if it reached the target unit
if this.duration == 0 then
set this.total = this.total - 1
set this.data[i] = this.data[this.total]
set i = i - 1
call this.destroy()
endif
set this.duration = this.duration - INTERVAL
set i = i + 1
endloop
if thistype.total == 0 then
call PauseTimer(thistype.tim)
endif
endmethod
//The following method allocates a new instance of this struct for later usage. In addtition all nessesary variables are set
static method create takes player owner, string effectPath, real x1, real y1, unit target,real duration,real damage returns thistype
local thistype this = thistype.allocate()
//create the unit + effect which will represent an moving object
set this.missile = CreateUnit(owner,DUMMY_ID,x1,y1,0)
call AddSpecialEffectTarget(effectPath,this.missile,"origin")
set this.target = target
set this.duration = duration
set this.damage = damage
if this.total == 0 then
call TimerStart(this.tim,INTERVAL,true,function thistype.callback)
endif
set this.data[this.total] = this
set this.total = this.total + 1
return this
endmethod
private method onDestroy takes nothing returns nothing
call UnitDamageTargetEx(this.missile,this.target,this.damage,ATTACK_TYPE_NORMAL,DAMAGE_TYPE_SPELL,true)
call RemoveUnit(this.missile)
call DestroyEffect(this.gfx)
call DestroyEffect(AddSpecialEffect(COIL_DEATH_EFFECT,GetUnitX(this.target),GetUnitY(this.target)))
set this.target = null
set this.missile = null
set this.gfx = null
endmethod
private static method onInit takes nothing returns nothing
set thistype.tim = CreateTimer()
endmethod
endstruct
/**********************
* 3.3 Spirit Struct *
**********************/
//The spiritStruct is the "main" struct and it represents the Lyrium Spirit in general and its actions
private struct spiritStruct
public unit caster = null //Who casted the spell
public real spellX = 0.0 //The X-Coordiante of the spell targeted area
public real spellY = 0.0 //The Y-Coordiante of the spell targeted area
public integer unitsInRange = 0 //Is set to the number of units in range (maximum is equal to getMaximumUnitCount see also 2.1 Formulas)
private unit summon = null //This is the Lyrium Spirit
private unit summonRitual = null //Just an unit representing the summon effect
private effect ritualEffect = null //The effect used by summonRitual
private real timePassed = 0.0 //How long did the spirit allready lasts
private real damageTime = 0.0 //This counts to DAMAGE_TIME and then again set to 0
private real damageDealt = 0.0 //We must store the dealt damage to calculate the shield-strength later
private boolean isSummoned = false //This is set to true if the spirit is summoned
private boolean coilWave = false //Just needed for the summoning
private static timer tim //This static timer loops through all instances of this struct to do some things
private static integer total = 0 //The maximum number of current instances
private static integer array data //All instances are stored here for loop through it
//This method is called each INTERVAL by the static timer tim
private static method callback takes nothing returns nothing
local thistype this
local integer i = 0
//The following 2 variables are used for group-loop reasons
local integer j = 0
local unit u = null
loop
exitwhen i >= thistype.total
set this = thistype.data[i]
set this.timePassed = this.timePassed + INTERVAL
set this.damageTime = this.damageTime + INTERVAL
//If the following conditions are true we finally can summon the spirit
if this.timePassed >= SUMMON_TIME and this.isSummoned != true then
set this.summon = CreateUnit(GetOwningPlayer(this.caster),UNIT_ID,this.spellX,this.spellY,0)
//The ritual effect is no more needed so lets destroy it
call RemoveUnit(this.summonRitual)
call DestroyEffect(this.ritualEffect)
//How long should the spirit lasts see also 2.1 Formuals
call UnitApplyTimedLife(this.summon,'BTLF',getDuration(GetUnitAbilityLevel(this.caster,SPELL_ID)))
//Should the spirit get some extra damage lets check it!
call UnitAddAbility(this.summon,DMG_BUFF_ID)
call SetUnitAbilityLevel(this.summon,DMG_BUFF_ID,this.unitsInRange*getDamageBoost(GetUnitAbilityLevel(this.caster,SPELL_ID)))
set this.damageDealt = this.unitsInRange*getCoilDmg(GetUnitAbilityLevel(this.caster,SPELL_ID))
if this.unitsInRange == 0 then
call UnitRemoveAbility(this.summon,DMG_BUFF_ID)
endif
set this.isSummoned = true
//Each DAMAGE_INTERVAL we should damage all sorrounding foes , so lets send some missiles to them and save the dealt damage
elseif this.timePassed >= SUMMON_TIME and this.damageTime >= DAMAGE_INTERVAL then
set TMPP = GetOwningPlayer(this.caster)
call GroupEnumUnitsInRange(TMPG,GetUnitX(this.summon),GetUnitY(this.summon),getDamageRadius(GetUnitAbilityLevel(this.caster,SPELL_ID)),COND)
loop
set u = FirstOfGroup(TMPG)
exitwhen u == null or j >= getMaximumUnitCount(GetUnitAbilityLevel(this.caster,SPELL_ID))
set j = j + 1
call missileStruct.create(GetOwningPlayer(this.caster),MISSILE_EFFECT,GetUnitX(this.summon),GetUnitY(this.summon),u,MISSILE_DURATION,getAoeDmg(GetUnitAbilityLevel(this.caster,SPELL_ID)))
set this.damageDealt = this.damageDealt + getAoeDmg(GetUnitAbilityLevel(this.caster,SPELL_ID))
call GroupRemoveUnit(TMPG,u)
endloop
set this.damageTime = 0.0
//We just need that part for eye-candy reasons: In general it sends missiles from the units to the summoning point
elseif this.timePassed >= COIL_DURATION and this.coilWave != true then
set this.summonRitual = CreateUnit(GetOwningPlayer(this.caster),DUMMY_ID,this.spellX,this.spellY,0)
set this.ritualEffect = AddSpecialEffectTarget(SUMMON_EFFECT,this.summonRitual,"origin")
set TMPP = GetOwningPlayer(this.caster)
call GroupEnumUnitsInRange(TMPG,this.spellX,this.spellY,getDamageRadius(GetUnitAbilityLevel(this.caster,SPELL_ID)),COND)
loop
set u = FirstOfGroup(TMPG)
exitwhen u == null or j >= getMaximumUnitCount(GetUnitAbilityLevel(this.caster,SPELL_ID))
set j = j + 1
call missileStruct.create(GetOwningPlayer(this.caster),COIL_EFFECT,GetUnitX(u),GetUnitY(u),this.summonRitual,COIL_DURATION,0)
call GroupRemoveUnit(TMPG,u)
endloop
set j = 0
set this.coilWave = true
endif
//This if-block is needed to check if there are units arround and if the Lyrium Spirit should get some extra damage (Eeach Interval)
if this.timePassed >= SUMMON_TIME and this.isSummoned == true then
set TMPP = GetOwningPlayer(this.caster)
call GroupEnumUnitsInRange(TMPG,GetUnitX(this.summon),GetUnitY(this.summon),getDamageRadius(GetUnitAbilityLevel(this.caster,SPELL_ID)),COND)
loop
set u = FirstOfGroup(TMPG)
exitwhen u == null or j >= getMaximumUnitCount(GetUnitAbilityLevel(this.caster,SPELL_ID))
set j = j + 1
call GroupRemoveUnit(TMPG,u)
endloop
if GetUnitAbilityLevel(this.summon,DMG_BUFF_ID) <= 0 then
call UnitAddAbility(this.summon,DMG_BUFF_ID)
endif
set this.unitsInRange = j
call SetUnitAbilityLevel(this.summon,DMG_BUFF_ID,this.unitsInRange*getDamageBoost(GetUnitAbilityLevel(this.caster,SPELL_ID)))
if this.unitsInRange == 0 then
call UnitRemoveAbility(this.summon,DMG_BUFF_ID)
endif
set j = 0
endif
//Destroy this struct if following coditions are true
if (this.timePassed >= getDuration(GetUnitAbilityLevel(this.caster,SPELL_ID)) or GetUnitState(this.summon,UNIT_STATE_LIFE) <= 0.406) and this.isSummoned == true then
set this.total = this.total - 1
set this.data[i] = this.data[this.total]
set i = i - 1
call shieldStruct.create(this.caster,this.damageDealt/SHIELD_FACTOR,getShieldDuration(GetUnitAbilityLevel(this.caster,SPELL_ID)))
call this.destroy()
endif
set i = i + 1
endloop
if thistype.total == 0 then
call PauseTimer(thistype.tim)
endif
endmethod
static method create takes nothing returns thistype
local thistype this = thistype.allocate()
if this.total == 0 then
call TimerStart(this.tim,INTERVAL,true,function thistype.callback)
endif
set this.data[this.total] = this
set this.total = this.total + 1
return this
endmethod
private method onDestroy takes nothing returns nothing
set this.caster = null
set this.summon = null
set this.ritualEffect = null
endmethod
private static method onInit takes nothing returns nothing
set thistype.tim = CreateTimer()
endmethod
endstruct
/*****************************
* 4. Initialization - Part *
*****************************/
/******************
* 4.1 Condition *
******************/
//When a casted spell is equal to this spell we can call the action-function
private function spellCond takes nothing returns boolean
return GetSpellAbilityId() == SPELL_ID
endfunction
/******************
* 4.2 Action *
******************/
//Here we setup the main struct and send missiles to all foes in the targeted area
private function spellAction takes nothing returns nothing
//We need an isntance of the spiritStruct to have some nice effects :P
local spiritStruct this = spiritStruct.create()
local integer i = 0
local unit u = null
//Set all public variables of the spiritStruct instance
set this.spellX = GetSpellTargetX()
set this.spellY = GetSpellTargetY()
set this.caster = GetTriggerUnit()
set TMPP = GetOwningPlayer(this.caster)
call GroupEnumUnitsInRange(TMPG,this.spellX,this.spellY,getDamageRadius(GetUnitAbilityLevel(this.caster,SPELL_ID)),COND)
loop
set u = FirstOfGroup(TMPG)
exitwhen u == null or i >= getMaximumUnitCount(GetUnitAbilityLevel(this.caster,SPELL_ID))
set i = i + 1
call missileStruct.create(GetOwningPlayer(this.caster),COIL_EFFECT,GetUnitX(this.caster),GetUnitY(this.caster),u,COIL_DURATION,getCoilDmg(GetUnitAbilityLevel(this.caster,SPELL_ID)))
call GroupRemoveUnit(TMPG,u)
endloop
set this.unitsInRange = i
endfunction
/*******************
* 4.3 Initializer *
*******************/
//This function initializes everything... it's needed :)
private function onInit takes nothing returns nothing
local trigger trig = CreateTrigger()
local unit dummy = null
local integer index = 0
loop
call TriggerRegisterPlayerUnitEvent(trig, Player(index), EVENT_PLAYER_UNIT_SPELL_EFFECT, null)
set index = index + 1
exitwhen index == bj_MAX_PLAYER_SLOTS
endloop
call TriggerAddCondition(trig,Condition(function spellCond))
call TriggerAddAction(trig, function spellAction)
set trig = null
//Setup group Issues
set TMPG = CreateGroup()
set COND = Filter(function filter)
//Preload-Part so no future lags
set dummy = CreateUnit(Player(14),DUMMY_ID,0,0,0)
call UnitAddAbility(dummy,DMG_BUFF_ID)
call RemoveUnit(dummy)
set dummy = null
call Preload(SHIELD_SUMMON_GFX)
call Preload(SUMMON_EFFECT)
call Preload(COIL_EFFECT)
call Preload(COIL_DEATH_EFFECT)
call Preload(MISSILE_EFFECT)
call PreloadStart()
endfunction
endscope