- Joined
- Jul 10, 2007
- Messages
- 6,306
3 kilobytes per spawn; avg footmen wars map of 17 dif spawn types would have 50kb or so worth of spawns
Cool demo
JASS:
library SimpleSpawn /* v1.0.0.4
*************************************************************************************
*
* Handles simple spawning
*
* - one type of unit gets one type of spawn per SimpleSpawn
* - constant spawn time
* - constant spawn count
* - self managing
* - adds/removes spawns as units are created/destroyed
* - adds/removes spawns as units are upgraded
*
*************************************************************************************
*
* */uses/*
*
* */ TQ /* hiveworkshop.com/forums/jass-functions-413/system-timerqueue-187502/
* */ optional Table /* hiveworkshop.com/forums/jass-functions-413/snippet-new-table-188084/
* */ UnitIndexer /* hiveworkshop.com/forums/jass-functions-413/system-unit-indexer-172090/
* */ UnitEvent /* hiveworkshop.com/forums/jass-functions-413/extension-unit-event-172365/
*
************************************************************************************
*
* SETTINGS
*/
globals
/*************************************************************************************
*
* DYNAMIC
*
* If this is true, changing a unit's type via abilities will properly update the spawn.
*
* - Table is required if this is enabled
*
*************************************************************************************/
private constant boolean DYNAMIC = true
endglobals
/*
************************************************************************************
*
* Example
*
* struct Barracks extends array
* private static constant real INTERVAL = 6 //6 interval spawn time
* private static constant integer ORIGIN = 'hbar' //barracks
* private static constant integer SPAWN = 'hfoo' //footman
* private static constant integer COUNT = 2 //count
*
* implement LightSpawn
* endstruct
*
************************************************************************************/
globals
private trigger tt = CreateTrigger()
private trigger tt2 = CreateTrigger()
private trigger tt3 = CreateTrigger()
endglobals
static if DYNAMIC then
//dynamic will evaluate a trigger that generates a spawn given an origin
//this way spawns can be updated on the fly
//only useful if working with changing abilities like chaos, avatar, hex that effect
//spawners
private module Init
public static timer c //clean up timer
public static Table t //trigger table
public static Table h //timer table
public static integer i = 0 //unit pointer
public static integer o = 0 //unit type id
public static real r = 0 //timeout
public static real array l //largest remaining time
private static method onInit takes nothing returns nothing
set t = Table.create()
set h = Table.create()
set c = CreateTimer()
endmethod
endmodule
endif
private module Init2
private static method onInit takes nothing returns nothing
//upgrade trigger registration
local integer i = 15
loop
call TriggerRegisterPlayerUnitEvent(tt, Player(i), EVENT_PLAYER_UNIT_UPGRADE_START, null)
call TriggerRegisterPlayerUnitEvent(tt2, Player(i), EVENT_PLAYER_UNIT_UPGRADE_CANCEL, null)
call TriggerRegisterPlayerUnitEvent(tt3, Player(i), EVENT_PLAYER_UNIT_UPGRADE_FINISH, null)
exitwhen i == 0
set i = i - 1
endloop
endmethod
endmodule
private struct D extends array
implement optional Init
implement Init2
endstruct
static if DYNAMIC then
private function C takes nothing returns nothing
//simply cleans up the spawn unit type id (stops multiple trigger evaluations)
//has to be cleaned on a timer
set D.o = 0
set D.i = 0
set D.r = 0
endfunction
endif
module LightSpawn
private static unit array u //unit
private static integer array p //timer by unit
static if DYNAMIC then
//spawn trigger registration
private static method r2 takes nothing returns nothing
local integer t = GetHandleId(GetExpiredTimer())
local integer i = GetUnitUserData(D.h.unit[t])
local integer c
set D.h.unit[t] = null
call DestroyTimer(GetExpiredTimer())
if (GetUnitTypeId(GetUnitById(i)) == ORIGIN) then
set t = allocate()
set c = COUNT
set p[i] = t
set u[t] = GetUnitById(i)
loop
exitwhen c == 0
call CreateUnit(GetOwningPlayer(u[t]), SPAWN, GetUnitX(u[t]), GetUnitY(u[t]), GetUnitFacing(u[t]))
set c = c - 1
endloop
endif
endmethod
private static method rs takes nothing returns boolean
local timer t
local integer i = D.i
local real r = INTERVAL-D.r //remaining time on new spawn
local integer c = COUNT
//the reason remaining time is so important is that the origin could have changed at any
//point during the interval
//origin changes are only checked at the end of each interval
//loop until the remaining time is > 0
loop
exitwhen r > 0
loop
exitwhen c == 0
call CreateUnit(GetOwningPlayer(GetUnitById(i)), SPAWN, GetUnitX(GetUnitById(i)), GetUnitY(GetUnitById(i)), GetUnitFacing(GetUnitById(i)))
set c = c - 1
endloop
set r = r + INTERVAL
endloop
//start up a timer using remainnig time and then send to the timer queue
static if DYNAMIC then
if (INTERVAL > D.l[i]) then
set D.l[i] = INTERVAL
endif
endif
set t = CreateTimer()
call TimerStart(t, r, false, function thistype.r2)
set D.h.unit[GetHandleId(t)] = GetUnitById(i)
set t = null
return false
endmethod
endif
method expire takes nothing returns nothing
local integer c = COUNT
static if DYNAMIC then
local integer i
local integer id = GetUnitTypeId(u[this])
//if the unit type id isn't the origin, then it was changed via an ability
//and needs to be updated
if (id == ORIGIN) then
loop
exitwhen c == 0
call CreateUnit(GetOwningPlayer(u[this]), SPAWN, GetUnitX(u[this]), GetUnitY(u[this]), GetUnitFacing(u[this]))
set c = c - 1
endloop
else
//deallocate it
set i = GetUnitUserData(u[this])
call TQ_D(this)
set u[this] = null
set p[i] = 0
//if the trigger wasn't already evaluated for this unit, evaluate it
//use unit type id, not pointer id***. A unit may be changed multiple times
//before the timer runs
if (D.o != id and D.i != i) then
set D.i = i
set D.o = id
set D.r = D.l[i]
set D.l[i] = 0
call TriggerEvaluate(D.t.trigger[id])
call TimerStart(D.c, 0, false, function C)
endif
endif
else
//without dynamics, just create the unit like normal
loop
exitwhen c == 0
call CreateUnit(GetOwningPlayer(u[this]), SPAWN, GetUnitX(u[this]), GetUnitY(u[this]), GetUnitFacing(u[this]))
set c = c - 1
endloop
endif
endmethod
//this uses a timer queue as otherwise an origin will more than likely spawn too soon on the
//first spawn
implement TQ
private static method index takes nothing returns boolean
//on index, allocate a timer for the unit
local integer t //timer
local integer i = GetIndexedUnitId() //indexed unit id
if (GetUnitTypeId(GetUnitById(i)) == ORIGIN) then
set t = allocate() //allocate timer
set u[t] = GetUnitById(i) //store indexed unit in timer
set p[i] = t //store timer in unit
static if DYNAMIC then
if (INTERVAL > D.l[i]) then
set D.l[i] = INTERVAL
endif
endif
endif
return false
endmethod
private static method deindex takes nothing returns boolean
//on deindex, deallocate timer for unit
local integer i = GetIndexedUnitId()
local integer t = p[i] //timer
if (t != 0) then
set p[i] = 0
set u[t] = null
call TQ_D(t)
static if DYNAMIC then
set D.l[i] = 0
endif
endif
return false
endmethod
private static method start takes nothing returns nothing
//starting an upgrade will destroy the timer
//it would be better to pause, but it's impossible to pause
//a timer in a timer queue
local integer i = GetUnitUserData(GetTriggerUnit())
local integer t = p[i]
if (t != 0) then
call TQ_D(t)
static if DYNAMIC then
set D.l[i] = 0
endif
endif
endmethod
private static method cancel takes nothing returns nothing
//on cancellation, recreate the timer (add it back in)
local integer i = GetUnitUserData(GetTriggerUnit())
local integer t = p[i]
if (t != 0) then
set t = allocate()
set p[i] = t
set u[t] = GetTriggerUnit()
static if DYNAMIC then
if (INTERVAL > D.l[i]) then
set D.l[i] = INTERVAL
endif
endif
endif
endmethod
private static method finish takes nothing returns nothing
//when finished, either finish destroying the timer (if going out), or
//create a new timer (if going in)
local integer i = GetUnitUserData(GetTriggerUnit())
local integer t = p[i]
if (GetUnitTypeId(GetTriggerUnit()) == ORIGIN) then
set t = allocate()
set u[t] = GetTriggerUnit()
set p[i] = t
static if DYNAMIC then
if (INTERVAL > D.l[i]) then
set D.l[i] = INTERVAL
endif
endif
elseif (t != 0) then
set p[i] = 0
set u[t] = null
endif
endmethod
private static method stop takes nothing returns boolean
local integer i = GetEventUnitId()
local integer t = p[i]
if (t != 0) then
set p[i] = 0
set u[t] = null
call TQ_D(t)
static if DYNAMIC then
set D.l[i] = 0
endif
endif
return false
endmethod
private static method restart takes nothing returns boolean
local integer t
local integer i = GetEventUnitId()
if (GetUnitTypeId(GetUnitById(i)) == ORIGIN) then
set t = allocate() //allocate timer
set u[t] = GetUnitById(i) //store indexed unit in timer
set p[i] = t //store timer in unit
static if DYNAMIC then
if (INTERVAL > D.l[i]) then
set D.l[i] = INTERVAL
endif
endif
endif
return false
endmethod
private static method onInit takes nothing returns nothing
//upgrade trigger registration
call TriggerAddAction(tt, function thistype.start)
call TriggerAddAction(tt2, function thistype.cancel)
call TriggerAddAction(tt3, function thistype.finish)
call RegisterUnitIndexEvent(Condition(function thistype.index), UnitIndexer.INDEX)
call RegisterUnitIndexEvent(Condition(function thistype.deindex), UnitIndexer.DEINDEX)
call UnitEvent.DEATH.register(Condition(function thistype.stop))
call UnitEvent.START_REINCARNATE.register(Condition(function thistype.stop))
call UnitEvent.RESURRECT.register(Condition(function thistype.restart))
call UnitEvent.ANIMATE.register(Condition(function thistype.restart))
call UnitEvent.REINCARNATE.register(Condition(function thistype.restart))
static if DYNAMIC then
//if the trigger doesn't already exist, create it
if (not D.t.trigger.has(ORIGIN)) then
set D.t.trigger[ORIGIN] = CreateTrigger()
endif
//register the registration function
call TriggerAddCondition(D.t.trigger[ORIGIN], Condition(function thistype.rs))
endif
endmethod
endmodule
endlibrary
Cool demo
JASS:
struct BarracksFoot extends array
private static constant real INTERVAL = 6 //6 interval spawn time
private static constant integer ORIGIN = 'hbar' //barracks
private static constant integer SPAWN = 'hfoo' //footman
private static constant integer COUNT = 1 //count
implement LightSpawn
endstruct
struct BarracksRif extends array
private static constant real INTERVAL = 9 //9 interval spawn time
private static constant integer ORIGIN = 'hbar' //barracks
private static constant integer SPAWN = 'hrif' //footman
private static constant integer COUNT = 1 //count
implement LightSpawn
endstruct
Last edited: