Permalink
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
87 lines (75 sloc) 2.92 KB
/**
* Dummy casters are commonly used in custom spells to cast abilities dynamically onto targets or points.
* For example hexing all units in an AoE, or impaling in multiple directions.
* If your spell's effect is entirely instant, you should use `InstantDummyCaster`.
* For many spells however, InstantDummyCaster is not feasible, because they
* - are of type impale or channel
* - attach effects to the caster, like chain lightning
* - deal delayed damage (fireball, shockwave)
* In all of these scenarios the unit has to stand in a place and the spell's effects are not instant.
*
* DummyCaster uses one dummy per cast, and only removes it after a set delay, to allow effects and damage to process
* Example with long delay for blizzard:
*
* new DummyCaster(casterPos)
* ..owner(caster)
* ..delay(15)
* ..castPoint('A000', 1, OrderIds.OrderIds.blizzard, target)
*
* The dummy caster will be recycled automatically, after the last spell's `delay` duration has expired.
* You shouldn't destroy the object yourself. Just cast any amount of spells at once or shortly after and leave it.
* Allocate DummyCasters dynamically on the spot and don't save them.
*/
package DummyCaster
import DummyRecycler
import MapBounds
import ClosureTimers
public class DummyCaster
private var delay = 5.0
private var castCount = 0
private var origin = ZERO2
private var owner = DUMMY_PLAYER
construct()
function origin(vec2 pos)
this.origin = pos
/** Sets the owner of the dummy */
function owner(player owner)
this.owner = owner
/** Delay after which the dummy is recycled. Increase this if your spell is longer.
Default 5 seconds. */
function delay(real delay)
this.delay = delay
function castImmediate(int abilityId, int lvl, int orderId) returns boolean
let dummy = prepare(abilityId, lvl)
let success = dummy.issueImmediateOrderById(orderId)
finish(dummy, abilityId)
return success
function castTarget(int abilityId, int lvl, int orderId, widget target) returns boolean
let dummy = prepare(abilityId, lvl)
dummy.setFacing(dummy.getPos().angleTo(target.getPos()))
let success = dummy.issueTargetOrderById(orderId, target)
finish(dummy, abilityId)
return success
function castPoint(int abilityId, int lvl, int orderId, vec2 targetPos) returns boolean
let dummy = prepare(abilityId, lvl)
dummy.setFacing(dummy.getPos().angleTo(targetPos))
let success = dummy.issuePointOrderById(orderId, targetPos)
finish(dummy, abilityId)
return success
private function prepare(int id, int lvl) returns unit
let dummy = DummyRecycler.get(origin, angle(0))
if origin.inBounds()
dummy.setXY(origin)
dummy..addAbility(id)..setMana(1000000)
if lvl > 1
dummy.setAbilityLevel(id, lvl)
dummy.setOwner(owner, false)
return dummy
private function finish(unit dummy, int id)
castCount++
doAfter(delay) ->
dummy..removeAbility(id)
DummyRecycler.recycle(dummy)
castCount--
if castCount == 0
destroy this