//:******************************************************************************
//: Anachrons Spawn System
//: by dhk_undead_lord / aka Anachron
//: version 1.05
//: BETA
//:
//: ABOUT:
//: This system has been made for easily create
//: and manage grouped spawns such as in DotA or
//: AotZ. Could also be very useful in Tower Defenses,
//: TAG maps and/or all other map genres with interval
//: spawning, such as Enfo, Castle Defenses etc.
//:
//: WHAT YOU NEED:
//: You need JassNewGenPack to use this vJASS system.
//: (Download it here: http://www.wc3c.net/showthread.php?goto=newpost&t=90999)
//:
//: STEPS TO IMPORT:
//: I.) Copy this code.
//: II.) Paste it into the head of your map.
//: (Therefor go to the Trigger Editor, select the mapname and paste
//: into the area on the right)
//: III.) Save your map!
//: (With File - Save Map (S) or control + S. DO NOT SAVE WITH SAVE AS!)
//: IV.) You got it! You imported the system.
//:
//: To make sure this system works, you should try a few tests!
//:
//: METHODS
//:
//: SharedObjects:
//: This is a small library for GroupSpawns and unitsspawns so
//: you can easily manage conditional spawning and function calls
//: at actual spawning.
//:
//:
//:
//:
//:
//:
//: Thanks for downloading and using my system!
//:
//: Please don't forget to give credits to me (dhk_undead_lord / Aka Anachron)
//:
//:******************************************************************************
library AnaSpawnSys initializer init
//==========================================================================
// %CUSTOMIZATION AREA%: Feel free to change anything to what you need!
//==========================================================================
globals
//: %Default Values%
//: Check whether wanting to create units in each other
//: on creation or not. This prevents the bug that units
//: spawn out of area when to much units are into, or
//: simple the pathing is off.
private constant boolean CREATION_ZEROCOLLISION = true
//: %Timers%
private constant timer WAVE_TIMER = CreateTimer()
private constant real WAVE_INT = 0.25
endglobals
//==========================================================================
//: %DO NOT CHANGE THIS UNLIKE YOU KNOW WHAT YOU ARE DOING%
//==========================================================================
//: =================================
//: Small Interface for Spawns
//: =================================
function interface onSpawn takes nothing returns nothing
function interface onCheck takes nothing returns boolean
function interface onUnitSpawn takes unit u returns nothing
private function returnTrue takes nothing returns boolean
return true
endfunction
struct SharedObjects
onSpawn spawnCall = 0
onCheck checkCall = 0
boolean isSetSpawn = false
boolean isSetCheck = false
public method setOnSpawnCall takes onSpawn onS returns nothing
set .spawnCall = onS
set .isSetSpawn = true
endmethod
public method runOnSpawnCall takes nothing returns nothing
if .isSetSpawn then
call .spawnCall.execute()
endif
endmethod
public method setOnSpawnCheck takes onCheck onC returns nothing
set .checkCall = onC
set .isSetCheck = true
endmethod
public method runOnSpawnCheck takes nothing returns boolean
if .isSetCheck then
return .checkCall.evaluate()
endif
return true
endmethod
endstruct
//: =================================
struct UnitSpawn extends SharedObjects
integer ID = 0
integer unitID = '0000'
integer amount = 0
string sfxPath = ""
onUnitSpawn onUnitSpawnCall = 0
public static method create takes integer unitId, integer amount, onUnitSpawn onUnitSp, string effPath returns UnitSpawn
local thistype us = thistype.allocate()
set us.unitID = unitId
set us.amount = amount
set us.onUnitSpawnCall = onUnitSp
set us.sfxPath = effPath
return us
endmethod
public method spawn takes player p, real posX, real posY returns nothing
local integer i = 0
local integer i2 = .amount
local unit u = null
if .runOnSpawnCheck() then
call .runOnSpawnCall()
loop
exitwhen i >= i2
set u = CreateUnit(p, .unitID, posX, posY, 270)
if .sfxPath != "" then
call DestroyEffect(AddSpecialEffect(.sfxPath, GetUnitX(u), GetUnitY(u)))
endif
if CREATION_ZEROCOLLISION then
call SetUnitPathing(u, false)
call SetUnitX(u, posX)
call SetUnitY(u, posY)
call SetUnitPathing(u, true)
endif
if .onUnitSpawnCall != 0 then
call .onUnitSpawnCall.execute(u)
endif
set i = i + 1
endloop
endif
set u = null
endmethod
endstruct
struct GroupSpawn extends SharedObjects
integer ID = 0
real delay = 0
real baseX = 0.
real baseY = 0.
UnitSpawn array unitSpawns[64]
integer index = 0
//: =================================
//: CREATE NEW INSTANCES
//: =================================
public static method create takes real baseX, real baseY, real d returns thistype
local thistype usg = thistype.allocate()
set usg.baseX = baseX
set usg.baseY = baseY
set usg.delay = d
return usg
endmethod
//: =================================
//: =================================
//: Add and remove UnitSpawns
//: =================================
public method addUnitSpawn takes UnitSpawn us returns nothing
set us.ID = .index
set .unitSpawns[.index] = us
set .index = .index + 1
endmethod
public method removeUnitSpawn takes UnitSpawn us returns nothing
set .unitSpawns[us.ID] = .unitSpawns[.index]
set .index = .index - 1
endmethod
//: =================================
//: =================================
//: Spawn UnitSpawn-objects.
//: =================================
public method spawnUnits takes player p returns nothing
local integer i = 0
local UnitSpawn us = 0
if .runOnSpawnCheck() then
call .runOnSpawnCall()
loop
exitwhen i >= .index
set us = .unitSpawns[i]
call us.spawn(p, .baseX, .baseY)
set i = i + 1
endloop
endif
endmethod
//: =================================
//: ====================================
//: Desctrutor Method
//: ====================================
private method onDestroy takes nothing returns nothing
local integer i = 0
loop
exitwhen i >= .index
call .unitSpawns[i].destroy()
set i = i + 1
endloop
endmethod
//: ====================================
endstruct
struct Wave
GroupSpawn array groupSpawns[64]
integer groupIndex = 0
player owner = null
real interval = 0.
integer ID = 0
//: =================================
//: CREATE NEW INSTANCES
//: =================================
public static method create takes real i, player own returns thistype
local thistype usg = thistype.allocate()
set usg.interval = i
set usg.owner = own
return usg
endmethod
//: =================================
//: =================================
//: Add and remove GroupSpawns
//: =================================
public method addGroupSpawn takes GroupSpawn gs returns nothing
set gs.ID = .groupIndex
set .groupSpawns[.groupIndex] = gs
set .groupIndex = .groupIndex + 1
endmethod
public method removeGroupSpawn takes GroupSpawn gs returns nothing
set .groupSpawns[gs.ID] = .groupSpawns[.groupIndex]
set .groupIndex = .groupIndex - 1
endmethod
//: =================================
public method spawnUnitGroup takes integer i returns nothing
call .groupSpawns[i].spawnUnits(.owner)
endmethod
//: ====================================
//: Desctrutor Method
//: ====================================
private method onDestroy takes nothing returns nothing
local integer i = 0
loop
exitwhen i >= .groupIndex
call .groupSpawns[i].destroy()
set i = i + 1
endloop
endmethod
//: ====================================
endstruct
struct WaveStack
static Wave array toSpawn[8191]
static integer index = 0
// %Data of the Waves%
static real array waitTime[8191]
static real array groupDelay[8191]
static integer array curGroup[8191]
static boolean array isPermanent[8191]
static integer array spawnTimes[8191]
//: =================================
//: CHECK ALL WAYS AND ALL UNITS
//: =================================
public static method checkSpawn takes nothing returns nothing
local integer i = 0
local Wave w = 0
loop
exitwhen i >= thistype.index
set w = thistype.toSpawn[i]
//: We don't have to wait so we
//: can check what should happen after the wave has to
//: be spammed.
if thistype.waitTime[i] <= 0. then
if thistype.groupDelay[i] > 0. then
set thistype.groupDelay[i] = thistype.groupDelay[i] - WAVE_INT
endif
debug call BJDebugMsg("!AoSSpawnSys] |NOTICE| <Wave[" + I2S(i) + "]> <CHECKING FOR SPAWNING!>")
//: If the group has no delay we can call the spawn
if thistype.groupDelay[i] <= 0. then
debug call BJDebugMsg("!AoSSpawnSys] |NOTICE| <Wave[" + I2S(i) + "]> <SPAWN GROUP " + I2S(thistype.curGroup[i]) + "!>")
call w.spawnUnitGroup(thistype.curGroup[i])
if thistype.curGroup[i] < w.groupIndex - 1 then
set thistype.curGroup[i] = thistype.curGroup[i] + 1
else
set thistype.curGroup[i] = 0
set thistype.waitTime[i] = w.interval
debug call BJDebugMsg("!AoSSpawnSys] |NOTICE| <Wave[" + I2S(i) + "]> <RESET GROUPS!>")
endif
set thistype.groupDelay[i] = w.groupSpawns[thistype.curGroup[i]].delay
endif
//: If we have no permanent wave reduce its amount.
//: If required delete the wave from the stack.
if not thistype.isPermanent[i] then
debug call BJDebugMsg("!AoSSpawnSys] |NOTICE| <Wave[" + I2S(i) + "]> <DELETING THE WAVE!>")
set thistype.spawnTimes[i] = thistype.spawnTimes[i] - 1
if thistype.spawnTimes[i] <= 0 then
call thistype.removeWave(w)
set i = i - 1
endif
endif
else
//: If we have to wait decrease time
set thistype.waitTime[i] = thistype.waitTime[i] - WAVE_INT
endif
set i = i + 1
endloop
endmethod
//: =================================
//: =================================
//: Add and remove Waves
//: =================================
public static method addWave takes Wave w, integer times returns nothing
local integer i = thistype.index
set w.ID = i
set thistype.toSpawn[i] = w
// %Init Wave%
set thistype.waitTime[i] = w.interval
set thistype.curGroup[i] = 0
set thistype.groupDelay[i] = w.groupSpawns[0].delay
set thistype.spawnTimes[i] = times
if times == 0 then
set thistype.isPermanent[i] = true
else
set thistype.isPermanent[i] = false
endif
set thistype.index = thistype.index + 1
endmethod
public static method removeWave takes Wave w returns nothing
local integer i = w.ID
set thistype.toSpawn[i] = thistype.toSpawn[thistype.index]
set thistype.curGroup[i] = thistype.curGroup[thistype.index]
set thistype.groupDelay[i] = thistype.groupDelay[thistype.index]
set thistype.isPermanent[i] = thistype.isPermanent[thistype.index]
set thistype.spawnTimes[i] = thistype.spawnTimes[thistype.index]
set thistype.index = thistype.index - 1
endmethod
//: =================================
endstruct
public function init takes nothing returns nothing
call TimerStart(WAVE_TIMER, WAVE_INT, true, function WaveStack.checkSpawn)
endfunction
endlibrary