scope HydroSpheres initializer init
globals
//RAWCODE STUFF
private constant integer Spell_ID = 'A002'
//rawcode of the spell
private constant integer Dummy_ID = 'e000'
//rawcode of the dummy unit
private constant integer Locust_ID = 'Aloc'
//rawcode of the locust spell
private constant integer Dummy_Height_Enabler = 'Amrf'
//allows modification of the dummy's flying height
private constant integer Hero_ID = 'H000'
//rawcode of the hero's normal form
private constant integer Avatar_ID = 'H001'
//rawcode of the hero's alternate form
//DAMAGE / MANA STUFF
private constant real DPS = 5.0
//starting damage per second
private constant real DPSinc = 1.0
//damage increases by this vaule per second
private constant real mana = 50.0
//mana drain when spheres detonate
private constant real manaInc = 0.0
//increase of mana drain per level (not used in the hero), put here for more config options
private constant real drain = 0.3
// % of mana restored to the hero (0,3 = 30%)
private constant real drainInc = 0.0
//increase of mana restored per level (not used in the hero), put here for more config options
//VISUAL STUFF
private constant integer spheres = 3
//starting number of spheres
private constant integer sInc = 1
//increase of spheres per level
private constant integer uInc = 2
//how many spheres are added (ultimate form)
private constant string mdlPath = "Abilities\\Weapons\\SpiritOfVengeanceMissile\\SpiritOfVengeanceMissile.mdl"
//model path of the spheres
private constant real rad = 125.0
//radius of the sphere circle
private constant real z = 30.0
//z height of the dummy unit
//ANIMATION STUFF
private constant real animTimer = 1.0
//duration of the animation
private constant string Anim = "spell"
//animation played
private constant integer A_red = 255
private constant integer A_green = 255
private constant integer A_blue = 255
private constant integer A_alpha = 95
//vaules for the RGBA colors of the avatar that appears
private constant real fdTime = 0.06
//fade timer period for the avatar
//MOVEMENT STUFF
private constant real mTimer = 0.025
//timer period for the movement of the spheres
private constant real dist = 25.0
//distance in WC3 units moved every mTimer period
private constant real aDist = 5.0
//angle in degrees moved every mTimer period
endglobals
//calculates damage per second
private constant function DamagePS takes integer time returns real
return DPS + DPSinc * time
endfunction
//calculates the mana drained according to level
private constant function Mana takes integer level returns real
return mana + manaInc * (level - 1)
endfunction
//calculates the mana restored according to level
private constant function Drain takes integer level returns real
return drain + drainInc * (level - 1)
endfunction
//calculates how many spheres are spawned
private function Spheres takes integer level, boolean ultimate returns integer
if ultimate == true then
return spheres + sInc * (level - 1) + uInc
else
return spheres + sInc * (level - 1)
endif
endfunction
//****************************************************************************************
//****************************************************************************************
//******************************* END OF SETUP SECTION ***********************************
//****************************************************************************************
//****************************************************************************************
globals
private Table Tab
endglobals
private struct Data
unit caster
unit target
unit avatar
unit dummy
boolean exists
integer counter
integer time
real t
real mn
real dr
integer array id [8190]
real x
real y
endstruct
private struct SData
effect sfx
unit dummy
real angl
method onDestroy takes nothing returns nothing
call DestroyEffect(sfx)
call KillUnit(dummy)
endmethod
endstruct
private struct FD
integer alpha
unit avt
static method create takes integer a, unit avt returns FD
local FD Fade = FD.allocate()
set Fade.alpha = a
set Fade.avt = avt
return Fade
endmethod
endstruct
//****************************************************************************************
private function Conditions takes nothing returns boolean
return GetSpellAbilityId()==Spell_ID
endfunction
//****************************************************************************************
private function FadeAvatar takes nothing returns nothing
local timer T = GetExpiredTimer()
local FD Fade = FD(GetTimerData(T))
set Fade.alpha = Fade.alpha - 5
if Fade.alpha == 0 then
call RemoveUnit(Fade.avt)
call Fade.destroy()
call ReleaseTimer(T)
else
call SetUnitVertexColor(Fade.avt, A_red, A_green, A_blue, Fade.alpha)
endif
endfunction
private function MLoop takes nothing returns nothing
local timer t = GetExpiredTimer()
local Data D = Data(GetTimerData(t))
local integer countMax = D.counter
local real dmg
local boolean du = false
local integer id
local SData SD
local real x = GetUnitX(D.dummy)
local real y = GetUnitY(D.dummy)
local real oX
local real oY
local real tX = GetUnitX(D.target)
local real tY = GetUnitY(D.target)
local real dX = tX - x
local real dY = tY - y
local real dbp = SquareRoot(dX * dX + dY * dY)
local real angl = Atan2(tY - y, tX - x)
if dbp <= dist + 20.0 then
call SetUnitX(D.dummy, tX)
call SetUnitY(D.dummy, tY)
set du = true
else
call SetUnitX(D.dummy, (x + dist * Cos(angl)))
call SetUnitY(D.dummy, (y + dist * Sin(angl)))
endif
set D.t = D.t + mTimer
loop
exitwhen D.counter == 0
set id = D.id[D.counter]
set SD = Tab[id]
set oX = GetUnitX(SD.dummy)
set oY = GetUnitY(SD.dummy)
set SD.angl = SD.angl + aDist
call SetUnitX(SD.dummy, (x + rad * Cos(SD.angl * bj_DEGTORAD)))
call SetUnitY(SD.dummy, (y + rad * Sin(SD.angl * bj_DEGTORAD)))
set D.counter = D.counter - 1
endloop
set D.counter = countMax
endfunction
private function Start takes nothing returns nothing
local timer T = GetExpiredTimer()
local Data D = Data(GetTimerData(T))
local FD Fade
local timer t
local timer mt = CreateTimer()
local location loc = Location(D.x, D.y)
local SData SD
local real x
local real y
local integer countMax
local unit u
if D.exists == true then
set Fade = FD.create(A_alpha, D.avatar)
set t = CreateTimer()
call SetTimerData(t, integer(Fade))
call TimerStart(t, fdTime, true, function FadeAvatar)
endif
set u = CreateUnitAtLoc(GetOwningPlayer(D.caster), Dummy_ID, loc, 0.0)
call UnitAddAbility(u, Locust_ID)
call UnitAddAbility(u, Dummy_Height_Enabler)
call UnitRemoveAbility(u, Dummy_Height_Enabler)
call SetUnitFlyHeight(u, z, 0)
set D.dummy = u
set countMax = D.counter
loop
exitwhen D.counter == 0
set x = D.x + rad * Cos(((360/countMax)*D.counter) * bj_DEGTORAD)
set y = D.y + rad * Sin(((360/countMax)*D.counter) * bj_DEGTORAD)
set loc = Location(x, y)
set SD = SData.create()
set SD.dummy = CreateUnitAtLoc(GetOwningPlayer(D.caster), Dummy_ID, loc, 0.0)
set SD.angl = ((360/countMax)*D.counter)
call UnitAddAbility(SD.dummy, Locust_ID)
call UnitAddAbility(SD.dummy, Dummy_Height_Enabler)
call UnitRemoveAbility(SD.dummy, Dummy_Height_Enabler)
call SetUnitFlyHeight(SD.dummy, z, 0)
set SD.sfx = AddSpecialEffectTarget(mdlPath, SD.dummy, "origin")
set Tab[GetHandleId(SD.dummy)]=integer(SD)
set D.id[D.counter]=GetHandleId(SD.dummy)
set D.counter = D.counter - 1
endloop
set D.counter = countMax
call SetTimerData(mt, integer(D))
call TimerStart(mt, mTimer, true, function MLoop)
call ReleaseTimer(T)
set t = null
set T = null
set mt = null
set u = null
endfunction
private function Actions takes nothing returns nothing
local unit caster = GetTriggerUnit()
local unit target = GetSpellTargetUnit()
local integer level = GetUnitAbilityLevel(caster, Spell_ID)
local unit A
local Data D = Data.create()
local timer t = CreateTimer()
set D.caster = caster
set D.target = target
set D.mn = Mana(level)
set D.dr = Drain(level)
set D.x = GetUnitX(caster)
set D.y = GetUnitY(caster)
if GetUnitTypeId(caster)==Hero_ID then
set D.counter = Spheres(level, false)
set A = CreateUnit(Player(PLAYER_NEUTRAL_PASSIVE), Avatar_ID, GetUnitX(caster), GetUnitY(caster), GetUnitFacing(caster))
call SetUnitColor(A, GetPlayerColor(GetOwningPlayer(caster)))
call SetUnitX(A, GetUnitX(caster))
call SetUnitY(A, GetUnitY(caster))
call UnitAddAbility(A, Locust_ID)
call SetUnitVertexColor(A, A_red, A_green, A_blue, A_alpha)
call SetUnitAnimation(A, Anim)
set D.avatar = A
set D.exists = true
call SetTimerData(t, integer(D))
call TimerStart(t, animTimer, false, function Start)
else
set D.counter = Spheres(level, true)
call SetTimerData(t, integer(D))
call TimerStart(t, 0.0, false, function Start)
endif
set t = null
set A = null
set caster = null
set target = null
endfunction
//****************************************************************************************
private function init takes nothing returns nothing
local trigger trig = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(trig, EVENT_PLAYER_UNIT_SPELL_EFFECT)
call TriggerAddCondition(trig, Condition(function Conditions))
call TriggerAddAction(trig, function Actions)
set Tab = Table.create()
set trig = null
endfunction
endscope