Discussion Spawn 2.0 Project Started

Nestharus

o-o
Reaction score
84
Yea, I know, back to Spawn ; O, but this time it's a very interesting design. Bringing it up here to see if anyone has some other ideas besides the ones I'm currently doing = ). This is being written in vJASS and is 100% OO.

Again, if you see any features listed here that you are thinking might be a bad idea, let me know. If you think of some features that aren't listed here that you think might rock, let me know : D. If you know some better designs than some of the ones that I am using, that too would be nice = ).

Quicko Description
For those who don't know, Spawn is used to create things. Think of a Cartesian graph with an origin and dots. The origin is what the handle references and the dots are what the origin references (origin = owner and dots = spawns like barracks on footmen wars spawning footmen).

Storage
Spawn runs off of a couple of hashtables and *0* interfaces. Nodes on the hashtables are all matrix style, meaning each node instance is derived from the instances that are linked up by it (like a database). For example, if an origin was instance 40 and a spawn was 30, it'd be 40, 30 as the node.

Origin System
Spawn 2.0 only supports locations, items, and units. It does not support regular coordinates!

Recursive Ownership
Origins have recursive ownership: they can be owned by origins and those origins can in turn be owned by origins. Owned origins get their player/coordinate information from their owner. For example, let's say there is an item with a spawn on it. The item is placed into a backpack. The backpack is the current owner: wherever the backpack is, the item is, and whichever player owns the backpack owns the item. The backpack is picked up by a unit, meaning that the backpack's location is the unit's location and the player that owns the unit owns the backpack.

item -> backpack -> unit

Origin is always the root origin.

Furthermore, each origin can have multiple root origins, so like if you have a base that has multiple spawn points, that base can be owned by all of those points (0 spawn at the spot itself!)

Multiple Origins
I'll also have a value for origins to determine how much of the spawn they get. Anything above 1 means that they get a relative portion of the spawn. For example, total spawn count of 9 with 3 origins would give the specific origin 3 spawns. 0 means it gets nothing. The numbers are rounded down =).
Edit- Multiple Origins removed
Edit- Share spawns added

Origin Charges
Origins get a bonus on spawns based on the charge they have. Items automatically retrieve the charge on the item.

Origins for Items
Whenever an item gets picked up or dropped by a unit, the origin is automatically transferred to the unit.

Item Stacking?
Item Stacking won't be supported and I don't suggest it be supported as each specific item can have its own spawns, meaning you'll have to merge the spawns and then somehow split them up >.<...

Origin Garbage Collector
Keeping track of which handles may have spawns and which may not have spawns and running deallocation and so on can be a major hassle. The system does it for you with a timer that runs 5 times per second (not much overhead). The timer itself just runs through a linked list. Everything is handled perfectly. Furthermore, origins are updated.

Example-
item -> backpack -> unit

backpack is deallocated

item -> unit


Spawns
Still designing some of this part, but I plan for relative spawn coords, hard spawn coods, placement algorithms, and so on. Not sure how to do this without interfaces, but I will use 0 interfaces for this (I'm very determined o-o). It's possible that I'll just have a trigger that you add your condition to and just have you code your own spawn, that way you can do w/e you want.

Multiple origins for Spawns
Spawn Counts

Archival Support
Archival Support is like undo/redo for spawns. This happens when an origin lends a spawn to another origin.

Spawn Operations:
Revert(steps)- sends the spawn back x steps
Root- sends the spawn to root owner

Origin Operations:
Revert(steps)- sends all borrowed spawns back x steps
Root- sends all borrowed spawns back to origin owners



What happens when an origin is destroyed?
All spawns the origin is borrowing revert
All spawns the origin is lending are destroyed
All origins referencing this origin reference this origin's origin
All spawns the origin has are destroyed
The origin's instance is recycled


How does an origin get destroyed?
When the origin no longer exists (unit decayed or w/e) or the destroy method is called.

When are an origin's spawns disabled?
While the origin is dead (units only as items go out of scope when they die)

What happens if I try to create more than 1 origin from the same handle?
the handle's origin instance is returned. Just use create() whenever you want to access a handle's origin instance as that'll either make a new one or return the one that's already made : P.

Why can't I make more than one origin instance per handle?
That's idiotic... add new spawns to the origin >.<...

I want to spawn at the handle and other origins all with the same spawn, but adding new origins to the original origin would make spawns stop spawning at that original origin
Uh huh... try adding the spawn to multiple origins then =).


How complicated is this system?
Not nearly as complicated as Spawn 1.0 : P.


Why are you not supporting regular coordinates yet you support locations?
Locations can be referenced by multiple things... coordinates require syncing : (.
 

Nestharus

o-o
Reaction score
84
Well, I'm just about done with plain old origins.

So far 4 hashtables. After I finish the rest, I'm estimating about 10 hashtables total.

Here is a look at the API ; P.

JASS:
struct Origin extends array
        public method operator origin takes nothing returns Origin
        public method operator origin= takes Origin origin returns nothing
        public method share takes thistype origin, boolean b returns nothing
        public method nextShare takes thistype node returns thistype

        //returns root origin properties
        public method operator owner takes nothing returns player
        public method operator owner= takes player p returns nothing
        public method operator facing takes nothing returns real
        public method operator facing= takes real face returns nothing
        public method operator x takes nothing returns real
        public method operator x= takes real val returns nothing
        public method operator y takes nothing returns real
        public method operator y= takes real val returns nothing

        //returns this origin properties
        public method operator charge takes nothing returns integer
        public method operator charge= takes integer val returns nothing
        public method operator enabled takes nothing returns boolean
        public method operator enabled= takes boolean b returns nothing

        //destruction
        public method destroy takes nothing returns nothing
endstruct


And the create only stuff =)
JASS:
struct OriginUnit extends array
        public static method create takes unit u returns thistype
endstruct

struct OriginItem extends array
        public static method create takes item i returns thistype
endstruct

struct OriginLocation extends array
        public static method create takes location l returns thistype
endstruct



That's all the stuff that is exposed at the moment. Rest is private.


This is a look at the garbage collector-
JASS:
//
        private static method collector takes nothing returns nothing
            local thistype this = thistype(NULL).next //NULL.next is the first node to check for garbage
            
            loop
                exitwhen this == NULL //exit when null
                
                //check to see if the handle still exists. Because there is no LoadAgentHandle,
                //need to check whether it is a location or a widget
                //if loading the handle returns null, that means the handle doesn&#039;t exist
                //for the pointer in the hashtable
                if (type == DataType.LOCATION) then
                    if (LoadLocationHandle(Data.agentHandle, this, 0) == null) then
                        call deallocate()
                    endif
                elseif (LoadWidgetHandle(Data.agentHandle, this, 0) == null) then
                    call deallocate()
                endif

                set this = next
            endloop
            
            //if the list is empty, stop the garbage collector
            if (thistype(NULL).next == NULL) then
                set garbageRunning = false
                call PauseTimer(garbageTimer)
            endif
        endmethod


Garbage Collector runs like this again so that you don't have to worry about any of the handles. It loops through all handles that are acting as origins and finds all of the ones that no longer exist.

Update
Removing an origin will make origins referencing it as an origin go NULL rather than reference its origin's origin. It makes more sense.

For example-
item -> backpack -> unit
remove backpack

item -> null

Deallocation Method (will be updated as new things are added, like Spawns and Archival Lists)-
JASS:
//
        public method deallocate takes nothing returns nothing
            local thistype ref
            //only deallocate if the origin is allocated
            if (allocated) then
                //recycle
                set recycle[recycleCount] = this
                set recycleCount = recycleCount + 1
                set allocated = false
                
                //remove the saved handle. This is important for recycling handle ids
                call RemoveSavedHandle(agentHandle, this, 0)
                
                //remove from garbage collector. Garbage collector will stop on its own if empty
                set next.previous = previous
                set previous.next = next
                
                //unset origins
                loop
                    set ref = nextRef(NULL)
                    exitwhen ref == NULL
                    set ref.origin = NULL
                endloop
                
                //remove from shared lists
                loop
                    set ref = shareRefNext(NULL)
                    exitwhen ref == NULL
                    call ref.share(this, false)
                endloop
                
                //break off shares with other origins
                loop
                    set ref = shareNext(NULL)
                    exitwhen ref == NULL
                    call share(ref, false)
                endloop
                
                //unset all values
                set origin = NULL
                set type = NULL
                set charge = NULL
                set owner = null
                set facing = NULL
                set enabled = false
            endif
        endmethod
 

Nestharus

o-o
Reaction score
84
Actually I am using the lessons i learned from Spawn 1.0 in making Spawn 2.0 ^.^

All I really need to do now is link up origins and spawns and do archival stuffs (lend, revert, retrieve, scatter, retrieveAll, root).

Oh well, I think the basic Spawn API is about ready to go ^.^.

JASS:
//
    struct Spawn extends array
        //get should be used when a spawn trigger fires. It returns the spawn instance of that trigger
        public static method operator get takes nothing returns thistype
        //onSpawn is the spawn trigger. Register your own events to this.
        public method operator onSpawn takes nothing returns trigger

        //code adds and manages code for the spawn trigger. A spawn trigger may only have one boolexpr ; O.
        public method operator code takes nothing returns boolexpr
        public method operator code= takes boolexpr c returns nothing

        //type is for integer ids, like &#039;hpea&#039;
        public method operator type takes nothing returns integer
        public method operator type= takes integer val returns nothing
        //spawn type is for w/e you want, but could be used for polymorphism
        public method operator spawnType takes nothing returns integer
        public method operator spawnType= takes integer val returns nothing
        //number of spawns to spawn
        public method operator count takes nothing returns integer
        public method operator count= takes integer val returns nothing
        //this clears out all events on the trigger
        public method resetEvents takes nothing returns nothing
        //creates a spawn
        public static method create takes nothing returns thistype
        //clones the spawn (except for trigger events /cry)
        public method clone takes nothing returns thistype
        //mimics a spawn (except for trigger events). The mimic instance goes on to what is called a mimic stack.
        //mimic does not stay sync&#039;d, it simply copies the values that the targeted spawn currently has
        //mimic can be called as many times as you like
        public method mimic takes thistype spawn returns nothing
        //determines whether or not the spawn is mimicing or not
        public method operator mimicing takes nothing returns boolean
        //pops off the mimic stack if the stack isn&#039;t empty.
        public method popMimic takes nothing returns nothing
        //clears out the mimic stack
        public method self takes nothing returns nothing
        //destroys the spawn
        public method destroy takes nothing returns nothing
    endstruct



The spawn struct has no actual data inside of it. It is a composite object made up of three objects-

SpawnNode - SpawnStat
SpawnStack

Each Spawn is actually a stack. SpawnNode objects have the same instances as SpawnStat objects

When a spawn mimics another spawn, a new spawn stat object is pushed on to its internal stack.

the mimic stack is an array

The stack instance and the nodes within it are entirely separate, so pushing on to the stack will not change the stack's head.

Now so that I can possibly get feedback and fix any mistakes I might not have seen, here is current Spawn Struct code = ).

Also, please let me know if you know of a better design than the one I'm using ^.^, ty ty

Spawn Struct Code (subject to change)
JASS:
library Spawn
    globals
        private constant integer NULL = 0
    endglobals

    //manages spawn stats
    private struct SpawnStats extends array
        public static hashtable instance = InitHashtable()
        
        public integer count
        public integer type
        public integer spawnType
        
        public triggercondition tc
        public boolexpr onSpawnCode
        public integer onSpawnId
        public trigger onSpawn
        
        public method destroy takes nothing returns nothing
            set count = NULL
            set type = NULL
            set spawnType = NULL
            call DisableTrigger(onSpawn)
            if (tc != null) then
                call TriggerRemoveCondition(onSpawn, tc)
                set tc = null
            endif
            call DestroyTrigger(onSpawn)
            call RemoveSavedInteger(instance, onSpawnId, 0)
            set onSpawn = null
            set onSpawnCode = null
            set onSpawnId = NULL
        endmethod
    endstruct
    
    private struct SpawnNode extends array
        //instance vars
        private static integer instanceCount = NULL
        private static SpawnStats array recycle
        private static integer recycleCount = NULL
        
        //stack pointer
        private thistype next
        
        private static method allocate takes nothing returns thistype
            if (recycleCount != NULL) then
                set recycleCount = recycleCount - 1
                return recycle[recycleCount]
            endif
            
            set instanceCount = instanceCount + 1
            return instanceCount
        endmethod
        
        public static method create takes nothing returns thistype
            return allocate()
        endmethod
        
        public method operator getNext takes nothing returns thistype
            return next
        endmethod
        
        public method push takes nothing returns thistype
            local thistype new = allocate()
            set new.next = this
            call DisableTrigger(SpawnStats(this).onSpawn)
            return new
        endmethod
        
        public method destroy takes nothing returns nothing
            set recycle[recycleCount] = this
            set recycleCount = recycleCount + 1
            call SpawnStats(this).destroy()
        endmethod
        
        public method pop takes nothing returns thistype
            call destroy()
            call EnableTrigger(SpawnStats(next).onSpawn)
            return next
        endmethod
    endstruct
    
    private struct SpawnStack extends array
        //instance vars
        private static integer instanceCount = NULL
        private static thistype array recycle
        private static integer recycleCount = NULL
        
        private SpawnNode stack
        
        public static method create takes nothing returns thistype
            local thistype this
            if (recycleCount != null) then
                set recycleCount = recycleCount - 1
                set this = recycle[recycleCount]
            else
                set instanceCount = instanceCount + 1
                set this = instanceCount
            endif
            
            set stack = SpawnNode.create()
            return this
        endmethod
        
        public method operator spawn takes nothing returns SpawnStats
            return stack
        endmethod
        
        public method push takes nothing returns nothing
            set stack = stack.push()
        endmethod
        
        public method pop takes nothing returns nothing
            set stack = stack.pop()
        endmethod
        
        public method destroy takes nothing returns nothing
            loop
                exitwhen stack == 0
                call stack.destroy()
                set stack = stack.getNext
            endloop
            set recycle[recycleCount] = this
            set recycleCount = recycleCount + 1
        endmethod
        
        public method clear takes nothing returns nothing
            loop
                exitwhen stack.getNext == 0
                call stack.destroy()
                set stack = stack.getNext
            endloop
            
            call EnableTrigger(spawn.onSpawn)
        endmethod
    endstruct
    
    struct Spawn extends array
        public static method operator get takes nothing returns thistype
            return LoadInteger(SpawnStats.instance, GetHandleId(GetTriggeringTrigger()), 0)
        endmethod
        
        public method operator onSpawn takes nothing returns trigger
            return SpawnStack(this).spawn.onSpawn
        endmethod
        
        private method operator tc takes nothing returns triggercondition
            return SpawnStack(this).spawn.tc
        endmethod
        
        private method operator tc= takes triggercondition val returns nothing
            set SpawnStack(this).spawn.tc = val
        endmethod
        
        public method operator code takes nothing returns boolexpr
            return SpawnStack(this).spawn.onSpawnCode
        endmethod
        
        public method operator code= takes boolexpr c returns nothing
            if (tc != null) then
                call TriggerRemoveCondition(onSpawn, tc)
            endif
            set SpawnStack(this).spawn.onSpawnCode = c
            if (c != null) then
                set tc = TriggerAddCondition(onSpawn, c)
            else
                set tc = null
            endif
        endmethod
        
        private method operator onSpawnId takes nothing returns thistype
            return SpawnStack(this).spawn.onSpawnId
        endmethod
        
        private method operator onSpawnId= takes integer val returns nothing
            set SpawnStack(this).spawn.onSpawnId = val
        endmethod
        
        public method operator type takes nothing returns integer
            return SpawnStack(this).spawn.type
        endmethod
        
        public method operator type= takes integer val returns nothing
            set SpawnStack(this).spawn.type = val
        endmethod
        
        public method operator spawnType takes nothing returns integer
            return SpawnStack(this).spawn.spawnType
        endmethod
        
        public method operator spawnType= takes integer val returns nothing
            set SpawnStack(this).spawn.spawnType = val
        endmethod
        
        public method operator count takes nothing returns integer
            return SpawnStack(this).spawn.count
        endmethod
        
        public method operator count= takes integer val returns nothing
            set SpawnStack(this).spawn.count = val
        endmethod
        
        private method operator onSpawn= takes trigger t returns nothing
            set SpawnStack(this).spawn.onSpawn = t
            set onSpawnId = GetHandleId(t)
            call SaveInteger(SpawnStats.instance, onSpawnId, 0,  this)
        endmethod
        
        public method resetEvents takes nothing returns nothing
            call DisableTrigger(onSpawn)
            
            if (code != null) then
                call TriggerRemoveCondition(onSpawn, tc)
            endif
            
            call RemoveSavedInteger(SpawnStats.instance, onSpawnId, 0)
            call DestroyTrigger(onSpawn)
            
            set onSpawn = CreateTrigger()
            
            if (code != null) then
                call TriggerAddCondition(onSpawn, code)
            endif
        endmethod
        
        public static method create takes nothing returns thistype
            local thistype this = SpawnStack.create()
            
            set onSpawn = CreateTrigger()
            
            return this
        endmethod
        
        private method copyTo takes thistype to returns thistype
            set to.count = count
            set to.type = type
            set to.spawnType = spawnType
            set to.code = code
            return to
        endmethod
        
        public method clone takes nothing returns thistype
            return copyTo(create())
        endmethod
        
        public method mimic takes thistype spawn returns nothing
            call SpawnStack(this).push()
            set onSpawn = CreateTrigger()
            call spawn.copyTo(this)
        endmethod
        
        public method operator mimicing takes nothing returns boolean
            return SpawnNode(SpawnStack(this).spawn).getNext != 0
        endmethod
        
        public method popMimic takes nothing returns nothing
            if (mimicing) then
                call SpawnStack(this).pop()
            endif
        endmethod
        
        public method self takes nothing returns nothing
            call SpawnStack(this).clear()
        endmethod
        
        public method destroy takes nothing returns nothing
            call SpawnStack(this).destroy()
        endmethod
    endstruct
endlibrary


Test code (demonstrates mimic stack)
JASS:
scope Test
/////////////Test Code
    private function Bleh1 takes nothing returns boolean
        local Spawn spawn = Spawn.get
        
        call DisplayTextToPlayer(GetLocalPlayer(), 0, 0, I2S(spawn) + &quot; is on Bleh1!&quot;)
        
        call spawn.popMimic()
        
        return false
    endfunction
    
    private function Bleh2 takes nothing returns boolean
        local Spawn spawn = Spawn.get
        
        call DisplayTextToPlayer(GetLocalPlayer(), 0, 0, I2S(spawn) + &quot; is on Bleh2!&quot;)
        
        call spawn.popMimic()
        
        return false
    endfunction
    
    private function Bleh3 takes nothing returns boolean
        local Spawn spawn = Spawn.get
        
        call DisplayTextToPlayer(GetLocalPlayer(), 0, 0, I2S(spawn) + &quot; is on Bleh3!&quot;)
        
        call spawn.popMimic()
        
        return false
    endfunction
    
    private struct Tester extends array
        private static timer t
        private static boolexpr bleh1
        private static boolexpr bleh2
        private static boolexpr bleh3
        
        private static method onInit takes nothing returns nothing
            local Spawn spawn1 = Spawn.create()
            local Spawn spawn2 = Spawn.create()
            local Spawn spawn3 = Spawn.create()
            set t = CreateTimer()
            call TriggerRegisterTimerExpireEvent(spawn1.onSpawn, t)
            call TriggerRegisterTimerExpireEvent(spawn2.onSpawn, t)
            call TriggerRegisterTimerExpireEvent(spawn3.onSpawn, t)
            set bleh1 = Condition(function Bleh1)
            set bleh2 = Condition(function Bleh2)
            set bleh3 = Condition(function Bleh3)
            set spawn1.code = bleh1
            set spawn2.code = bleh2
            set spawn3.code = bleh3
            call spawn3.mimic(spawn2)
            call TriggerRegisterTimerExpireEvent(spawn3.onSpawn, t)
            call spawn3.mimic(spawn1)
            call TriggerRegisterTimerExpireEvent(spawn3.onSpawn, t)
            call spawn2.mimic(spawn1)
            call TriggerRegisterTimerExpireEvent(spawn2.onSpawn, t)
            
            call TimerStart(t, 5, true, null)
        endmethod
    endstruct
endscope



Don't like the look of the mass registered triggers above? You can always do something like this-
JASS:
scope TestCode
    private function Bleh1 takes nothing returns boolean
        local Spawn spawn = Spawn.get
        
        call DisplayTextToPlayer(GetLocalPlayer(), 0, 0, I2S(spawn) + &quot; is on Bleh1!&quot;)
        
        call spawn.popMimic()
        
        return false
    endfunction
    
    private function Bleh2 takes nothing returns boolean
        local Spawn spawn = Spawn.get
        
        call DisplayTextToPlayer(GetLocalPlayer(), 0, 0, I2S(spawn) + &quot; is on Bleh2!&quot;)
        
        call spawn.popMimic()
        
        return false
    endfunction
    
    private function Bleh3 takes nothing returns boolean
        local Spawn spawn = Spawn.get
        
        call DisplayTextToPlayer(GetLocalPlayer(), 0, 0, I2S(spawn) + &quot; is on Bleh3!&quot;)
        
        call spawn.popMimic()
        
        return false
    endfunction
    
    struct SpawnE extends array
        private static hashtable h = InitHashtable()
        private delegate Spawn spawnD
        private integer onSpawnId
        public trigger onSpawn
        
        private static method operator get takes nothing returns Spawn
            return LoadInteger(h, GetHandleId(GetTriggeringTrigger()), 0)
        endmethod
        
        private static method run takes nothing returns boolean
            call TriggerEvaluate(get.onSpawn)
            return false
        endmethod
        
        public static method create takes nothing returns thistype
            local thistype this = Spawn.create()
            set spawnD = this
            set onSpawn = CreateTrigger()
            set onSpawnId = GetHandleId(onSpawn)
            call SaveInteger(h, onSpawnId, 0, this)
            call TriggerAddCondition(onSpawn, Condition(function thistype.run))
            return spawnD
        endmethod
        
        public method destroy takes nothing returns nothing
            call Spawn(this).destroy()
            call DisableTrigger(onSpawn)
            call TriggerClearConditions(onSpawn)
            call DestroyTrigger(onSpawn)
            call RemoveSavedInteger(h, onSpawnId, 0)
            set onSpawnId = 0
        endmethod
    endstruct
    
    private struct Tester extends array
        private static timer t
        private static boolexpr bleh1
        private static boolexpr bleh2
        private static boolexpr bleh3
        private static trigger tr = CreateTrigger()
        
        private static method onTr takes nothing returns boolean
            return false
        endmethod
        
        private static method onInit takes nothing returns nothing
            local SpawnE spawn1 = SpawnE.create()
            local SpawnE spawn2 = SpawnE.create()
            local SpawnE spawn3 = SpawnE.create()
            set t = CreateTimer()
            call TriggerRegisterTimerExpireEvent(spawn1.onSpawn, t)
            call TriggerRegisterTimerExpireEvent(spawn2.onSpawn, t)
            call TriggerRegisterTimerExpireEvent(spawn3.onSpawn, t)
            set bleh1 = Condition(function Bleh1)
            set bleh2 = Condition(function Bleh2)
            set bleh3 = Condition(function Bleh3)
            set spawn1.code = bleh1
            set spawn2.code = bleh2
            set spawn3.code = bleh3
            call spawn3.mimic(spawn2)
            call spawn3.mimic(spawn1)
            call spawn2.mimic(spawn1)
            
            call TimerStart(t, 5, true, null)
        endmethod
    endstruct
endscope



edit
=========================
After writing some demo code of features I haven't written yet, I decided to add quite a few features

Adding-

root origin (actual location/owner etc of the origin)
multi origins (for scattering spawns)
spawns (for disabling root origin spawn)
enabled (for disabling origin spawn, meaning everything)

spawn max (total spawns of a spawn that can be up at a time specific to an origin)
origin max (total spawns an origin can have up at a time)


The demo code I wrote
JASS:
struct SpawnUnit extends array
    private static boolexpr runn
    
    public static method runX takes nothing returns boolean
        local Spawn spawn = Spawn.get
        
        //! runtextmacro SPAWN_START()
            call CreateUnit(spawn.owner, spawn.type, spawn.x, spawn.y, spawn.facing)
        //! runtextmacro SPAWN_END()
        
        return false
    endmethod
    
    public static method operator run takes nothing returns boolexpr
        return Condition(thistype.runn)
    endmethod
    
    private static method onInit takes nothing returns nothing
        set runn = Condition(function thistype.runX)
    endmethod
endstruct

struct TimedSpawn extends array
    implement Spawn
    
    private timer t
    private real timeout
    
    public static method create takes real timeout returns thistype
        local thistype this = allocate()
        set t = CreateTimer()
        set this.timeout = timeout
    endmethod
    
    public method start takes nothing returns nothing
        call TimerStart(t, timeout, true, this.code)
    endmethod
    
    public method stop takes nothing returns nothing
        call PauseTimer(t)
    endmethod
    
    public method operator time takes nothing returns real
        return timeout
    endmethod
    
    public method operator time= takes real val returns nothing
        set timeout = val
        call start()
    endmethod
    
    public method destoy takes nothing returns nothing
        call PauseTimer(t)
        call DestroyTimer(t)
        set t = null
    endmethod
endstruct

struct RangeSpawn extends array
    implement Spawn
    private unit rootX
    private real rangeX
    
    private static method filter takes nothing returns boolean
        return IsUnitEnemy(GetFilterUnit(), GetOwningPlayer(thistype(Spawn.get).rootX))
    endmethod
    
    private method resetEvents takes nothing returns nothing
        call resetEvents()
        if (rootX != null) then
            call TriggerRegisterUnitInRange(onSpawn, rootX, rangeX, Condition(function thistype.filter))
        endmethod
    endmethod
    
    public static method create takes real range, unit root returns thistype
        local thistype this = allocate()
        set rangeX = range
        set code = SpawnUnit.run
        set rootX = root
        if (rootX != null) then
            call TriggerRegisterUnitInRange(onSpawn, rootX, rangeX, Condition(function thistype.filter))
        endif
        return this
    endmethod
    
    public method operator range takes nothing returns real
        return rangeX
    endmethod
    
    public method operator range= takes real val returns nothing
        set rangeX = val
        call resetEvents()
    endmethod
    
    public method operator root takes nothing returns unit
        return rootX
    endmethod
    
    public method operator root= takes unit u returns nothing
        set rootX = u
        call resetEvents()
    endmethod
    
    public method destroy takes nothing returns nothing
        call deallocate()
        set rootX = null
    endmethod
endstruct

struct Soldier extends array
    private delegate TimedSpawn spawn
    public constant static real TIMEOUT = 15
    public constant static integer COUNT = 1
    public constant integer ID = &#039;hfoo&#039;
    
    public static method create takes nothing returns thistype
        local thistype this = TimedSpawn.create(TIMEOUT)
        set spawn = this
        set spawn.code = SpawnUnit.run
        set spawn.count = COUNT
        set spawn.type = ID
        
        return this
    endmethod
    
    public method destroy takes nothing returns nothing
        call spawn.destroy()
    endmethod
endstruct

struct Bodyguard extends array
    private delegate RangeSpawn spawn
    public static constant real RANGE = 500
    public static constant integer MAX = 16
    public static constant integer REPLENISH = 4
    public static constant integer ID = &#039;hkni&#039;
    
    public static method create takes unit u returns thistype
        local thistype this = RangeSpawn.create(RANGE, u)
        set spawn = this
        set spawn.count = COUNT
        set spawn.max = MAX
        set spawn.type = ID
        
        return this
    endmethod
    
    public method destroy takes nothing returns nothing
        call spawn.destroy()
    endmethod
endstruct

struct Army extends array
    implement Origin
    
    public static method create takes nothing returns thistype
        return allocate()
    endmethod
    
    public method addPoint takes Origin spawnPoint returns nothing
        call share(spawnPoint, true)
        set spawnPoint.owner = owner
    endmethod
    
    public method destroy takes nothing returns nothing
        call deallocate()
        set powerX = 0
    endmethod
endstruct

scope Tester initializer init
    private function init takes nothing returns nothing
        //create a ring that commands all of the spawn points of an army
        //the one who picks up the ring controls the army!! : o
        local Army army = OriginItem.create(CreateItem(&#039;dsum&#039;, 125, 125))
        set army.spawns = false //does not spawn at origin, but shared will still work
        //enable = false disables entire thing
        
        //create some spawn points for the ring
        //a square ^.^
        local Origin origin1 = OriginLocation.create(Location(50, 50))
        local Origin origin2 = OriginLocation.create(Location(0, 50))
        local Origin origin3 = OriginLocation.create(Location(50, 0))
        local Origin origin4 = OriginLocation.create(Location(0, 0))
        
        //and how about an officer that spawns bodyguards
        local unit u = CreateUnit(Player(0), &#039;Hpal&#039;, 25, 25, 0)
        local Origin officer = OriginUnit.create(u)
        
        //addPoint does a share and sets owner of point to army.owner
        call army.addPoint(origin1)
        call army.addPoint(origin2)
        call army.addPoint(origin3)
        call army.addPoint(origin4)
        call army.addPoint(officer)
        
        //now for some spawns!!
        //let&#039;s give the officer some bodyguards
        call officer.add(Bodyguard.create(u))
        //this guy will replenish 4 spawns every time a unit comes in range, so don&#039;t run away
        
        //each origin will spawn 1 soldier
        call origin1.addSpawn(Soldier.create())
        call origin2.addSpawn(Soldier.create())
        call origin3.addSpawn(Soldier.create())
        call origin4.addSpawn(Soldier.create())
        
        //and entire army will get a soldier bonus
        call army.addSpawn(Soldier.create())
    endfunction
endscope
 
General chit-chat
Help Users
  • No one is chatting at the moment.
  • Varine Varine:
    How can you tell the difference between real traffic and indexing or AI generation bots?
  • 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 Discord

      Members online

      Affiliates

      Hive Workshop NUON Dome World Editor Tutorials

      Network Sponsors

      Apex Steel Pipe - Buys and sells Steel Pipe.
      Top