scope Test
//native UnitAlive takes unit u returns boolean
globals
private constant integer SPELL_ID = 'A000'
private constant integer MISS_ID = 'M000'
private constant real ANGLE /*In radian*/ = bj_PI/4
private constant integer OFFSET = 200
private constant real FPS = 0.0312500
private constant real SPEED = 500.
private constant real DISTANCE =500.
private constant real AOE = 200.
private constant attacktype A_TYPE = ATTACK_TYPE_MAGIC
private constant damagetype D_TYPE = DAMAGE_TYPE_MAGIC
endglobals
private constant function Damage takes integer level returns real
return 60.*level
endfunction
private struct Dummy extends array
unit targ
real temp
thistype prev
thistype next
static integer count
static group g
static timer period
method destroy takes nothing returns nothing
if this.next != 0 then
set this.next.prev = this.prev
endif
set this.prev.next = this.next
call GroupRemoveUnit(g, this.targ)
set this.targ = null
set this.prev = thistype(0).prev
set thistype(0).prev = this
if thistype(0).next == 0 then
call PauseTimer(period)
endif
endmethod
static method periodic takes nothing returns nothing
local thistype this = thistype(0).next
loop
exitwhen this == 0
set this.temp = this.temp - FPS
if this.temp <= 0 then
call this.destroy()
endif
set this = this.next
endloop
endmethod
static method is takes unit u returns boolean
return IsUnitInGroup(u,g)
endmethod
static method add takes unit u, real r returns nothing
local thistype this
if thistype(0).prev == 0 then
set count = count + 1
set this = count
else
set this = thistype(0).prev
set thistype(0).prev = thistype(0).prev.prev
endif
if thistype(0).next == 0 then
call TimerStart(period, FPS, true, function thistype.periodic)
else
set thistype(0).next.prev = this
endif
set this.next = thistype(0).next
set thistype(0).next = this
set this.prev = thistype(0)
set this.targ = u
set this.temp = r
call GroupAddUnit(g, u)
endmethod
static method onInit takes nothing returns nothing
set count = 0
set g = CreateGroup()
set period = CreateTimer()
endmethod
endstruct
private struct Core extends array
unit missile
unit caster
real dmg
real X
real Y
integer steps
thistype prev
thistype next
static timer period
static integer count
static group g
method destroy takes nothing returns nothing
if this.next != 0 then
set this.next.prev = this.prev
endif
set this.prev.next = this.next
set this.missile = null
set this.caster = null
set this.prev = thistype(0).prev
set thistype(0).prev = this
if thistype(0).next == 0 then
call PauseTimer(period)
endif
endmethod
static method periodic takes nothing returns nothing
local thistype this = thistype(0).next
local unit u
local real x
local real y
local player p
loop
exitwhen this == 0
set x = GetUnitX(this.missile)+this.X
set y = GetUnitY(this.missile)+this.Y
call SetUnitX(this.missile, x)
call SetUnitY(this.missile, y)
set p = GetOwningPlayer(this.missile)
call GroupEnumUnitsInRange(g, x, y, AOE, null)
loop
set u = FirstOfGroup(g)
exitwhen u == null
call GroupRemoveUnit(g,u)
if IsUnitEnemy(u, p) and UnitAlive(u) then
call UnitDamageTarget(this.caster, u, this.dmg, true, false, A_TYPE, D_TYPE, null)
call Dummy.add(u,1)
endif
endloop
set this.steps = this.steps - 1
if this.steps == 0 then
call this.destroy()
endif
set this = this.next
endloop
set p = null
endmethod
static method cond takes nothing returns boolean
local thistype this
local real x
local real y
local real tx
local real ty
local integer lvl
local integer i
local unit u
local player p
local real angle
if GetSpellAbilityId() == SPELL_ID then
set i = 0
set u = GetTriggerUnit()
set x = GetUnitX(u)
set y = GetUnitY(u)
set tx = GetSpellTargetX()
set ty = GetSpellTargetY()
set angle = Atan2(ty-y, tx-x) - ANGLE
set lvl = GetUnitAbilityLevel(u, SPELL_ID)
set p = GetOwningPlayer(u)
loop
exitwhen i>3
if thistype(0).prev == 0 then
set count = count + 1
set this = count
else
set this = thistype(0).prev
set thistype(0).prev = thistype(0).prev.prev
endif
if thistype(0).next == 0 then
call TimerStart(period, FPS, true, function thistype.periodic)
else
set thistype(0).next.prev = this
endif
set this.next = thistype(0).next
set thistype(0).next = this
set this.prev = thistype(0)
set this.caster = u
set this.dmg = Damage(lvl)
set this.missile = CreateUnit(p, MISS_ID, x+OFFSET*Cos(angle), y+OFFSET*Sin(angle), angle)
set this.X = FPS*SPEED*Cos(angle)
set this.Y = FPS*SPEED*Sin(angle)
set this.steps = R2I(DISTANCE/SPEED/FPS)
set angle = angle + ANGLE
set i = i + 1
endloop
set u = null
set p = null //Safety is costless
endif
return false
endmethod
static method onInit takes nothing returns nothing
local trigger t = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_SPELL_EFFECT)
call TriggerAddCondition(t, Condition(function thistype.cond))
set period = CreateTimer()
set g = CreateGroup()
set count = 0
set t =null
endmethod
endstruct
endscope