• 🏆 Texturing Contest #33 is OPEN! Contestants must re-texture a SD unit model found in-game (Warcraft 3 Classic), recreating the unit into a peaceful NPC version. 🔗Click here to enter!

[vJASS] Anachrons Spawn System 1.05

Hey ;D Finally I managed to do the Anachrons Spawn System! HAVE FUN! :)

Please give credits if you use this! =)

by dhk_undead_lord / Anachron


JASS:
//:******************************************************************************
//:  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



JASS:
scope example initializer init

    globals
        private Wave array NIGHTELF_WAVES
        private unit array NIGHTELF_STRUCTURES[8191]
        
        private constant integer ID_LEFTWAVE = 0
        private constant integer ID_CENTERWAVE = 1
        private constant integer ID_RIGHTWAVE = 2
    endglobals

    public function nightelfGroupSpawnCheckLeft takes nothing returns boolean
        return GetUnitState(NIGHTELF_STRUCTURES[ID_LEFTWAVE], UNIT_STATE_LIFE) != 0.
    endfunction
    
    public function nightelfGroupSpawnCheckCenter takes nothing returns boolean
        return GetUnitState(NIGHTELF_STRUCTURES[ID_CENTERWAVE], UNIT_STATE_LIFE) != 0.
    endfunction
    
    public function nightelfGroupSpawnCheckRight takes nothing returns boolean
        return GetUnitState(NIGHTELF_STRUCTURES[ID_RIGHTWAVE], UNIT_STATE_LIFE) != 0.
    endfunction
    
    public function timedLife takes unit u returns nothing
        call UnitApplyTimedLife(u, '0000', 25.)
    endfunction

    private function init takes nothing returns nothing
        local Wave w = 0
        local GroupSpawn gs = 0
        local UnitSpawn us = 0 
        
        //:**********************************
        //: %LEFT WAVE
        //:**********************************
        
        //: Instanciate a new wave
        //:     spawn every 30 seconds
        //:     owner is Player 0. (red)
        set w = Wave.create(5, Player(0))
        
        //: Instanciate a new GroupSpawn 
        //:     based on Point(0., 0.)
        //:     delay to last group: 0.00    
        set gs = GroupSpawn.create(0., 0., 0.)
        
        //: Add a condition to the group spawn
        //:     first parameter = condition 
        //:     func that returns boolean
        call gs.setOnSpawnCheck(nightelfGroupSpawnCheckLeft)
        
        //: Create a new unitspawn
        //:     type: 'efon' (ent)
        //:     amount: 1
        //:     function to call on construction: nothing = 0
        //:     effect-path: "Objects\\Spawnmodels\\NightElf\\EntBirthTarget\\EntBirthTarget.mdl"
        set us = UnitSpawn.create('efon', 1, timedLife, "Objects\\Spawnmodels\\NightElf\\EntBirthTarget\\EntBirthTarget.mdl")
        
        //: Add the unit spawn to the group
        call gs.addUnitSpawn(us)
        
        //: Add the groupspawn to the wave
        call w.addGroupSpawn(gs)
        
        //: Add the wave to the current spawn system
        //: 0 = endless spawning
        call WaveStack.addWave(w, 0)
        
        set NIGHTELF_WAVES[ID_LEFTWAVE] = w
        set NIGHTELF_STRUCTURES[ID_LEFTWAVE] = CreateUnit(Player(0), 'eaow', -64., -64., 270.)     
        //:**********************************
    endfunction

endscope


Keywords:
Spawn, System, Spawn System, Spawn, System
Contents

Anachrons Spawn System 1.05 (Map)

Reviews
21:52, 9th Oct 2009 The_Reborn_Devil: The coding looks really good and the system is quite useful I think. I guess I'll need to Approve this too... I give this system the rating Recommended :(

Moderator

M

Moderator

21:52, 9th Oct 2009
The_Reborn_Devil:

The coding looks really good and the system is quite useful I think.
I guess I'll need to Approve this too...
I give this system the rating Recommended :(
 
Ok, so you are assuming the computer owns the creeps. The example is far to basic, I believe something with movement would be better. I will say more once you post a better demo map =P

I have made another system for movement AoS Move System.

This is very advanced and allows you to create way routes.

When you combine this two systems, you will be able to rebuild DotAs spawn system completly.
 
Top