//=====================================================================================================================================
// About
// Spirits v1.6
// Created by bajaist
// This spell: [url]http://www.hiveworkshop.com/forums/spells-569/spirits-v1-6-a-250320/[/url]
//
// For more resources visit:
// [url]www.thehelper.net[/url]
// [url]www.hiveworkshop.com[/url]
// [url]www.wc3c.net[/url]
//
//
//
// MUI: true
// Language: JASS
// Editor: vanilla Editor
// Import difficulty: low
// Spell type: no target
//
// Io summons 5 ancient Spirits over the course of 3 seconds. The Spirits dance around Io in a circle to protect him.
// If an enemy hero moves close enough to touch a Spirit, the Spirit releases its life energy in a burst,
// dealing damage to all enemies in a 300 area of effect. Non hero units only take minor damage upon touching a spirit
// and do not cause them to explode.
// ===================================================================================================================================
// Importing
// These settings are optional, user should set them to their liking. You can look at the provided map for all settings.
// --------------------------------------------------------
// External requirements: none
// --------------------------------------------------------
// Triggers:
// Simple copy and paste. Remember to allow pasting of variables:
// File/Preferences/Automatically create unknown variables while pasting trigger data (English version)
// If not already, set initial value for IS_maxIndex to -1.
// --------------------------------------------------------
// Units:
// A hero or heroes with Spirits ability.
// A Spirit unit:
// Scaling Value: 0.5 damageUnit[0] should be relative to scaling value
// Model File: Wisp
// Sight Radius (Day): 0
// Sight Radius (Night): 0
// --------------------------------------------------------
// Abilities:
// This spell requires 3 dummy abilities: Spirits, Push Out and Pull In.
// If you don't want them to interrupt orders use Mana Shield, Wind Walk and Berserk, clear all unneeded values. For all 3:
// Duration: 0.01
// Or 3 spells based off of channel.
//
// ===================================================================================================================================
function SpiritsInitialization takes nothing returns nothing
// This function is used to set/configure spell values
local integer l = 1 // l; integer; counter, helper variable
local integer rotation // rotation; integer; sets clockwise/anticlockwise rotation for Spirits
local integer nLevels // levels; integer; number of spell levels
local real ang // ang; real; angle added on every shift, for Spirits rotation
// Note: changing any value too much may cause malfunctions
// ======================== Spell Configuration ==================================================================================
// ============== Stats ==============
set udg_IS_nSpirits = 5 // Set number of Spirits
// Note: duration countdown timer always starts when Push Out and Pull In abilities are added
set udg_IS_durTime = 19 // Set duration time
set udg_IS_perTime = 0.025 // Periodic time for Spirits rotation
// Note: Use ctrl + D in Object Editor to see raw data
set udg_IS_abiUnitID[0] = 'A007' // Spirits ability
set udg_IS_abiUnitID[1] = 'A006' // Push Out ability
set udg_IS_abiUnitID[2] = 'A004' // Pull In ability
set udg_IS_abiUnitID[3] = 'e000' // Spirit unit
set udg_IS_abiUnitID[4] = 'Aloc' // Locust ability
// ============== Damage ==============
set nLevels = 4 // Number of spell levels
// Damage calculator per level
loop
exitwhen l > nLevels
// ------------------------------
set udg_IS_dmgUnit[l] = l * 6 + 2 // damage to units
set udg_IS_dmgHero[l] = l * 25 // damage to heroes
// ------------------------------
set l = l + 1 // Note: for heroes and for end of spell, damage is AOE
endloop
set udg_IS_dmgHero[0] = 300 // Area of effect
set udg_IS_dmgUnit[0] = 40 // Detection radius of Spirit, Spirits Damage trigger event
set udg_IS_dmgAttackType = ATTACK_TYPE_HERO // Attack type
set udg_IS_dmgType = DAMAGE_TYPE_MAGIC // Damage type
set udg_IS_dmgUnitType[1] = false // Damage to flying
set udg_IS_dmgUnitType[2] = true // Damage to mechanical
set udg_IS_dmgUnitType[3] = true // Damage to structure
// ============== Visuals ==============
// There are 2, dota style - Spirits are created at minimal oscillation distance
// and customized - Spirits are created at position of caster and are sent one by one to minimal oscillation distance
set udg_IS_creationStyle = true // Set to false for Dota styled creation of Spirits
set udg_IS_distOscMin = 100 // Minimal oscillation distance
set udg_IS_distOscMax = 875 // Maximal oscillation distance
set udg_IS_distAng[1] = 8 // Set "speed" of oscillation, distance traveled from/to caster, while pushing out/pulling in
set udg_IS_distAng[3] = 0 // Starting angle at which Spirits are created
set rotation = 1 // Set to -1 for clockwise rotation
set udg_IS_sfxAnim = "Stand Work" // Queued Spirits animation
set udg_IS_sfxModel = "Abilities\\Spells\\NightElf\\Blink\\BlinkCaster.mdl" // Effect played upon Spirits explosion
set ang = 3 // Angle added on every shift, for Spirits rotation
// ======================== End of Spell Configuration ===========================================================================
set udg_IS_maxIndex = 0 // Setting maxIndex from -1 to 0
set udg_IS_distAng[0] = rotation * ang // Anticlockwise/clockwise rotation, angle while rotated is increased by 3
set udg_IS_distAng[2] = udg_IS_distOscMin / (360 / udg_IS_nSpirits / ang) // Distance traveled on each iteration for SpiritsCreate function (customized creation)
if udg_IS_creationStyle then // If creation style is customized
set udg_IS_durTime = udg_IS_durTime + udg_IS_perTime * (360 / ang) // Extending duration time for customized creation of Spirits
endif
set udg_IS_spiritHash = InitHashtable() // spiritHash; hashtable; stores spirits units
set udg_IS_dmgGroup = CreateGroup() // damageGroup; unit group; unit froup for AOE damage
set udg_IS_perTimer = CreateTimer() // perTimer; timer; periodic timer for Spirits rotation
endfunction
// ----------------------------------------------------------
function SpiritsUnitTypeFilter takes unit filt returns boolean
// This function is used to filter unit types for damage
// filt; unit; filter unit
if IsUnitType(filt, UNIT_TYPE_FLYING) then // Damage to flying
return udg_IS_dmgUnitType[1]
elseif IsUnitType(filt, UNIT_TYPE_MECHANICAL) then // Damage to mechanical
return udg_IS_dmgUnitType[2]
elseif IsUnitType(filt, UNIT_TYPE_STRUCTURE) then // Damage to structure
return udg_IS_dmgUnitType[3]
endif
return true
endfunction
// ----------------------------------------------------------
function SpiritsIsAliveFilter takes unit filt returns boolean
// This function is used to filter alive units
// filt; unit; filter unit
return GetWidgetLife(filt) > 0.405 and not IsUnitType(filt, UNIT_TYPE_DEAD) and GetUnitTypeId(filt) != 0
endfunction
// ----------------------------------------------------------
function SpiritsUnitGroupFilter takes nothing returns boolean
// This function is filter for damage group
return SpiritsUnitTypeFilter(GetFilterUnit()) and SpiritsIsAliveFilter(GetFilterUnit()) and IsUnitEnemy(GetFilterUnit(), udg_IS_ownPlayer)
endfunction
// ----------------------------------------------------------
function SpiritsDynamicIndex takes integer curIndex returns nothing
// This function is used to change indexes
// curIndex; integer; current index
call FlushChildHashtable(udg_IS_spiritHash, GetHandleId(udg_IS_caster[curIndex])) // Clearing child hashtable
// Clears both events and conditions of trigger, flush data inside trigger
call FlushChildHashtable(udg_IS_spiritHash, GetHandleId(udg_SpiritCollisionTrigger[curIndex]))
call DestroyTrigger(udg_SpiritCollisionTrigger[curIndex])
set udg_SpiritCollisionTrigger[curIndex] = null
call UnitRemoveAbility(udg_IS_caster[curIndex], udg_IS_abiUnitID[1]) // Removes Push Out and
call UnitRemoveAbility(udg_IS_caster[curIndex], udg_IS_abiUnitID[2]) // Pull In abilities
// =================== Max index to current index =======================================
set udg_IS_durTimer[curIndex] = udg_IS_durTimer[udg_IS_maxIndex] // Duration timer
set udg_IS_caster[curIndex] = udg_IS_caster[udg_IS_maxIndex] // Caster
set udg_IS_angMove[curIndex] = udg_IS_angMove[udg_IS_maxIndex] // Angle of Spirits while moving
set udg_IS_distMove[curIndex] = udg_IS_distMove[udg_IS_maxIndex] // Distance of Spirits while moving
set udg_IS_angCreate[curIndex] = udg_IS_angCreate[udg_IS_maxIndex] // Angle of Spirits while created
set udg_IS_distCreate[curIndex] = udg_IS_distCreate[udg_IS_maxIndex] // Distance of Spirits while created
set udg_IS_distAngC[curIndex] = udg_IS_distAngC[udg_IS_maxIndex] // Counts number of iterations
set udg_IS_distOscPushOut[curIndex] = udg_IS_distOscPushOut[udg_IS_maxIndex] // Push Out
set udg_IS_distOscPullIn[curIndex] = udg_IS_distOscPullIn[udg_IS_maxIndex] // Pull In
set udg_IS_nSpiritsCreated[curIndex] = udg_IS_nSpiritsCreated[udg_IS_maxIndex] // Number of created Spirits
set udg_IS_nSpiritsCurrent[curIndex] = udg_IS_nSpiritsCurrent[udg_IS_maxIndex] // Current number of Spirits
set udg_IS_maxIndex = udg_IS_maxIndex - 1 // Lowering max index
if udg_IS_maxIndex == 0 then // If no one is using the spell
call PauseTimer(udg_IS_perTimer) // pause periodic timer
endif
endfunction
// ----------------------------------------------------------
function SpiritsEndSpell takes integer curIndex returns nothing
// This function is used to end spell if caster dies
// or if spell is used before duration expire
// or if duration expire
// curIndex; integer; current index
local integer c = 1 // c; integer; counter, helper variable
local unit fog // fog; unit; first of group; used for damageGroup unit group
local unit spirit // spirit; unit; current Spirit, helper variable
// =========== Reamaining Spirits burst, at the end of spell, releasing damage ================
loop
exitwhen c > udg_IS_nSpirits
set spirit = LoadUnitHandle(udg_IS_spiritHash, GetHandleId(udg_IS_caster[curIndex]), c)
// If Spirit is alive
if SpiritsIsAliveFilter(spirit) then
// Picking units in group for aoe damage around each Spirit
set udg_IS_ownPlayer = GetOwningPlayer(spirit)
call GroupEnumUnitsInRange(udg_IS_dmgGroup, GetUnitX(spirit), GetUnitY(spirit), udg_IS_dmgHero[0], Filter(function SpiritsUnitGroupFilter))
loop
set fog = FirstOfGroup(udg_IS_dmgGroup)
exitwhen fog == null
// Damaging unit in group
call UnitDamageTarget(udg_IS_caster[curIndex], fog, udg_IS_dmgUnit[GetUnitAbilityLevel(udg_IS_caster[curIndex], udg_IS_abiUnitID[0])], false, false, udg_IS_dmgAttackType, udg_IS_dmgType, WEAPON_TYPE_WHOKNOWS)
call GroupRemoveUnit(udg_IS_dmgGroup, fog)
endloop
call DestroyEffect(AddSpecialEffect(udg_IS_sfxModel, GetUnitX(spirit), GetUnitY(spirit))) // Adding special effect at position of spirit
call RemoveUnit(spirit) // Spirit explode at the end of spell
endif
set c = c + 1
endloop
call SpiritsDynamicIndex(curIndex) // Managing indexes
// fog is already nulled
set spirit = null
endfunction
// ----------------------------------------------------------
function SpiritCollision takes nothing returns boolean
local integer curIndex = LoadInteger(udg_IS_spiritHash, GetHandleId(GetTriggeringTrigger()), 0)
local unit spirit // spirit; unit; current Spirit, helper variable
local integer c = 1 // c; integer; counter, helper variable
// ================= Checking which Spirit enemy unit came in contact with =============================================
loop
exitwhen c > udg_IS_nSpirits
// Loading spirits
set spirit = LoadUnitHandle(udg_IS_spiritHash, GetHandleId(udg_IS_caster[curIndex]), c)
// Checking if triggering unit is in range of each Spirit
if IsUnitInRangeXY(triggerUnit, GetUnitX(spirit), GetUnitY(spirit), udg_IS_dmgUnit[0] + 1) then
call SpiritsDamage(curIndex, spirit, triggerUnit)
endif
set c = c + 1
endloop
return false
endfunction
// ----------------------------------------------------------
function SpiritsCreate takes integer curIndex returns nothing
// This function is used for customized creation of Spirits
// Spirits are created at position of caster
// and moved, over time, one by one to minimal oscillation distance
// curIndex; integer; current index
local unit spirit // spirit; unit; created Spirit, helper variable
if udg_IS_distCreate[curIndex] == 0 then // If angle is reset, Spirit reached minimal oscillation distance, and another is created
// Creating Spirit for caster, at position of caster
set spirit = CreateUnit(GetOwningPlayer(udg_IS_caster[curIndex]), udg_IS_abiUnitID[3], GetUnitX(udg_IS_caster[curIndex]), GetUnitY(udg_IS_caster[curIndex]), 0)
call UnitAddAbility(spirit, udg_IS_abiUnitID[4]) // add Locust to Spirit
call SaveUnitHandle(udg_IS_spiritHash, GetHandleId(udg_IS_caster[curIndex]), udg_IS_nSpiritsCreated[curIndex], spirit)
call QueueUnitAnimation(spirit, udg_IS_sfxAnim)
else
set spirit = LoadUnitHandle(udg_IS_spiritHash, GetHandleId(udg_IS_caster[curIndex]), udg_IS_nSpiritsCreated[curIndex])
endif
// =================== Moving Spirit towards minimal oscillation distance ======================================================================
call SetUnitX(spirit, GetUnitX(udg_IS_caster[curIndex]) + udg_IS_distCreate[curIndex] * Cos(udg_IS_angCreate[curIndex] * bj_DEGTORAD))
call SetUnitY(spirit, GetUnitY(udg_IS_caster[curIndex]) + udg_IS_distCreate[curIndex] * Sin(udg_IS_angCreate[curIndex] * bj_DEGTORAD))
set udg_IS_distCreate[curIndex] = udg_IS_distCreate[curIndex] + udg_IS_distAng[2] // Always increases distance
set udg_IS_angCreate[curIndex] = udg_IS_angCreate[curIndex] + udg_IS_distAng[0] // Always increases angle
// =================== Checking if all Spirits are created or next Spirit should be ============================================================
// If distance of Spirits while created is same as minimimal oscillation distance
if udg_IS_distCreate[curIndex] == udg_IS_distOscMin then
// Adding "unit comes within event", for each Spirit
call TriggerRegisterUnitInRange(udg_SpiritCollisionTrigger[curIndex], spirit, udg_IS_dmgUnit[0], null)
set udg_IS_nSpiritsCreated[curIndex] = udg_IS_nSpiritsCreated[curIndex] + 1 // Counts current number of Spirits, from 1 - 5 since creation
set udg_IS_angCreate[curIndex] = udg_IS_distAng[3] // Resets angle of Spirits while created
set udg_IS_distCreate[curIndex] = 0 // Resets distance of Spirits while created
// Note: All 5 Spirits are meant to use the same path from caster to minimal oscillation distance
if udg_IS_nSpiritsCreated[curIndex] == udg_IS_nSpirits + 1 then // If all Spirits are created:
call UnitAddAbility(udg_IS_caster[curIndex], udg_IS_abiUnitID[1]) // add Push Out to Caster
call UnitAddAbility(udg_IS_caster[curIndex], udg_IS_abiUnitID[2]) // add Pull In to Caster
endif
endif
set spirit = null
endfunction
// ----------------------------------------------------------
function SpiritsCreateDota takes integer curIndex returns nothing
// This function is used to create Spirits as in Dota
// Spirits are created one by one at minimal oscillation distance
// curIndex; integer; current index
local unit spirit // spirit; unit; created Spirit, helper variable
// Creating Spirit for caster, at position of caster
// Spirit is immediately moved to minimal oscialtion distance by MoveSpirit function
set spirit = CreateUnit(GetOwningPlayer(udg_IS_caster[curIndex]), udg_IS_abiUnitID[3], GetUnitX(udg_IS_caster[curIndex]), GetUnitY(udg_IS_caster[curIndex]), 0)
call UnitAddAbility(spirit, udg_IS_abiUnitID[4]) // add Locust to Spirit
call SaveUnitHandle(udg_IS_spiritHash, GetHandleId(udg_IS_caster[curIndex]), udg_IS_nSpiritsCreated[curIndex], spirit)
// Adding unit comes within event, for each Spirit, to Spirits Damage trigger
call TriggerRegisterUnitInRange(udg_SpiritCollisionTrigger[curIndex], spirit, udg_IS_dmgUnit[0], null)
call QueueUnitAnimation(spirit, udg_IS_sfxAnim)
if udg_IS_nSpiritsCreated[curIndex] == 1 then // If all Spirits are created:
call UnitAddAbility(udg_IS_caster[curIndex], udg_IS_abiUnitID[1]) // add Push Out to Caster
call UnitAddAbility(udg_IS_caster[curIndex], udg_IS_abiUnitID[2]) // add Pull In to Caster
endif
set udg_IS_nSpiritsCreated[curIndex] = udg_IS_nSpiritsCreated[curIndex] + 1 // Increasing number of created spirits
set spirit = null
endfunction
// ----------------------------------------------------------
function SpiritsMove takes nothing returns nothing
// This function is used to move Spirits,
// check which creation style is used,
// manage oscillation distance
// and check if caster is dead or duration expired
local integer c // c; integer; counter, helper variable
local integer curIndex = 1 // curIndex; integer; current index
local unit spirit // spirit; unit; current Spirit, helper variable
local unit fog // fog; unit; first of group; used for damageGroup unit group
local real x // x; real; new x coordinate, helper variable
local real y // y; real; new y coordiante, helper variable
local real a = 360 / udg_IS_nSpirits // a; real; angle
// ===================
loop
exitwhen curIndex > udg_IS_maxIndex
// =================== Checking if duration time expired =====================================================
if udg_IS_durTimer[curIndex] >= udg_IS_durTime or not SpiritsIsAliveFilter(udg_IS_caster[curIndex]) then
call SpiritsEndSpell(curIndex)
else
// =================== Checking if all Spirits are created ===================================
if udg_IS_nSpiritsCreated[curIndex] < udg_IS_nSpirits + 1 then
if udg_IS_creationStyle then
call SpiritsCreate(curIndex) // Create another Spirit
elseif udg_IS_distAngC[udg_IS_maxIndex] >= (360 / udg_IS_nSpirits) then // Reseting counter
set udg_IS_distAngC[udg_IS_maxIndex] = 0
call SpiritsCreateDota(curIndex) // Create another Spirit
else
set udg_IS_distAngC[udg_IS_maxIndex] = udg_IS_distAngC[udg_IS_maxIndex] + RAbsBJ(udg_IS_distAng[0]) // Adding "ang degrees" to counter
endif
endif
// ================ Setting up oscialtion distance ===========================================
if udg_IS_distMove[curIndex] < udg_IS_distOscMin + 1 then // If oscillation distance is minimal:
set udg_IS_distOscPullIn[curIndex] = false // turn off Pull in
set udg_IS_distMove[curIndex] = udg_IS_distOscMin // set oscillation distance to minimal oscillation distance
elseif udg_IS_distMove[curIndex] > udg_IS_distOscMax - 1 then // If oscillation distance is maximal:
set udg_IS_distOscPushOut[curIndex] = false // turn off Push Out
set udg_IS_distMove[curIndex] = udg_IS_distOscMax // set oscillation distance to maximal oscillation distance
elseif udg_IS_distOscPushOut[curIndex] then // If Push Out is on:
set udg_IS_distMove[curIndex] = udg_IS_distMove[curIndex] + udg_IS_distAng[1] // Increase oscillation distance
elseif udg_IS_distOscPullIn[curIndex] then // If Pull In is on:
set udg_IS_distMove[curIndex] = udg_IS_distMove[curIndex] - udg_IS_distAng[1] // decrease oscillation distance
endif
set udg_IS_angMove[curIndex] = udg_IS_angMove[curIndex] + udg_IS_distAng[0] // Always increase angle
set udg_IS_distAngC[curIndex] = udg_IS_distAngC[curIndex] + 1 // Iteration counter
// ================ Moving Spirits ===========================================================
set c = 1
loop
// current number of Spirits; transfering from create to move function
exitwhen c == udg_IS_nSpiritsCreated[curIndex]
// Loading spirits
set spirit = LoadUnitHandle(udg_IS_spiritHash, GetHandleId(udg_IS_caster[curIndex]), c)
if udg_IS_distAng[0] > 0 then
// anticlockwise, (1 - c) * a sets it to the last created Spirit
set x = GetUnitX(udg_IS_caster[curIndex]) + udg_IS_distMove[curIndex] * Cos((udg_IS_angMove[curIndex] + (1 - c) * a) * bj_DEGTORAD)
set y = GetUnitY(udg_IS_caster[curIndex]) + udg_IS_distMove[curIndex] * Sin((udg_IS_angMove[curIndex] + (1 - c) * a) * bj_DEGTORAD)
else
// cloclwise, (c - 1) * a sets it to the last created Spirit
set x = GetUnitX(udg_IS_caster[curIndex]) + udg_IS_distMove[curIndex] * Cos((udg_IS_angMove[curIndex] + (c - 1) * a) * bj_DEGTORAD)
set y = GetUnitY(udg_IS_caster[curIndex]) + udg_IS_distMove[curIndex] * Sin((udg_IS_angMove[curIndex] + (c - 1) * a) * bj_DEGTORAD)
endif
call SetUnitX(spirit, x) // Moving Spirit to new coordinates
call SetUnitY(spirit, y)
set c = c + 1
endloop
set udg_IS_durTimer[curIndex] = udg_IS_durTimer[curIndex] + udg_IS_perTime // Increasing duration time
set curIndex = curIndex + 1 // Increasing index
endif
endloop
// fog is already nulled
set spirit = null
endfunction
// ----------------------------------------------------------
function SpiritsDamage takes integer curIndex, unit triggeredSpirit, unit triggerUnit returns nothing
// This function is used to deal damage
// triggeredSpirit; unit; triggered spirit
// triggerUnit; unit; triggering unit
// curIndex; integer; current index
local unit fog // fog; unit; first of group; used for damageGroup unit group
// ================= Dealing damage ====================================================================================
// If Spirit is alive
if SpiritsIsAliveFilter(triggeredSpirit) then
// If triggerting unit is alive, and an enemy
if SpiritsIsAliveFilter(triggerUnit) and SpiritsUnitTypeFilter(triggerUnit) and IsUnitEnemy(triggerUnit, GetOwningPlayer(udg_IS_caster[curIndex])) then
if IsUnitType(triggerUnit, UNIT_TYPE_HERO) then // If enemy unit is a hero
set udg_IS_nSpiritsCurrent[curIndex] = udg_IS_nSpiritsCurrent[curIndex] - 1 // Lowering number of Spirits
// Picking units in group for aoe damage around enemy hero
set udg_IS_ownPlayer = GetOwningPlayer(triggeredSpirit)
call GroupEnumUnitsInRange(udg_IS_dmgGroup, GetUnitX(triggerUnit), GetUnitY(triggerUnit), udg_IS_dmgHero[0], Filter(function SpiritsUnitGroupFilter))
loop
set fog = FirstOfGroup(udg_IS_dmgGroup)
exitwhen fog == null
// Damaging unit in group
call UnitDamageTarget(udg_IS_caster[curIndex], fog, udg_IS_dmgUnit[GetUnitAbilityLevel(udg_IS_caster[curIndex], udg_IS_abiUnitID[0])], false, false, udg_IS_dmgAttackType, udg_IS_dmgType, WEAPON_TYPE_WHOKNOWS)
call GroupRemoveUnit(udg_IS_dmgGroup, fog)
endloop
call DestroyEffect(AddSpecialEffect(udg_IS_sfxModel, GetUnitX(triggeredSpirit), GetUnitY(triggeredSpirit))) // Adding special effect at position of spirit
call RemoveUnit(triggeredSpirit) // Spirit explode at the end of spell
else
// If enemy unit is not a hero
call UnitDamageTarget(udg_IS_caster[curIndex], triggerUnit, udg_IS_dmgUnit[GetUnitAbilityLevel(udg_IS_caster[curIndex], udg_IS_abiUnitID[0])], false, false, udg_IS_dmgAttackType, udg_IS_dmgType, WEAPON_TYPE_WHOKNOWS)
endif
endif
endif
if udg_IS_nSpiritsCurrent[curIndex] == 0 then // If there are no Spirits left
call SpiritsDynamicIndex(curIndex) // Lowering index
endif
// fog is already nulled
set triggeredSpirit = null
set triggerUnit = null
endfunction
// ----------------------------------------------------------
function SpiritsManage takes nothing returns nothing
// This function is used to detect which ability is being used,
// to set/reset spell values
// to detect if unit is in range of spirit
local integer c // c; integer; counter, helper variable
local integer curIndex = 1 // curIndex; integer; counter, helper variable
local unit triggerUnit = GetTriggerUnit() // triggerUnit; unit; helper variable
// =========== Initializating spell values, 0.01s event =======================================
if udg_IS_maxIndex == -1 then // maxIndex is used as a helper variable
call SpiritsInitialization() // setting spell values
// =========== Ability being used is Spirits ==================================================
elseif GetSpellAbilityId() == udg_IS_abiUnitID[0] then
loop
exitwhen curIndex > udg_IS_maxIndex
if udg_IS_caster[curIndex] == triggerUnit then
call SpiritsEndSpell(curIndex) // Ending spell if activated before duration expire
endif
set curIndex = curIndex + 1
endloop
set udg_IS_maxIndex = udg_IS_maxIndex + 1 // Incereasing max index
// ========== Reseting spell values =======================================================
set udg_IS_caster[udg_IS_maxIndex] = triggerUnit // caster
set udg_IS_durTimer[udg_IS_maxIndex] = 0 // duration time
set udg_IS_angMove[udg_IS_maxIndex] = udg_IS_distAng[3] // angle of Spirits while moving
set udg_IS_distMove[udg_IS_maxIndex] = udg_IS_distOscMin // distance of Spirits while moving
set udg_IS_angCreate[udg_IS_maxIndex] = udg_IS_distAng[3] // angle of Spirits while created
set udg_IS_distCreate[udg_IS_maxIndex] = 0 // distance of Spirits while created
set udg_IS_distAngC[udg_IS_maxIndex] = (360 / udg_IS_nSpirits) // counts number of iterations
set udg_IS_distOscPushOut[udg_IS_maxIndex] = false // Push Out
set udg_IS_distOscPullIn[udg_IS_maxIndex] = false // Pull In
set udg_IS_nSpiritsCreated[udg_IS_maxIndex] = 1 // Number of created Spirits
set udg_IS_nSpiritsCurrent[udg_IS_maxIndex] = udg_IS_nSpirits // Current number of Spirits
set udg_SpiritCollisionTrigger[udg_IS_maxIndex] = CreateTrigger()
// Save curIndex inside trigger so we can retrieve data from fired trigger
call SaveInteger(udg_IS_spiritHash, GetHandleId(udg_SpiritCollisionTrigger[udg_IS_maxIndex]), 0, udg_IS_maxIndex)
call TriggerAddCondition(udg_SpiritCollisionTrigger[udg_IS_maxIndex], Condition(function SpiritCollision))
if udg_IS_maxIndex == 1 then // If only one hero is using the spell and is first to start
call TimerStart(udg_IS_perTimer, udg_IS_perTime, true, function SpiritsMove) // turn on periodic timer for SpiritsMove function
endif
// =========== Ability being used is Push Out =================================================
elseif GetSpellAbilityId() == udg_IS_abiUnitID[1] then
loop // Looping through units
exitwhen curIndex > udg_IS_maxIndex
if udg_IS_caster[curIndex] == triggerUnit then
if udg_IS_distMove[curIndex] == udg_IS_distOscMax then // If distance of oscillation is maximal:
set udg_IS_distOscPushOut[curIndex] = false // turn off Push Out
elseif udg_IS_distOscPushOut[curIndex] then // Sets Spirits oscillation distance at current if
set udg_IS_distOscPushOut[curIndex] = false // casted while pushing out
else
set udg_IS_distOscPullIn[curIndex] = false // Turn off Pull In
set udg_IS_distOscPushOut[curIndex] = true // Turn on Push Out
set udg_IS_distMove[curIndex] = udg_IS_distMove[curIndex] + udg_IS_distAng[1] // Incerease oscillation distance
endif
endif
set curIndex = curIndex + 1
endloop
// ========= Ability being used is Pull In ====================================================
elseif GetSpellAbilityId() == udg_IS_abiUnitID[2] then
loop // Looping through units
exitwhen curIndex > udg_IS_maxIndex
if udg_IS_caster[curIndex] == triggerUnit then
if udg_IS_distMove[curIndex] == udg_IS_distOscMin then // If distance of oscillation is minimal:
set udg_IS_distOscPullIn[curIndex] = false // turn off Pull In
elseif udg_IS_distOscPullIn[curIndex] then // Sets Spirits oscillation distance at current if
set udg_IS_distOscPullIn[curIndex] = false // casted while pulling in
else
set udg_IS_distOscPushOut[curIndex] = false // Turn off Push Out
set udg_IS_distOscPullIn[curIndex] = true // Turn on Pull In
set udg_IS_distMove[curIndex] = udg_IS_distMove[curIndex] - udg_IS_distAng[1] // Decrease oscillation distance
endif
endif
set curIndex = curIndex + 1
endloop
endif
set triggerUnit = null
endfunction
// ======================= Init Trigger Spirits Initialization =======================================================================
function InitTrig_Spirits takes nothing returns nothing
set gg_trg_Spirits = CreateTrigger()
call TriggerRegisterTimerEvent(gg_trg_Spirits, 0.01, false)
call TriggerRegisterAnyUnitEventBJ(gg_trg_Spirits, EVENT_PLAYER_UNIT_SPELL_EFFECT)
call TriggerAddCondition(gg_trg_Spirits, Condition(function SpiritsManage))
endfunction