scope Armageddon initializer init
globals
//******
//* Configuration
//* -------------
//*
public constant integer ABIL_ID = 'AOws'
//*
//*
public constant real DURATION = 15.00
public constant real EFFECT_RADIUS = 750.00
public constant real DAMAGE_RADIUS = 300.00
//*
public constant real METEOR_INITIAL_HEIGHT = 1000.00
public constant real METEOR_DELAY = 2
public constant real METEOR_VELOCITY = 250.00
//*
public constant real METEOR_ANGLE = bj_PI //measured in radians
//*
//*************************************
private location tempLoc = Location(0,0)
endglobals
struct s_armageddon_meteor
s_armageddon parentspell
unit object = null
effect objectmodel = null
real targetx
real targety
real targetz
real x
real y
real z
real zstart
integer index
static timer stackRefresh = CreateTimer()
static constant real stackRefreshPeriod = 0.025
static thistype array stack
static integer n = 0
method onDestroy takes nothing returns nothing
set thistype.n=thistype.n-1
set thistype.stack[this.index]=thistype.stack[thistype.n]
set thistype.stack[this.index].index=this.index
call KillUnit(this.object)
call DestroyEffect(this.objectmodel)
endmethod
method onStrike takes nothing returns nothing
endmethod
static method onRefresh takes nothing returns nothing
local integer i
local thistype dat
set i=thistype.n-1
loop
exitwhen (i<0)
set dat=thistype.stack[i]
if (dat!=0) then
set dat.x =dat.x+(METEOR_VELOCITY*thistype.stackRefreshPeriod)*Cos(METEOR_ANGLE)
set dat.y =dat.y+(METEOR_VELOCITY*thistype.stackRefreshPeriod)*Sin(METEOR_ANGLE)
set dat.z =dat.z - ((dat.zstart-dat.targetz)/METEOR_DELAY)*thistype.stackRefreshPeriod
call SetUnitX(dat.object, dat.x)
call SetUnitY(dat.object, dat.y)
call MoveLocation(tempLoc, dat.x, dat.y)
call SetUnitFlyHeight(dat.object, dat.z-GetLocationZ(tempLoc), 0)
if (dat.z<GetLocationZ(tempLoc)) then
call dat.onStrike()
call dat.destroy()
endif
endif
set i=i-1
endloop
endmethod
static method create takes s_armageddon parentspell returns thistype
local thistype dat=thistype.allocate()
local real r
local real th
local real x
local real y
set dat.parentspell=parentspell
set dat.index=thistype.n
set thistype.stack[thistype.n]=dat
set thistype.n=thistype.n+1
//*** Random point within the area of effect ***
set r = GetRandomInt(0, R2I(EFFECT_RADIUS))
set th = GetRandomReal(0, 360)
set x = GetUnitX(parentspell.abilcaster) + (r*Cos(th*bj_DEGTORAD))
set y = GetUnitY(parentspell.abilcaster) + (r*Sin(th*bj_DEGTORAD))
set dat.targetx=x
set dat.targety=y
call MoveLocation(tempLoc, dat.targetx, dat.targety)
set dat.targetz=GetLocationZ(tempLoc)
set dat.x = x+(METEOR_VELOCITY*METEOR_DELAY)*Cos(METEOR_ANGLE-bj_PI)
set dat.y = y+(METEOR_VELOCITY*METEOR_DELAY)*Sin(METEOR_ANGLE-bj_PI)
call MoveLocation(tempLoc, dat.x, dat.y)
set dat.z = GetLocationZ(tempLoc)+METEOR_INITIAL_HEIGHT
set dat.zstart=dat.z
set dat.object=CreateUnit(GetOwningPlayer(parentspell.abilcaster), dummyCasterId, dat.x, dat.y, METEOR_ANGLE*bj_RADTODEG)
set dat.objectmodel=AddSpecialEffectTarget(GetAbilityEffectById(ABIL_ID, EFFECT_TYPE_SPECIAL, 0), dat.object, "origin")
call SetUnitX(dat.object, dat.x)
call SetUnitY(dat.object, dat.y)
call UnitAddAbility(dat.object, 'Amrf')
call UnitRemoveAbility(dat.object, 'Amrf')
call SetUnitFlyHeight(dat.object, METEOR_INITIAL_HEIGHT, 0)
return dat
endmethod
static method onInit takes nothing returns nothing
//** Initialize timer to update motion of meteors
call TimerStart(thistype.stackRefresh, thistype.stackRefreshPeriod, true, function thistype.onRefresh)
endmethod
endstruct
struct s_armageddon
unit abilcaster = null
integer abillevel
timer abilrefresh = CreateTimer()
real time = 0.00
static hashtable spellData = InitHashtable()
static constant real refreshLapse = 1.0
method onDestroy takes nothing returns nothing
call RemoveSavedInteger(thistype.spellData, GetHandleId(this.abilrefresh), 1)
call PauseTimer(this.abilrefresh)
call DestroyTimer(this.abilrefresh)
endmethod
static method onInterval takes nothing returns nothing
local thistype spelldata=LoadInteger(thistype.spellData, GetHandleId(GetExpiredTimer()), 1)
local integer i
set spelldata.time=spelldata.time+thistype.refreshLapse
set i=0
loop
exitwhen (i==6)
call s_armageddon_meteor.create(spelldata)
set i=i+1
endloop
if spelldata.time>DURATION then
call spelldata.destroy()
endif
endmethod
static method create takes unit caster, integer level returns thistype
local thistype spelldata=thistype.allocate()
set spelldata.abilcaster=caster
set spelldata.abillevel=level
call SaveInteger(thistype.spellData, GetHandleId(spelldata.abilrefresh), 1, spelldata)
call TimerStart(spelldata.abilrefresh, thistype.refreshLapse, true, function thistype.onInterval)
return spelldata
endmethod
endstruct
private function abilEffect takes nothing returns nothing
call s_armageddon.create(GetTriggerUnit(), 1)
endfunction
private function abilFilter takes nothing returns boolean
return GetSpellAbilityId()==ABIL_ID
endfunction
public function init takes nothing returns nothing
local trigger t=CreateTrigger()
local integer i=0
loop
exitwhen (i==16)
call TriggerRegisterPlayerUnitEvent(t, Player(i), EVENT_PLAYER_UNIT_SPELL_EFFECT, null)
set i=i+1
endloop
call TriggerAddCondition(t, Filter(function abilFilter))
call TriggerAddAction(t, function abilEffect)
endfunction
endscope