// ==================================
// Spawn Projectiles as units
function SpawnUnitProjectile_Update takes nothing returns nothing
local timer t = GetExpiredTimer()
local real speed = GetHandleReal(t, "speed")
local unit projectile = GetHandleUnit(t, "projectile")
local widget target = GetHandleUnit(t, "target")
local real dx = GetWidgetX(target) - GetUnitX(projectile)
local real dy = GetWidgetY(target) - GetUnitY(projectile)
local real angle = Atan2(dy, dx)
local trigger trg = GetHandleTrigger(t, "trg")
if ( target == null ) then // Target might die before we hit it
// This is a cheap solution though...
call KillUnit(projectile)
call FlushHandleLocals(t)
call DestroyTimer(t)
call FlushHandleLocals(trg)
call DestroyTrigger(trg)
return
endif
if ( dx*dx+dy*dy <= speed*speed ) then // See if the target is hit
// Projectile hit!
call KillUnit(projectile) // Get rid of arrow/fireball/etc
if ( trg != null ) then
call TriggerExecute(trg) // Deal the damage and stuff
endif
call FlushHandleLocals(t) // Clean up
call DestroyTimer(t) // Stop loop
return
endif
call SetUnitX(projectile, GetUnitX(projectile)+Cos(angle)*speed)
call SetUnitY(projectile, GetUnitY(projectile)+Sin(angle)*speed)
call SetUnitFacing(projectile, angle*bj_RADTODEG)
endfunction
function SpawnUnitProjectile takes integer unitid, real x, real y, widget target, real speed returns trigger
local real angle = Atan2(GetUnitY(target)-y, GetUnitX(target)-x)*bj_RADTODEG)
local unit projectile = CreateUnit(Player(PLAYER_NEUTRAL_PASSIVE), unitid, x, y, angle)
local timer t = CreateTimer()
local trigger whenHit = CreateTrigger()
local real update = 0.05 // Update interval
call SetHandleHandle(t, "target", target)
call SetHandleHandle(t, "projectile", projectile)
call SetHandleReal(t, "speed", speed*update)
call UnitAddAbility(projectile, 'Aloc') // Make unselectable
call SetUnitInvulnerable(projectile, true) // Make untargetable
call TimerStart(t, update, true, function SpawnUnitProjectile_Update)
return whenHit
endfunction
// ==================================
// Simulate poison arrows
function CastPoisonArrow_Update takes nothing returns nothing
local timer t = GetExpiredTimer()
local integer duration = GetHandleInt(t, "duration") - 1
local unit caster = GetHandleUnit(t, "caster")
local unit target = GetHandleUnit(t, "target")
local real dmg = GetHandleReal(t, "dmg")
call UnitDamageTarget(caster, target, dmg, false, true, ATTACK_TYPE_MAGIC, DAMAGE_TYPE_POISON, WEAPON_TYPE_WHOKNOWS)
if ( duration <= 0 or target == null) then
call FlushHandleLocals(t)
call DestroyTimer(t)
return
endif
call SetHandleInt(t, "duration", duration)
endfunction
function CastPoisonArrow_Start takes nothing returns nothing
local trigger trg = GetTriggeringTrigger()
local unit caster = GetHandleUnit(trg, "caster")
local unit target = GetHandleUnit(trg, "target")
local real dmgInitial = GetHandleReal(trg, "dmgInitial")
local timer t = CreateTimer()
local real update = 0.5
call UnitDamageTarget(caster, target, dmgInitial, false, true, ATTACK_TYPE_MAGIC, DAMAGE_TYPE_POISON, WEAPON_TYPE_WHOKNOWS)
call SetHandleHandle(t, "caster", caster)
call SetHandleHandle(t, "target", target)
call SetHandleReal(t, "dmg", GetHandleReal(trg, "dmgPerSec")*update)
call SetHandleInt(t, "duration", R2I(GetHandleReal(trg, "duration")/update))
call TimerStart(t, update, true, CastPoisonArrow_Update)
call FlushHandleLocals(trg)
call DestroyTrigger(trg)
endfunction
function CastPoisonArrow takes unit caster, unit target, real dmgInitial, real dmgPerSec, real duration returns nothing
local trigger t = SpawnUnitProjectile('h000', GetUnitX(caster), GetUnitY(caster), target, 1000)
call TriggerAddAction(t, function CastPoisonArrow_Start)
call SetHandleHandle(t, "caster", caster)
call SetHandleHandle(t, "target", target)
call SetHandleReal(t, "dmgInitial", dmgInitial)
call SetHandleReal(t, "dmgPerSec", dmgPerSec)
call SetHandleReal(t, "duration", duration)
endfunction