// CONFIGURATION
// Constants
// Main spell raw code
constant function AS_GetSpellID takes nothing returns integer
return 'A005'
endfunction
// Slow spell raw code
constant function AS_GetSlowID takes nothing returns integer
return 'A000'
endfunction
// Main caster dummy raw code
constant function AS_DummycasterID takes nothing returns integer
return 'h000'
endfunction
// Main projectile dummy raw code
constant function AS_DummyID takes nothing returns integer
return 'h002'
endfunction
// Main projectile death effect
constant function AS_Sfx takes nothing returns string
return "Abilities\\Weapons\\SentinelMissile\\SentinelMissile.mdl"
endfunction
// Blood effect
constant function AS_Sfx1 takes nothing returns string
return "Objects\\Spawnmodels\\Human\\HumanBlood\\BloodElfSpellThiefBlood.mdl"
endfunction
// Attachment point
constant function AS_AttachPoint takes nothing returns string
return "origin"
endfunction
// Order for the custom ability
constant function AS_DummyOrder takes nothing returns string
return "slow"
endfunction
// Movement interval
constant function AS_Interval takes nothing returns real
return 0.03125
endfunction
// Filter valid units
function AS_FilterUnit takes unit caster, unit u returns boolean
return IsUnitEnemy(u, GetOwningPlayer(caster)) and GetWidgetLife(u) > 0.405 and GetUnitAbilityLevel(u, 'Avul') == 0 and not IsUnitType (u, UNIT_TYPE_MAGIC_IMMUNE) and not IsUnitType (u, UNIT_TYPE_STRUCTURE)
endfunction
// Get Abilities Level
function AS_SpellLvl takes unit caster returns integer
return GetUnitAbilityLevel (caster, AS_GetSpellID()) // Get the spell level of the caster
endfunction
// Level dependable values
// Main target damage
function AS_Damage takes integer level returns real
return 100 + level*50.
endfunction
// Area of Effect
function AS_AoE takes integer level returns real
return 100 + level*10.
endfunction
// Distance travelled in 1 second
function AS_Speed takes integer level returns real
return 750. + level*100.
endfunction
// Attack - Damage - Weapon type
// Attack type
function AS_AttackType takes nothing returns attacktype
return ATTACK_TYPE_NORMAL
endfunction
// Damage type
function AS_DamageType takes nothing returns damagetype
return DAMAGE_TYPE_MAGIC
endfunction
// Weapon type
function AS_WeaponType takes nothing returns weapontype
return WEAPON_TYPE_METAL_MEDIUM_SLICE
endfunction
// Preload
function AS_Preload takes nothing returns nothing
local unit dummy = CreateUnit(Player(0), 'h000', 0, 0, 0.00)
call UnitAddAbility(dummy, AS_GetSpellID())
call UnitAddAbility(dummy, AS_GetSlowID())
call RemoveUnit (dummy)
set dummy = null
endfunction
// END CONFIGURATION
// SPELL FUNCTIONS
// This is the main function of the spell
function AS_TimerLoop takes nothing returns nothing
local integer ID
local integer listmax = LoadInteger(udg_AS_Hashtable, -1, 0 )
local unit caster
local unit dummyProjectile0
local unit dummyProjectile1
local unit dummyCaster
local integer i = 0
local real x1
local real y1
local real x2
local real y2
local unit u
local integer level
local group enumGroup
local group tempGroup0
local group tempGroup1
local real t
// Now we start looping through all the spell instances
loop
exitwhen i >= listmax
// First we load the saved values of a spell instance
set i = i + 1
set ID = LoadInteger(udg_AS_Hashtable, -1, i)
set caster = LoadUnitHandle(udg_AS_Hashtable, ID, 1)
set dummyProjectile0 = LoadUnitHandle(udg_AS_Hashtable, ID, 2)
set dummyProjectile1 = LoadUnitHandle(udg_AS_Hashtable, ID, 9)
set dummyCaster = LoadUnitHandle(udg_AS_Hashtable, ID, 7)
set t = LoadReal(udg_AS_Hashtable, ID, 5)
set x1 = GetUnitX(caster)
set y1 = GetUnitY(caster)
set x2 = LoadReal (udg_AS_Hashtable, ID, 3)
set y2 = LoadReal (udg_AS_Hashtable, ID, 4)
set level = AS_SpellLvl(caster)
set tempGroup0 = LoadGroupHandle(udg_AS_Hashtable, ID, 6)
set tempGroup1 = LoadGroupHandle(udg_AS_Hashtable, ID, 10)
if t >= bj_PI then
call KillUnit (dummyProjectile0)
call KillUnit (dummyProjectile1)
call KillUnit (dummyCaster)
call DestroyGroup(tempGroup0)
call DestroyGroup(tempGroup1)
call DestroyEffect (AddSpecialEffect(AS_Sfx(), x1, y1))
if listmax != i then
call SaveInteger(udg_AS_Hashtable, LoadInteger(udg_AS_Hashtable, -1, listmax), 0, i)
call SaveInteger(udg_AS_Hashtable, -1, i, LoadInteger(udg_AS_Hashtable, -1, listmax))
call RemoveSavedInteger(udg_AS_Hashtable, -1, listmax)
set i = i - 1
endif
set listmax = listmax - 1
call SaveInteger(udg_AS_Hashtable, -1, 0, listmax)
if LoadInteger(udg_AS_Hashtable, 0, 0) + 1 == LoadInteger(udg_AS_Hashtable, 0, -1) then
call FlushChildHashtable(udg_AS_Hashtable, 0)
call PauseTimer(LoadTimerHandle(udg_AS_Hashtable, -2, 0))
else
call SaveInteger (udg_AS_Hashtable, 0, 0, LoadInteger(udg_AS_Hashtable, 0, 0) + 1)
call SaveInteger(udg_AS_Hashtable, 0, LoadInteger(udg_AS_Hashtable, 0, 0), ID)
endif
call FlushChildHashtable(udg_AS_Hashtable, ID)
else
if IsUnitType(caster, UNIT_TYPE_DEAD) then
call KillUnit (dummyProjectile0)
call KillUnit (dummyProjectile1)
call KillUnit (dummyCaster)
call DestroyGroup(tempGroup0)
call DestroyGroup(tempGroup1)
call DestroyEffect (AddSpecialEffect(AS_Sfx(), x1, y1))
if listmax != i then
call SaveInteger(udg_AS_Hashtable, LoadInteger(udg_AS_Hashtable, -1 ,listmax), 0, i)
call SaveInteger(udg_AS_Hashtable, -1, i, LoadInteger(udg_AS_Hashtable, -1, listmax))
call RemoveSavedInteger(udg_AS_Hashtable, -1, listmax)
set i = i - 1
endif
set listmax = listmax - 1
call SaveInteger(udg_AS_Hashtable, -1, 0, listmax)
if LoadInteger(udg_AS_Hashtable, 0, 0) + 1 == LoadInteger(udg_AS_Hashtable, 0, -1) then
call FlushChildHashtable(udg_AS_Hashtable, 0)
call PauseTimer(LoadTimerHandle(udg_AS_Hashtable, -2, 0))
else
call SaveInteger (udg_AS_Hashtable, 0, 0, LoadInteger(udg_AS_Hashtable, 0, 0) + 1)
call SaveInteger(udg_AS_Hashtable, 0, LoadInteger(udg_AS_Hashtable, 0, 0), ID)
endif
call FlushChildHashtable(udg_AS_Hashtable, ID)
else
// Move the projectiles, dealing damage and slowing enemies around
call SetUnitX(dummyProjectile0, (x2-x1)*Sin(t) + 0.25*(y2-y1)*Sin(2*t) + x1)
call SetUnitY(dummyProjectile0, (y2-y1)*Sin(t) + 0.25*(x1-x2)*Sin(2*t) + y1)
call SetUnitX(dummyProjectile1, (x2-x1)*Sin(t) - 0.25*(y2-y1)*Sin(2*t) + x1)
call SetUnitY(dummyProjectile1, (y2-y1)*Sin(t) - 0.25*(x1-x2)*Sin(2*t) + y1)
set enumGroup = CreateGroup()
call GroupEnumUnitsInRange(enumGroup, GetUnitX(dummyProjectile0), GetUnitY(dummyProjectile0), AS_AoE(level), null)
loop
set u = FirstOfGroup(enumGroup)
exitwhen u == null
if AS_FilterUnit(caster, u) and not IsUnitInGroup(u, tempGroup0) then
call UnitDamageTarget(caster, u, AS_Damage(level), false, false, AS_AttackType(), AS_DamageType(), AS_WeaponType())
call DestroyEffect (AddSpecialEffectTarget(AS_Sfx(), u, AS_AttachPoint()))
call DestroyEffect (AddSpecialEffectTarget(AS_Sfx1(), u, AS_AttachPoint()))
call SetUnitX(dummyCaster, GetUnitX(u))
call SetUnitY(dummyCaster, GetUnitY(u))
call SetUnitAbilityLevel(dummyCaster, AS_GetSlowID(), level)
call IssueTargetOrder(dummyCaster, AS_DummyOrder(), u)
call GroupAddUnit(tempGroup0, u)
endif
call GroupRemoveUnit (enumGroup, u)
endloop
call GroupEnumUnitsInRange(enumGroup, GetUnitX(dummyProjectile1), GetUnitY(dummyProjectile1), AS_AoE(level), null)
loop
set u = FirstOfGroup(enumGroup)
exitwhen u == null
if AS_FilterUnit(caster, u) and not IsUnitInGroup(u, tempGroup1) then
call UnitDamageTarget(caster, u, AS_Damage(level), false, false, AS_AttackType(), AS_DamageType(), AS_WeaponType())
call DestroyEffect (AddSpecialEffectTarget(AS_Sfx(), u, AS_AttachPoint()))
call DestroyEffect (AddSpecialEffectTarget(AS_Sfx1(), u, AS_AttachPoint()))
call SetUnitX(dummyCaster, GetUnitX(u))
call SetUnitY(dummyCaster, GetUnitY(u))
call SetUnitAbilityLevel(dummyCaster, AS_GetSlowID(), level)
call IssueTargetOrder(dummyCaster, AS_DummyOrder(), u)
call GroupAddUnit(tempGroup1, u)
endif
call GroupRemoveUnit (enumGroup, u)
endloop
call DestroyGroup(enumGroup)
set enumGroup = null
set t = t + (AS_Speed(level)/((1/AS_Interval())*LoadReal(udg_AS_Hashtable, ID, 8)))*bj_PI
call SaveReal(udg_AS_Hashtable, ID, 5, t)
endif
endif
set caster = null
set dummyProjectile0 = null
set dummyProjectile1 = null
set tempGroup0 = null
set tempGroup1 = null
set dummyCaster = null
endloop
endfunction
// Initiate function
function Trig_AS_Conditions takes nothing returns boolean
local unit caster
local integer ID
local integer listmax
local real x1
local real y1
local real x2
local real y2
local real angle
local player owner
if GetSpellAbilityId() == AS_GetSpellID() then
set caster = GetTriggerUnit()
set x1 = GetUnitX(caster)
set y1 = GetUnitY(caster)
set x2 = GetSpellTargetX()
set y2 = GetSpellTargetY()
set angle = Atan2(y2-y1, x2-x1)*bj_RADTODEG
set owner = GetTriggerPlayer()
set ID = LoadInteger(udg_AS_Hashtable, 0, 0)
// Now we start indexing the spell
if ID>0 then
call SaveInteger(udg_AS_Hashtable, 0, 0, ID - 1)
set ID = LoadInteger (udg_AS_Hashtable, 0, ID)
else
set ID = LoadInteger(udg_AS_Hashtable, 0, -1) + 1
call SaveInteger(udg_AS_Hashtable,0 ,-1, ID)
if ID == 1 then
call TimerStart (LoadTimerHandle(udg_AS_Hashtable, -2, 0), AS_Interval(), true, function AS_TimerLoop)
endif
endif
// Save the values related to this spell instance
call SaveUnitHandle(udg_AS_Hashtable, ID, 1, caster)
call SaveUnitHandle(udg_AS_Hashtable, ID, 2, CreateUnit(owner, AS_DummyID(), x1, y1, angle))
call SaveUnitHandle(udg_AS_Hashtable, ID, 9, CreateUnit(owner, AS_DummyID(), x1, y1, angle))
call SaveReal(udg_AS_Hashtable, ID, 3, x2)
call SaveReal(udg_AS_Hashtable, ID, 4, y2)
call SaveReal(udg_AS_Hashtable, ID, 5, 0)
call SaveGroupHandle(udg_AS_Hashtable, ID, 6, CreateGroup())
call SaveGroupHandle(udg_AS_Hashtable, ID, 10, CreateGroup())
call SaveUnitHandle(udg_AS_Hashtable, ID, 7, CreateUnit(owner, AS_DummycasterID(), x1, y1, angle))
call UnitAddAbility (LoadUnitHandle(udg_AS_Hashtable, ID, 7), AS_GetSlowID())
if (x2-x1)*(x2-x1) + (y2-y1)*(y2-y1) == 0 then
call SaveReal(udg_AS_Hashtable, ID, 8, 1)
else
call SaveReal(udg_AS_Hashtable, ID, 8, SquareRoot((x2-x1)*(x2-x1) + (y2-y1)*(y2-y1)))
endif
set listmax = LoadInteger (udg_AS_Hashtable, -1, 0) + 1
call SaveInteger (udg_AS_Hashtable, -1, 0, listmax )
call SaveInteger (udg_AS_Hashtable, -1, listmax, ID)
call SaveInteger (udg_AS_Hashtable, ID, 0, listmax)
set caster = null
set owner = null
endif
return false
endfunction
//===========================================================================
function InitTrig_Arcing_Shuriken takes nothing returns nothing
local trigger t = CreateTrigger()
set udg_AS_Hashtable = InitHashtable ()
call AS_Preload()
call SaveTimerHandle (udg_AS_Hashtable, -2, 0, CreateTimer())
call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_SPELL_EFFECT)
call TriggerAddCondition(t, Condition( function Trig_AS_Conditions ) )
set t = null
endfunction