System Spawn Units at Point Over Time (SUPOT)

Prometheus

Everything is mutable; nothing is sacred
Reaction score
589
This can be used for anything, though I don't think it would be good for a TD. Implementation instructions are in the SUPOT trigger.

Code
JASS:
//==============================================================================
//  SUPOT - Spawn Units at Point Over Time by kc102 AKA R34P3R - v6.6
//==============================================================================
//
//  PURPOSE OF SUPOT:
//       * Spawning units at a point with ease~
//
//  PROS: 
//       * Makes spawning units for anything easy.
//
//  CONS:
//       * Limited to 8191 instances running at a time.
//
//  FUNCTIONS:
//       * SUPOT_Start(player PlayerToSpawnFor, integer UnitTypeID, integer NumberOfUnits, real TimePerSpawn, real Spawn Location X, real Spawn Location Y)
//         Starts the spawning.
//
//       * SUPOT_StartEx(player PlayerToSpawnFor, integer UnitTypeID, integer NumberOfUnits, real TimePerSpawn, location SpawnLocation)
//         Starts the spawning using a location, meant for eGUI use.
//
//       * SUPOT_Stop(integer Instance ID)
//         Stops the spawning for that ID.
//         
//       * SUPOT_Pause(integer Instance ID)
//         Pauses the spawning for that ID.
//
//       * SUPOT_UnPause(integer Instance ID)
//         Unpauses the spawning for that ID.
//         
//       * SUPOT_ChangeUnitID(integer Instance ID, integer newUnitID)
//         Changes the unit-type spawned for that ID.
//         
//       * SUPOT_ChangeSpawnTime(integer Instance ID, real newSpawnTime)
//         Changes the interval between spawning for that ID.
//         
//       * SUPOT_ChangePlayer(integer Instance ID, player newPlayer)
//         Changes the player that the unit is spawned for, for that ID.
//         
//       * SUPOT_ChangeSpawnAmount(integer Instance ID, integer newSpawnAmount)
//         Changes the number of units spawned per interval, for that ID.
//         
//       * SUPOT_ChangeLocation(integer Instance ID, real newX, real newY)
//         Changes the location of the spawning, for that ID.
//
//       * GetLastSpawned(integer Instance)
//         This function returns a group with the units made
//         in the last run of that SUPOT instance
//
//       * GetLastInstance()
//         This function is for eGUI mainly, but anyone can use it.
//         Since each start returns an integer, this basically takes that integer
//         and allows you to set it to a variable after starting SUPOT.
//
//       * The start function returns an integer, so make sure to call it properly.
//         To stop something, call the stop function with the integer you set to call
//         the start function, same with the other functions.
//
//  HALPS:
//       * Report any bugs or odd happennings please.
//       * Assigning a single integer to the function twice will result in
//         you only having once instance of SUPOT on that integer.
//
//  REQUIREMENTS:
//       * NewGen v5 and above (there might be some problems with older NewGen's)
//
//
//  HOW TO IMPORT:
//       * Copy this code into your map.
//==============================================================================//
//                      Change Log                                              //
//                      1.0 - Release                                           //
//                      1.0 to 3.3 - Stuff                                      //
//                      4.0 - Major Code Overhaul, Self-Sufficient              //
//                      4.5 - Added modification functions, inproved code       //
//                      4.6 - Safeties added to mod functions                   //
//                      4.7 - Added more safeties, fixed a few others           //
//                      4.8 - Added a pause function                            //
//                      4.9 - Added function so the unit can do stuff           //
//                      4.10 - Fixed a pause function error                     //
//                      5.0 - Made struct SUPOT open                            //
//                      5.1 - Readme fix                                        //
//                      5.2 - Global supot variable is now private              //
//                      5.3 - All spawned units are now returned VIA group      //
//                      5.4 - Lst changed to Last <Blame Uberplayer>            //
//                      5.5 - Slight code changes                               //
//                      5.6 - Major Code Fixes                                  //
//                      5.7 - Modifed Pause function, UnPause added             //
//                      5.75 - SUPOT Public                                     //
//                      5.8 - Major & Minor Code Fixes                          //
//                      5.9 - Group Last is now an arrayed group                //
//                      5.10 - Code Improvements                                //
//                      6.0 - Code Improvments                                  //
//                      6.1 - Major Flaw Overcome thanks to Artificial          //
//                      6.2 - Safety Improvments & Inlining                     //
//                      6.3 - DoubleFree & Invalid X/Y values fixed             //
//                      6.4 - Improved for eGUI, code touchups                  //
//                      6.5 - *glares at Sevion* eGUI improvment                //
//                      6.55 - Fixed extra space on 5.7                         //
//                      6.6 - Added in StartEx for location use and eGUI        //
//==============================================================================//
//==============================================================================//
//                       ~<||§||Credits||§||>~                                  //
//                             Uberplayer                                       //
//                             Flare                                            //
//                             emjlr3                                           //
//                             Themis                                           //
//                             Dusk                                             //
//                           --Artificial--                                     //
//                             Gwypaas                                          //
//                             Romek                                            //
//                             Sevion                                           //
//==============================================================================//

library SUPOT initializer Init
    struct supot
        integer sid = 0
        integer num = 0
        
        player p = null
        
        real x
        real y
        real interval = 0
        real ticker = 0
        
        boolean paused = false
        
        method onDestroy takes nothing returns nothing
            set .interval = 0
            set .x = 0
            set .y = 0
            set .p = null
            set .num = 0
            set .sid = 0
        endmethod
    endstruct

    globals
        private constant real TIMER_INT = 0.25
        
        private integer N = 0
        
        private timer T = CreateTimer()
        
        private group array Last
  
        public supot array spawn
        
        private real MINX
        private real MAXX
        private real MINY
        private real MAXY
        
        integer bj_LastCreatedInstance
    endglobals
    
    function GetLastSpawned takes integer instance returns group 
        if Last[instance] != null then
            return Last[instance]
        endif
        debug call BJDebugMsg(I2S(instance) + " has no units running on that instance.") 
        return null
    endfunction
    
    private function DoSpawn takes nothing returns nothing
        local supot a
        local unit u
        local integer i = N
        local integer j = 0
        loop
        exitwhen i == 0
            set a = spawn<i>
            if a == 0 then
            else
                if not a.paused == true then
                    set a.ticker = a.ticker + TIMER_INT
                    if a.ticker &gt;= a.interval then
                        set a.ticker = a.ticker - a.interval
                        call GroupClear(Last<i>)
                        loop
                        exitwhen j == a.num
                            set u = CreateUnit(a.p, a.sid, a.x, a.y, bj_UNIT_FACING)
                            call GroupAddUnit(Last<i>,u)
                            debug call BJDebugMsg(&quot;Unit has been created!&quot;)
                            set u = null
                            set j = j + 1
                        endloop
                        set j = 0
                    endif
                endif
                if a.num == 0 and a.interval != 0 then
                    call a.destroy()
                    call DestroyGroup(Last<i>)
                endif
            endif
            set i = i - 1
        endloop
        set u = null
        set j = 0
    endfunction

    public function Stop takes integer instance returns nothing
        set supot(instance).num = 0
        debug call BJDebugMsg(&quot;The instance number &quot; + I2S(instance) + &quot; of SUPOT has been stopped!&quot;)
    endfunction
    
    public function Pause takes integer instance returns nothing
        set supot(instance).paused = true
    endfunction
    
    public function UnPause takes integer instance returns nothing
        set supot(instance).paused = false
    endfunction
    
    public function ChangeUnitID takes integer instance, integer newUnitID returns nothing
        if newUnitID == 0 then
            debug call BJDebugMsg(&quot;No Spawn ID!&quot;)
            return
        endif
        set supot(instance).sid = newUnitID
        debug call BJDebugMsg(&quot;A different unit is now being spawned for SUPOT instance number &quot; + I2S(instance))
    endfunction
    
    public function ChangeSpawnTime takes integer instance, real newSpawnTime returns nothing
        if newSpawnTime &lt;= 0 then
            debug call BJDebugMsg(&quot;Invalid Spawn Interval!&quot;)
            return
        endif
        set supot(instance).interval = newSpawnTime
        debug call BJDebugMsg(&quot;Spawn time has been changed for SUPOT instance number &quot; + I2S(instance))
    endfunction
    
    public function ChangePlayer takes integer instance, player newPlayer returns nothing
        if newPlayer == null then
            debug call BJDebugMsg(&quot;Player Not Found!&quot;)
            return
        endif
        set supot(instance).p = newPlayer
        debug call BJDebugMsg(&quot;Units are now being spawned for a different player under SUPOT instance number &quot; + I2S(instance))
    endfunction
    
    public function ChangeSpawnAmount takes integer instance, integer newNumber returns nothing
        if newNumber &lt;= 0 then
            debug call BJDebugMsg(&quot;Incorrect spawn number specified!&quot;)
            return
        endif
        set supot(instance).num = newNumber
        debug call BJDebugMsg(&quot;A different number of units are being spawned for SUPOT instance number &quot; + I2S(instance))
    endfunction
    
    public function ChangeLocation takes integer instance, real newX, real newY returns nothing
        if newX &gt; MAXX or newX &lt; MINX then
            debug call BJDebugMsg(&quot;Impossible Spawn Location X Given!&quot;)
            return
        elseif newY &gt; MAXY or newY &lt; MINY then
            debug call BJDebugMsg(&quot;Unusable Spawn Location Y Given!&quot;)
            return
        endif
        set supot(instance).x = newX
        set supot(instance).y = newY
        debug call BJDebugMsg(&quot;The spawn location has been changed for SUPOT instance number &quot; + I2S(instance))
    endfunction
    
    public function GetLastInstance takes nothing returns integer
        return bj_LastCreatedInstance
        //For eGUI users, so they can modify the function.
    endfunction
    
    public function Start takes player p, integer uid, integer number, real interval, real x, real y returns integer
        local supot a
        if uid == 0 then
            debug call BJDebugMsg(&quot;No Spawn ID!&quot;)
            return 0
        elseif number &lt;= 0 then
            debug call BJDebugMsg(&quot;Invalid Spawn Amount Specified!&quot;)
            return 0
        elseif interval &lt;= 0 then
            debug call BJDebugMsg(&quot;Invalid Spawn Time Interval Recieved!&quot;)
            return 0
        elseif x &gt; MAXX or x &lt; MINX then
            debug call BJDebugMsg(&quot;Impossible Spawn Location X Given!&quot;)
            return 0
        elseif y &gt; MAXY or y &lt; MINY then
            debug call BJDebugMsg(&quot;Unusable Spawn Location Y Given!&quot;)
            return 0
        elseif p == null then
            debug call BJDebugMsg(&quot;Spawn Player Not Found!&quot;)
            return 0
        endif
        set a = supot.create()
        set a.sid = uid
        set a.p = p
        set a.num = number
        set a.interval = interval
        set a.x = x
        set a.y = y
        debug call BJDebugMsg(R2S(MINX) + R2S(MAXX) + R2S(MINY) + R2S(MAXY))
        if N == 0 then
            call TimerStart(T, TIMER_INT, true, function DoSpawn)
        endif
        set N = N + 1
        debug call BJDebugMsg(&quot;A spawn has started under instance id &quot;+I2S(N)+&quot;!&quot;)
        if spawn[N].num != 0 then
            set N = 1
            loop
            exitwhen spawn[N].num == 0
                set N = N+1
            endloop
        endif
        set spawn[N] = a
        if Last[N] == null then
            set Last[N] = CreateGroup()
        endif
        set bj_LastCreatedInstance = integer(a)
        return integer(a)
    endfunction
    
    public function StartEx takes player p, integer uid, integer number, real interval, location l returns integer
        return Start(p,uid,number,interval,GetLocationX(l),GetLocationY(l))
    endfunction
    
    private function Init takes nothing returns nothing
        //Damned bj_mapInitialPlayableArea...
        set MINX = GetRectMinX(bj_mapInitialPlayableArea)
        set MAXX = GetRectMaxX(bj_mapInitialPlayableArea)
        set MINY = GetRectMinY(bj_mapInitialPlayableArea)
        set MAXY = GetRectMaxY(bj_mapInitialPlayableArea)
    endfunction
endlibrary</i></i></i></i>
 

Attachments

  • SUPOT.w3m
    20.3 KB · Views: 433

Flare

Stops copies me!
Reaction score
662
Cool concept (can't see why you would think it wouldn't be good for a TD, I'd say it'd be great if you expanded it slightly to take a destination as well since it would get rid of the problem of lag on unit spawning)

Why don't you just put everything in the struct? Would probably be alot easier :p

And why not use XY's instead of locations? It'd get rid of the leak removal issue, and you can create a GUI friendly function that takes a location, but calls the main function i.e.

JASS:
function StartXY takes ... returns nothing
...
endfunction

function StartLoc takes ... returns nothing
call StartXY (..., GetLocationX (whichLoc), GetLocationY (whichLoc))
endfunction
 

quraji

zap
Reaction score
144
Um...so it spawns units? Fancy..

No offense but I could make this myself in the time it would take to find and implement this. And it's not even stand-alone :eek:

I hope someone proves me wrong and finds this useful.
 

Prometheus

Everything is mutable; nothing is sacred
Reaction score
589
Its a single function. I think this would make doing upgrades and such extremely easy.
E: research
A: call SUPOT_Stop(0)
call SUPOT_Start()


Edit: Now @ v1.8.
 

demotry241

Don't Ever Categorize Yourself.
Reaction score
105
The fact that the name of this system is SUPOT is :thup:

it will be good for AoS.
 

Prometheus

Everything is mutable; nothing is sacred
Reaction score
589
My orignial idea was that this could be used for a footies.
[del]Reminder: Allow users to set the number of units spawned.[/del]

Added.
 

Artificial

Without Intelligence
Reaction score
326
I found a bug for you. :) Or at least I don't think it's supposed to work like this...

When you stop a spawn and start a new one with the same ID right after that one, it doesn't stop the old instance of the spawn, but keeps it going. :p I'm not too good with verbally explaining this, so I'll show you the function I tested it with.
JASS:
function Trig_Test_Uno_Actions takes nothing returns nothing
    local integer i = 0
    call SUPOT_Start(&#039;hfoo&#039;, 1, 1, Location(0, 0), i, Player(0))
    call TriggerSleepAction(5)
    call SUPOT_Stop(i)
    call SUPOT_Start(&#039;hpea&#039;, 1, 1, Location(0, 0), i, Player(1))
endfunction
After I stopped the old one and started the new one, it spawned 1 peasant and 1 footman for blue each second.

Why not change this:
JASS:
local supot dat = supot.create()
to this:
JASS:
local supot dat = supot(uqid)
Then you could make the spawn boolean (and the other globals) a struct member, and the problem would be solved (after modifying some parts of the code to work with the new way, ofc.). :p

And in case you're not going to go this way: you're never destroying the struct instances.
 

Prometheus

Everything is mutable; nothing is sacred
Reaction score
589
Thanks for pointing that out. I've updated the code to 3.0.
There have been a lot of changes the the code is a lot more struct orientated. The unique ID is still in use because of the way the code stops.
Thank you Artificial for point out the bug, and Flare for helping with some code.
 

emjlr3

Change can be a good thing
Reaction score
395
a lot of those inputs ppl could screw up and insert something negative, the odds of them being null is slim to nnone, I doubt the map would compile in that case

taking a loc is so GUI

I say you destroy structs when not in use, free up some memory

using 1 global timer would remove the need for ABCT and optimize it

more descriptive names would help ppl like me read it and figure out what everything means - even after going through the readme it was confusing

also, returning he new scruct, as opposd ot requiring a unique id would remove that need, and allow ppl to just "struct.destroy" when they needed to kill it
 
Reaction score
456
I think a loop could handle this, so no need for structs and whatever :).
 

Flare

Stops copies me!
Reaction score
662
Just thought of some ideas :D

1) A function that allowed for the modification of the unit-type being spawned - would be very handy if a person wanted a continous stream of units that alternated every X seconds (like Enfo's TS, Seelenjagd, Abyss Gates, or just about any other Team Survival) e.g.
Code:
Every X seconds of game-time

-

Custom script: call SUPOT_UpdateId (uniqueId, newSpawn)

2) Same as above, but for spawn point, number, and owner

3) Usage of coordinates instead of locations, and make a GUI friendly function, that calls the coordinate function using
JASS:
public function StartLoc takes ..., location spawnLoc, ... returns nothing
call StartXY (... , GetLocationX (spawnLoc), GetLocationY (spawnLoc), ... )
endfunction


4) As emjlr said, negative inputs :p

5) If you go by emjlr's suggestion of using a single timer, would be cool to allow for a spawn interval modification (again, would be fun to see in a Team Survival map if you wanted to double the spawn rate for your enemy for a period of time)
 

Prometheus

Everything is mutable; nothing is sacred
Reaction score
589
Just thought of some ideas :D

1) A function that allowed for the modification of the unit-type being spawned - would be very handy if a person wanted a continous stream of units that alternated every X seconds (like Enfo's TS, Seelenjagd, Abyss Gates, or just about any other Team Survival) e.g.
Code:
Every X seconds of game-time

-

Custom script: call SUPOT_UpdateId (uniqueId, newSpawn)

2) Same as above, but for spawn point, number, and owner

3) Usage of coordinates instead of locations, and make a GUI friendly function, that calls the coordinate function using
JASS:
public function StartLoc takes ..., location spawnLoc, ... returns nothing
call StartXY (... , GetLocationX (spawnLoc), GetLocationY (spawnLoc), ... )
endfunction


4) As emjlr said, negative inputs :p

5) If you go by emjlr's suggestion of using a single timer, would be cool to allow for a spawn interval modification (again, would be fun to see in a Team Survival map if you wanted to double the spawn rate for your enemy for a period of time)

1. I'm going to make this return structs so you can change anything, easily.
2. See 1.
3. Already been added to the latest V.
4. See bottom.


I think a loop could handle this, so no need for structs and whatever :).
Doubtful?

a lot of those inputs ppl could screw up and insert something negative, the odds of them being null is slim to nnone, I doubt the map would compile in that case

taking a loc is so GUI

I say you destroy structs when not in use, free up some memory

using 1 global timer would remove the need for ABCT and optimize it

more descriptive names would help ppl like me read it and figure out what everything means - even after going through the readme it was confusing

also, returning he new scruct, as opposd ot requiring a unique id would remove that need, and allow ppl to just "struct.destroy" when they needed to kill it

I'm going to make this run on 1 global timer, modding names a lil. Planning to return a struct. Removing the uqid part, removing the negative issue.



Updated to v4.0!
Apparently the map is a .w3m now, RoC users can open it now. xD
 

Flare

Stops copies me!
Reaction score
662
I'm going to make this return structs so you can change anything, easily.
Returning the struct can lead to abuses by the end-user, since they will then have access to .destroy (struct itself may be private, but as long as you have access to a struct var, you have access to .destroy) and as a result, they can break shit :p You could return an integer (rather than 'returns supot'), then people wouldn't have direct access to the struct, but you could have modification stuff like
JASS:
function AlterSpawnType takes integer index, integer newType returns nothing
  local supot data = supot(index) //Not sure if you need to do the cast, I&#039;ve never really worked with it
  set data.spawnType = newType
endfunction

(and why did you bold structs in your sentence xD)

Doubtful?
??? What?

JASS:
//         local &lt;struct name&gt; &lt;local name&gt; = &lt;struct name&gt;.create()
//         set &lt;local name&gt; = SUPOT_StartSpawn(integer UnitTypeID, integer NumberOfUnits, real TimePerSpawn, real Spawn Location X, real Spawn Location Y,  player PlayerToSpawnFor)

Hmmm... why would you .create, and then assign it to SUPOT_Start? That's creating a struct instance, then losing the reference to it in favour of a non-existant struct (since, as far as I know, struct instances aren't magically allocated if you don't .create them)

The supot struct is private, so how are people supposed to set a struct var to it (even if they make a seemingly* identical struct, it won't be the same, so they can't modify anything)

Ahm... does the StartSpawnBJ function even work? It's not doing anything other than returning x[num] (and it's not incrementing num either, so you could have overwritten instances)

*It may be indentical in name and members, but public/private syntax will differentiate them

(Can't test the map right now, but based on the above, I can't see how alot of this will even work with latest version)
 

emjlr3

Change can be a good thing
Reaction score
395
i had alreayd relayed all that to him after he posted over im
 
General chit-chat
Help Users
  • No one is chatting at the moment.
  • The Helper The Helper:
    The bots will show up as users online in the forum software but they do not show up in my stats tracking. I am sure there are bots in the stats but the way alot of the bots treat the site do not show up on the stats
  • Varine Varine:
    I want to build a filtration system for my 3d printer, and that shit is so much more complicated than I thought it would be
  • Varine Varine:
    Apparently ABS emits styrene particulates which can be like .2 micrometers, which idk if the VOC detectors I have can even catch that
  • Varine Varine:
    Anyway I need to get some of those sensors and two air pressure sensors installed before an after the filters, which I need to figure out how to calculate the necessary pressure for and I have yet to find anything that tells me how to actually do that, just the cfm ratings
  • Varine Varine:
    And then I have to set up an arduino board to read those sensors, which I also don't know very much about but I have a whole bunch of crash course things for that
  • Varine Varine:
    These sensors are also a lot more than I thought they would be. Like 5 to 10 each, idk why but I assumed they would be like 2 dollars
  • Varine Varine:
    Another issue I'm learning is that a lot of the air quality sensors don't work at very high ambient temperatures. I'm planning on heating this enclosure to like 60C or so, and that's the upper limit of their functionality
  • Varine Varine:
    Although I don't know if I need to actually actively heat it or just let the plate and hotend bring the ambient temp to whatever it will, but even then I need to figure out an exfiltration for hot air. I think I kind of know what to do but it's still fucking confusing
  • The Helper The Helper:
    Maybe you could find some of that information from AC tech - like how they detect freon and such
  • Varine Varine:
    That's mostly what I've been looking at
  • Varine Varine:
    I don't think I'm dealing with quite the same pressures though, at the very least its a significantly smaller system. For the time being I'm just going to put together a quick scrubby box though and hope it works good enough to not make my house toxic
  • Varine Varine:
    I mean I don't use this enough to pose any significant danger I don't think, but I would still rather not be throwing styrene all over the air
  • The Helper The Helper:
    New dessert added to recipes Southern Pecan Praline Cake https://www.thehelper.net/threads/recipe-southern-pecan-praline-cake.193555/
  • The Helper The Helper:
    Another bot invasion 493 members online most of them bots that do not show up on stats
  • Varine Varine:
    I'm looking at a solid 378 guests, but 3 members. Of which two are me and VSNES. The third is unlisted, which makes me think its a ghost.
    +1
  • The Helper The Helper:
    Some members choose invisibility mode
    +1
  • The Helper The Helper:
    I bitch about Xenforo sometimes but it really is full featured you just have to really know what you are doing to get the most out of it.
  • The Helper The Helper:
    It is just not easy to fix styles and customize but it definitely can be done
  • The Helper The Helper:
    I do know this - xenforo dropped the ball by not keeping the vbulletin reputation comments as a feature. The loss of the Reputation comments data when we switched to Xenforo really was the death knell for the site when it came to all the users that left. I know I missed it so much and I got way less interested in the site when that feature was gone and I run the site.
  • Blackveiled Blackveiled:
    People love rep, lol
    +1
  • The Helper The Helper:
    The recipe today is Sloppy Joe Casserole - one of my faves LOL https://www.thehelper.net/threads/sloppy-joe-casserole-with-manwich.193585/
  • The Helper The Helper:
    Decided to put up a healthier type recipe to mix it up - Honey Garlic Shrimp Stir-Fry https://www.thehelper.net/threads/recipe-honey-garlic-shrimp-stir-fry.193595/
  • The Helper The Helper:
    Here is another comfort food favorite - Million Dollar Casserole - https://www.thehelper.net/threads/recipe-million-dollar-casserole.193614/

      The Helper Discord

      Members online

      No members online now.

      Affiliates

      Hive Workshop NUON Dome World Editor Tutorials

      Network Sponsors

      Apex Steel Pipe - Buys and sells Steel Pipe.
      Top