luorax
Invasion in Duskwood
- Reaction score
- 67
Well, we've got tons of these already, but most of them is outdated, or overcomplicated. I tried to mix simplicity and efficiency. I got this:
Please share your thought with me. (Except those "too long variable names", "you should compare 0 to your variable and not the opposite" kind of comments; my spaghetti should be on my plate and my code should be on my monitor. So I'm not interested in reading 'em)
JASS:
library SpawnSystem uses TimerUtils,Alloc, optional AIDS, optional UnitIndexer
/*************************************************************************************
*
* Spawn System
* by Luorax
*
* DESCRIPTION
* >> AoS Spawn System is an basic and simple system that eases the creation
* of spawns in AoS or any other genre. You only have to create one AoSSpawn struct per
* Spawn and add your waypoints. After that call .finish() to make the whole stuff work.
*
* FEATURES
* > Easy to setup alot of spawns which would create a bunch of triggers normally
* > You can have nearly an unlimited number of spawns
* > Simple struct syntax should be easy to use
*
* FUNCTIONS LIST
* >> struct Spawn
* .create takes integer rawCode, integer count,player owner,real interval,string effectPath returns thistype
* .addWaypoint takes rect whichRect returns nothing
* .removeWayoint takes rect whichRect returns nothing
* .method addSpawnFunction takes onSpawn spw returns nothing
* .method addCheckFunction takes onCheck spw returns nothing
* .method addUnitSpawnFunction takes onUnitSpawn spw returns nothing
*
* CREDITS
* > YourName for the original system and this library header
* > Magtheridon96 for TimerUtils
* > Sevion for Alloc
* > Vexorian for JASSHelper and original TimerUtils
*
* MISC
*
* >> Function Interfaces
* > function interface onSpawn takes nothing returns nothing
* > function interface onCheck takes nothing returns boolean
* > function interface onUnitSpawn takes unit u returns nothing
*************************************************************************************/
//: =================================================================
//: Config
//: =================================================================
globals
// The basic interval which is used when you set -1 as interval in the create function.
private constant real DEFAULT_INTERVAL=10
endglobals
private function defaultSpawnCheck takes nothing returns boolean
return true
endfunction
//: =================================================================
//: System Code
//: =================================================================
function interface onSpawn takes nothing returns nothing
function interface onCheck takes nothing returns boolean
function interface onUnitSpawn takes unit u returns nothing
globals
private integer array WayPointData
endglobals
private struct RectList extends array
implement Alloc
readonly rect r
readonly real x
readonly real y
readonly boolean isList
readonly thistype next
readonly thistype prev
readonly thistype list
readonly integer size
static method create takes nothing returns thistype
local thistype this=thistype.allocate()
set this.isList=true
set this.list=this
set this.prev=0
set this.next=0
set this.size=0
return this
endmethod
method remove takes nothing returns thistype
local thistype next=this.next
set this.isList=false
call this.deallocate()
return next
endmethod
method destroy takes nothing returns nothing
loop
set this=this.remove()
exitwhen this==0
endloop
endmethod
method link takes rect r returns nothing
local thistype next=thistype.allocate()
set next.r=r
set next.x=GetRectCenterX(next.r)
set next.y=GetRectCenterY(next.r)
set next.list=this
set this.prev.next=next
set next.prev=this.prev
set this.prev=next
set this.size=this.size+1
if this.next==0 then
set this.next=next
endif
endmethod
method detachTail takes nothing returns nothing
local thistype tail=this.prev
set this.prev=this.prev.prev
set this.prev.next=0
set this.size=this.size-1
set tail.next=0
set tail.prev=0
set tail.list=0
if this.next==tail then
set this.next=0
endif
endmethod
method detachHead takes nothing returns nothing
local thistype head=this.next
set this.next=this.next.next
set this.next.prev=0
set this.size=this.size-1
set head.next=0
set head.prev=0
set head.list=0
if this.prev==head then
set this.prev=0
endif
endmethod
private method detach takes nothing returns nothing
if this.list.next==this then
call this.list.detachHead()
elseif this.list.prev==this then
call this.list.detachTail()
else
set this.prev.next=this.next
set this.next.prev=this.prev
set this.list.size=this.list.size-1
set this.next=0
set this.prev=0
set this.list=0
endif
endmethod
method unlink takes rect r returns nothing
loop
set this=this.next
if this.r==r then
call this.detach()
endif
exitwhen this==0
endloop
endmethod
method operator head takes nothing returns thistype
return this.next
endmethod
method operator hasNext takes nothing returns boolean
return this.next!=0
endmethod
method operator tail takes nothing returns thistype
return this.prev
endmethod
method operator hasPrev takes nothing returns boolean
return this.prev!=0
endmethod
method operator empty takes nothing returns boolean
return this.size==0
endmethod
endstruct
struct Spawn extends array
implement Alloc
private player owner
private integer rawCode
private integer count
private timer timer
private RectList wayPoints
private trigger onEnter
private string effectPath
private onSpawn onSpawn
private onCheck spawnCheck
private onUnitSpawn onUnitSpawn
//---== Privates ==---
private static method periodic takes nothing returns nothing
local thistype this=GetTimerData(GetExpiredTimer())
local integer i=0
local unit u
if this.spawnCheck.evaluate() then
call this.onSpawn.execute()
loop
exitwhen i>=this.count
set u=CreateUnit(this.owner,this.rawCode,this.wayPoints.head.x,this.wayPoints.head.y,0)
if this.effectPath!="" then
call DestroyEffect(AddSpecialEffectTarget(this.effectPath,u,"origin"))
endif
call this.onUnitSpawn.execute(u)
call IssuePointOrder(u,"attack",this.wayPoints.head.next.x,this.wayPoints.head.next.y)
set WayPointData[GetUnitUserData(u)]=this.wayPoints.head.next
set i=i+1
endloop
endif
set u=null
endmethod
private static method enter takes nothing returns boolean
local RectList list=RectList(WayPointData[GetUnitUserData(GetTriggerUnit())])
if list.hasNext then
set list=list.next
call IssuePointOrder(GetTriggerUnit(),"attack",list.x,list.y)
set WayPointData[GetUnitUserData(GetTriggerUnit())]=list
endif
return false
endmethod
//---== SetUps ==---
method addSpawnFunction takes onSpawn spw returns nothing
set this.onSpawn=spw
endmethod
method addCheckFunction takes onCheck spw returns nothing
set this.spawnCheck=spw
endmethod
method addUnitSpawnFunction takes onUnitSpawn spw returns nothing
set this.onUnitSpawn=spw
endmethod
method addWaypoint takes rect r returns nothing
local region reg=CreateRegion()
call RegionAddRect(reg,r)
call TriggerRegisterEnterRegion(this.onEnter,reg,null)
call this.wayPoints.link(r)
set reg=null
endmethod
method removeWaypoint takes rect r returns nothing
call this.wayPoints.unlink(r)
endmethod
//---== Allocation/Deallocation ==---
static method create takes integer rawCode, integer count,player owner,real interval,string effectPath returns thistype
local thistype this=thistype.allocate()
set this.rawCode=rawCode
set this.count=count
set this.owner=owner
set this.effectPath=effectPath
set this.timer=NewTimer()
set this.spawnCheck=defaultSpawnCheck
set this.onEnter=CreateTrigger()
set this.wayPoints=RectList.create()
call SetTimerData(this.timer,this)
call TriggerAddCondition(this.onEnter,Filter(function thistype.enter))
if interval<0 then
call TimerStart(this.timer,DEFAULT_INTERVAL,true,function thistype.periodic)
else
call TimerStart(this.timer,interval,true,function thistype.periodic)
endif
return this
endmethod
method destroy takes nothing returns nothing
call ReleaseTimer(this.timer)
call this.wayPoints.destroy()
call DestroyTrigger(this.onEnter)
call this.deallocate()
endmethod
endstruct
endlibrary
Please share your thought with me. (Except those "too long variable names", "you should compare 0 to your variable and not the opposite" kind of comments; my spaghetti should be on my plate and my code should be on my monitor. So I'm not interested in reading 'em)