• 🏆 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!
  • It's time for the first HD Modeling Contest of 2024. Join the theme discussion for Hive's HD Modeling Contest #6! Click here to post your idea!

[vJASS][System]SPAWN

Level 31
Joined
Jul 10, 2007
Messages
6,306
Spawn-
Spawn System


"The First for All Purpose Spawning"
---------------------------------------------------------

News Count- 9
Written: 7-15-09


I'm doing a new style. All example code will be able to be copy and pasted from documentation straight into the map and will immediately work. When handles are created with player owners, they will be created for Player 1 always.

I will also have a demo map attached to this that contains the latest Spawn and all of it's requirements. The example map will have an area where code can be pasted in. To run an example from the guide, copy the example code, paste it into the demo map's demo area, save, hit test map, done. There will also be 12 player slots so that you can play around with it online with your friends.

Also to help with learning and playing around with various features, you can play around with the example code and change things to see what happens.

I'm working very hard on this because I believe that the system is quite hard to learn as there is just so much.

Methods- none done
Variables- none done
Objects- none done
Interfaces- basic descriptions and Handle interface done
Functions- done

I swear this thing is ganna be 200 pages...


Note-
You must have a defined handle type that extends on Handle for this to work. If you do not, vjass will bug up. Why don't I just declare some private empty struct that extends on Handle? Because you should always have at least one handle type, otherwise why would you use this?

Is there any way for me to fix it so you don't have to have one? Only way is to declare some random private empty struct, and you might as well either get a premade object from me or just make ur own empty one to add on to later.

Example-
JASS:
public struct MyOwnHandleType extends Spawn_Handle
endstruct


Current-
Version- .01b
Compatibility Number- 2

To Be Released-
Version- .01c
Compatibility Number- 3

Requirements-
Mfn v.02a CN 29

Documentation Estimate (in pages)-
130 - 160



Feel free to give suggestions for when this amazing version that will use Vgn

For suggestions, keep in mind that Vgn deals with Virtual Grids, meaning that grids can be created instantly over an area and the cells within that grid can be quickly and easily accessed. That is how these rooms and everything can be created, and that is how dynamic instancing is done.

Vgn also supports quite a few other things that will be useful to this for physical dynamic instancing.


Structures
Floors
Rooms

Physical Dynamic Instancing
Dynamic Instancing of Data
Ownership Tracking
Room types
Floor types
Structure types
Modifications to rooms, floors, and structures with spiffy modify
Add and remove rooms from floors
Add and remove floors from structures
Add and remove structures from base
Link rooms
Link floors
Link structures (spiffy)
Bases inside of interiors
Paint rooms through Vgn (graphics)
Floor themes through Vgn (graphics)
Structure themes through Vgn (graphics)




Ok, I had written out a huge essay on the new features, but Mozilla became retarded and when i hit back to delete a character it went to last page. It does this from time to time. Frankly, I spent 2 hours going over the new extremely advanced features and fixes, but I don't feel like going over them at this point after writing everything out that I just did, so I'm just going to list them.

Pools (super beyond cool)
Sharing (enhances and fixes stuff ^^)
Upgrade Objects (decently cool)

At some point I'll rewrite my 5 page long essay and describe what pools are, what sharing refers to and what it fixes, and what upgrade objects are.

[/hidden]


Spawn is the ultimate in spawning with handle to base to spawn relationships (it has special added support for handles, but handles can also be treated as any sort of data such as a struct or an integer). This system was started up after I decided that the Ftmn framework was designed totally wrong and should be based off of a broader and more powerful system. Why? Because Ftmn had way too much power for a standard footmen wars map, and if it was supposed to be used for other maps, why on earth would I name it Ftmn Framework???

Spawns have full ownership tracking set up so that bases can lend and borrow spawns to any degree of any amount. Bases can get back their spawns and spawns can revert back one step, x amount of steps, or back to their original owner. Bases can also give and take spawns while maintaining ownership integrity, meaning that if a base gives a spawn that it was borrowing, that spawn will still be reverted properly and will still have its original owner. Cloning and mimicing is also provided as well as spawn disabling and enabling.

Spawn can manipulate anything that has to do with spawning. This means that it does not only spawn units like other spawn systems such as SUPOT. Spawn can spawn any handle including custom handle types. It does this through an interface and properties so that ambiguous handles can be used by it. In this way, any handle type can be created at a whim and any base can be attached to any type of handle and it will still be able to get that handle's information. What this means is that it may be used for not just spawning regular handles, but artificial ones as well like spells, effects, and attacks.

Due to all of the customizations of spawn: handle declaration, spawn method declaration, base method declaration, and spawn object declaration, spawn is best utilized for building other systems. However, it can be used directly in a map.

Because Spawn can handle all of this, people call it junk and say that it's bad at everything. However, I never said that it was good at everything, I only stated that it could handle anything when it came to spawning. Spawn is the ultimate at spawning, not the ultimate at everything, and any system that spawns anything can be run through it. It's extremely good at one thing, so it will not make spells or attach data to units. It will only do exactly what the name implies, and that is spawn.



v.01b tests removed as it is complete
No new tests until v.01c development


-News Section-


Might have noticed I changed the layout of the post. I'll be using this layout from now on : ).



More news on how close v.01b is to being released...

In fact, it is so close I can count exactly how many features are left to be completed O_O. ALL I CAN SAY IS FUAHHA YESSS!!!!

17-20 Methods!!!
Spawn Ownership Tracking
Spawn Mimicing
Base Mimicing

That... is... it O_O

While this may seem a lot to you all, it really isn't... considering how big this behemoth is : O. By the way, every other method and function and everything has been tested. The only ones that aren't tested are the ones that don't work because I am working on them : o.

Base and spawn mimicing used to 100% work, but they don't now because of how I want to do mimicing : O.

New v.01c feature list

Now accepting 10 beta testers (really people who want to get their hands on this before anyone else and maybe find some bugs that I might have missed as this thing is absolutely HUGE).

During the Beta Test, I will be frantically writing documentation for this so I can get Ftmn up, that way I can write documentation for that, get Vgn up, write more documentation (omg), and then get v.01c of this up >: O.

Please don't release the beta version ^_-, and please feel free to give feedback on Spawn while you are trying it out. At this point, I hope you reply to this post with feedback and happiness ^_^.

This is the biggest system I've done, and probably the best designed. I worked long and hard on this, and I'm so happy that I have so little left to go before this is ready to be released.

Please send me a PM (don't respond to this thread, I like it how it is right now with 0 replies, nice and clean. I'm hoping when it gets reviewed upon final release of v.01b that azn doesn't reply to the thread and PMs me instead ^_^ *hint to azn*).

In the PM, please answer these questions =).

What do you plan to use this for?
Are you experienced at vJASS?
What things have you made?
Do you know how to make a framework following Mfn conventions?



You may have noticed that I have added 2 more tests... yes, that is right, more methods are done and 1 feature is fully done: ownership tracking of spawns.

What does that leave?
Mimicing

Or like 5 methods..

By the way, I've had 0 applicants so far. I promise you I've already tested everything out and made sure it was working. Really, if you do find a bug it'll be a shocker o-o, it's more that you get to try it out before anyone else while I write documentation. You'll also be able to suggest some features you'd like to see added to v.01b that won't be too drastic (since I will be adding a lot of new "huge" features to v.01c).

It's probably that nobody has looked at this thread though ;o.



Ok... so I had a bug for lending that really took a long time to fix... and the fact is I still haven't fixed it. I finally figured out what the bug was 2 days ago I think, but it's a bit complicated to fix. Yesterday, I figured out how to fix it. Today.. I'm fixing it -.-, which shall be a few hours...

So far, everyone I've talked to about Spawn except for two people have called this system worthless and said that it was easy to do without this huge thing.

I told them that they didn't look at the features or the tests. They said, yea, they didn't.

Just because this system handles spawning doesn't mean that it handles just basic spawning... this manages a lot -.-. For those of you who have been following this, you should let people know what this thing can do.

I'm planning to open up a beta once I get this bug fixed and then do full v.01b release with mimic features (yes, mimic is not going to be in the beta... this is just so I can get it out faster).

If all goes well with fixing the bug, and then fixing the 100 methods that are being screwed up by the bug, then the beta of this should be released in the next 8 hours.

If all doesn't go well, it should be in 2 days.

So why is mimic not going to be in the beta release? What gives?

Well, mimic was originally done... however, when I added ownership tracking for spawns, everything broke, so I had to remake a lot o-o. Mimic is probably going to be the hardest thing to remake, so rather than pushing the release back by 1 or 2 weeks, I figured that I could just do a pre-release which is only missing mimic.

Will there be documentation?
Not yet, unless someone feels like writing it right now. Because I doubt anyone's going to write it except me, it won't be out for a bit -.-. I'm too busy programming a lot... and I just spent 8 hours today looking for food, so ; D.



The beta version is out! CN 1.5 as mimic is not included in this version.

Everyone have fun! : D. Try it out, enjoy, look at all the nifty features. Hopefully I got all of the bugs (i'm 99% sure I did ^_^).

What does this beta include?
1 base per handle
unlimited spawns per base
spawn ownership tracking for borrowing and lending and reverting o-o
Cloning

The most powerful spawning system ever created for wc3 vjass O_O. Good game.



Spawn v.01b CN 2 full release and fully tested.

Included debug statements for finding bugs in your map when using it as it is very powerful. You can do anything you want, so there are some dangerous things that "are" allowed. If you know what you're doing, no issues, but if you don't, you'll run into some "map" bugs, not system bugs.



Documentation for this behemoth is now being written Oo. I'm tired of coding, so yea, get ready for spiffy documentation. I will probably do it like I did for Mfn and post documentation versions and end with latest version ^_^. The style will be my normal style for those who have seen my documentation, and it will be in a standalone exe again.

Apparently nobody has really used this yet, and I don't blame them. The only thing anyone has to go off of are my selected tests O-o.



Ok, so I have some good news and some bad news about Spawn v.01b. The good news is that it works 100% with no bugs. The bad news is that it doesn't work the way it was supposed to work, meaning I need to start working on v.01c. v.01c will include all the features included in the feature list except for base interiors. It will also have various fixes that will increase what Spawn can handle and make it work right.

1- Handles are meant to be of handle types, not of actual handles. At the moment, they are of handle types and handles...

2. Base Prototypes originally needed to be extended, but with the latest designs they don't need to be extended anymore. This means that there is no need for an interface for them, they might as well be just one struct.

With v.01c, I would have had to do these improvements and fixes for base pools and spawn pools anyways : |.

More bad news is that because I'll be working on v.01c, documentation is being halted again because I'd have to rewrite some of it anyways : \. Good news is that I did do like 30 pages : D, but I'm still formatting those 30 pages with my new style o_O.

Oh yes, more bad news. With patch 1.24, removing saved native types from a hash table no longer works. This means that hasBase and hasHandle functions both broke o_O, so I did a quick fix last night since only one person had this thing anyways. The quick fix will be there until they work again : ), but the fix is actually slower than what it was originally :\.

Also, there are a lot of people who say this to me when i talk about all purpose spawning.

What is all purpose spawning??

I respond, spawning based on anything by anything and they respond with this

Isn't that just CreateUnit()

No. CreateUnit just makes a unit, it doesn't do the same action repeatedly based on whatever. Also, CreateUnit only handles units. They then respond with this

Why not just make a system to do the specific things or w/e?

Spawn is the base for spawning systems. All you do is plug in the type of spawn you want and then do all of your "cosmetics" (graphical appearances or w/e). All of the base features like mimicing, cloning, lending, borrowing, taking, giving, reverting, reverting by steps, reverting to original owner, etc that are included in a handle to base to spawn relationship can be usable by your system. I also stated that this system can be used directly and doesn't need some system with cosmetic stuff... The difference between using it directly and using it in a system is just this

System-
Plug in your type and make a system, may have cosmetics, may not. You can do w/e features you want and you'll have access to all of Spawn's features from your system as well as enough memory to handle 8191^2 instances (shared between all things on map, more than enough) and 8191 types (shared again, but way more than enough).

Direct Use-
Plug in your type and use it...

That is why this is called all purpose spawning and that's what it is used for. If you want to spawn units over an interval, it can do it. If you want to spawn 3 spells whenever an ability is cast (3 custom spells), it can do it. Why would you want to spawn spells with this? Because if spells are treated as spawns in a handle to base to spawn relationship, you can do to them what you could do to a spawn... give, take, lend, borrow, revert, etc... The handle may be a specific unit and the spawn may be an ability. From here, all abilities, even if they are the same, can be unique to each unit.



nvm again : O. Mfn is going to include some new features and the first level to creating a system with relationships between its data : ).

This is lvl 3 tho, so I'll need to create another system on top of that one before I can work on v.01c rewrites. This system will become smaller, more powerful, and all of the current issues will be fixed.

Hurray, hurray : D.

 

Attachments

  • Spawn Demo Map.w3m
    65.1 KB · Views: 87
  • Spawn.w3m
    21.2 KB · Views: 82
Last edited:
Level 31
Joined
Jul 10, 2007
Messages
6,306
JASS:
    //! runtextmacro Mfn_CREATE_HANDLE("Handle_Unit", "unit")
    
    public struct Unit extends Spawn_Handle
        public integer h
        public hashtable memory
        
        public method make takes player p, integer typeId, real x, real y, real facing returns nothing 
            set .h = Handle_Unit.create(CreateUnit(p, typeId, x, y, facing)) 
            call SaveInteger(Spawn_memory, Mfn_HANDLE, GetHandleId(Handle_Unit(.h).h), this) 
        endmethod 

        public method change takes integer typeId returns nothing 
            local player p = .getPlayer() 
            local real x = .getX() 
            local real y = .getY() 
            local real facing = .getFacing() 
            call RemoveSavedInteger(Spawn_memory, Mfn_HANDLE, GetHandleId(Handle_Unit(.h).h)) 
            call RemoveUnit((Handle_Unit(.h).h)) 
            set Handle_Unit(.h).h = CreateUnit(p, typeId, x, y, facing) 
            call SaveInteger(Spawn_memory, Mfn_HANDLE, GetHandleId(Handle_Unit(.h).h), this) 
        endmethod 

        public method clean takes nothing returns nothing
            local unit u = Handle_Unit(.h).h
            call .destroy() 
            call RemoveUnit(u) 
            set u = null
        endmethod
        
        public method getX takes nothing returns real
            return GetUnitX((Handle_Unit(.h).h))
        endmethod
        
        public method getY takes nothing returns real
            return GetUnitY((Handle_Unit(.h).h))
        endmethod
        
        public method getPlayer takes nothing returns player
            return GetOwningPlayer((Handle_Unit(.h).h))
        endmethod
        
        public method getTypeId takes nothing returns integer
            return GetUnitTypeId((Handle_Unit(.h).h))
        endmethod
        
        public method getLevel takes nothing returns integer
            return GetUnitLevel((Handle_Unit(.h).h))
        endmethod
        
        public method getXP takes nothing returns integer
            return GetHeroXP((Handle_Unit(.h).h))
        endmethod
        
        public method getHandleId takes nothing returns integer
            return GetHandleId((Handle_Unit(.h).h))
        endmethod
        
        public method getFacing takes nothing returns real
            return GetUnitFacing((Handle_Unit(.h).h))
        endmethod
        
        public method setPosition takes real x, real y returns nothing
            call SetUnitPosition((Handle_Unit(.h).h), x, y)
        endmethod
        
        public method setPlayer takes player p returns nothing
            call SetUnitOwner((Handle_Unit(.h).h), p, false)
        endmethod
        
        public method setLevel takes integer x returns nothing
            call SetHeroLevel((Handle_Unit(.h).h), x, false)
        endmethod
        
        public method setXP takes integer x returns nothing
            call SetHeroXP((Handle_Unit(.h).h), x, false)
        endmethod
        
        public method setFacing takes real x returns nothing
            call SetUnitFacing((Handle_Unit(.h).h), x)
        endmethod

        method onDestroy takes nothing returns nothing
            call RemoveSavedInteger(Spawn_memory, Mfn_HANDLE, GetHandleId(Handle_Unit(.h).h))
            set Handle_Unit(.h).h = null
            call Handle_Unit(.h).destroy() 
            call FlushParentHashtable(this.memory)
            set .h = -1 
        endmethod
    endstruct
    
    public struct SpawnUnit extends Spawn_SpawnObject
        public method make takes player p, integer typeId, real x, real y, real facing returns nothing
            call CreateUnit(p, typeId, x, y, facing)
        endmethod
    endstruct

JASS:
library Spawn initializer ini requires Mfn
    globals
        private constant string SYSTEM = "Spawn"
        private constant string VERSION = ".01b"
        private constant integer CN = 2
        private constant string AUTHOR = "Nestharus"
        private constant string HELPERS = "None"
        private constant string TEXTURE_PATH = "ReplaceableTextures\\CommandButtons\\BTNHumanBarracks.blp"
        private constant string NAME = "Spawn"
        public hashtable memory
        
        public key DATA
        public key SPAWN
        public key CONTAINER_BASE
        public key CONTAINER_SPAWN
        public key OWNERS
        public key LENT
        public key BORROWED
        public key LENT_SPAWN
        public key BORROWED_SPAWN
        public key BASE
        public key STEPS
        public key BORROWED_SPAWN_TYPE
        public key BORROWED_SPAWN_TYPE_R
        public key FIRST_BORROWED_SPAWN
    endglobals
    
    public keyword Base
    public keyword Spawn
    public keyword Handle
    
    public function getBase takes handle u returns integer
        return LoadInteger(memory, Mfn_UNIT, GetHandleId(u))
    endfunction
    
    public function getHandle takes handle u returns integer
        return LoadInteger(memory, Mfn_HANDLE, GetHandleId(u))
    endfunction
    
    public function hasBase takes handle u returns boolean
        local integer baseOwner = Base(LoadInteger(memory, Mfn_UNIT, GetHandleId(u))).base
        local integer h = getHandle(u)
        return ((baseOwner == h) and (h > -1))
    endfunction
    
    public function hasHandle takes handle u returns boolean
        return (Handle(getHandle(u)).h > 0)
    endfunction
    
    public function giveBase takes handle u1, handle u2 returns nothing
        call Base(getBase(u1)).transfer(Handle(getHandle(u2)))
    endfunction
    
    public function takeBase takes handle u1, handle u2 returns nothing
        call Base(getBase(u2)).transfer(getHandle(u1))
    endfunction
    
    public function tradeBase takes handle u1, handle u2 returns nothing
        call Base(getBase(u1)).trade(u2)
    endfunction
    
    public function enableHandleSpawns takes handle u, boolean b returns nothing
        call Base(getBase(u)).enableSpawns(b)
    endfunction
    
    public function enableHandleSpawn takes integer s, handle u, boolean b returns nothing
        call Base(getBase(u)).enableSpawn(s, b)
    endfunction
    
    public function tradeSpawns takes handle u, handle u2 returns nothing
        call Base(getBase(u)).tradeSpawnAll(Base(getBase(u2)))
    endfunction
    
    public function borrowBase takes handle u1, handle u2 returns nothing
        call Base(getBase(u2)).lend(getHandle(u1))
    endfunction
    
    public function lendBase takes handle u1, handle u2 returns nothing
        call Base(getBase(u1)).lend(getHandle(u2))
    endfunction
    
    public function getBackBase takes handle u returns nothing
        call Base(LoadInteger(memory, Spawn_LENT, GetHandleId(u))).original()
    endfunction
    
    public function revertBase takes handle u returns nothing 
        call Base(getBase(u)).revert()
    endfunction
    
    public function originalBase takes handle u returns nothing 
        call Base(getBase(u)).original()
    endfunction
    
    public function replace takes handle u, integer typeId returns integer
        local integer h = getBase(u)
        call Spawn_Handle(Base(h).base).change(typeId)
        return h
    endfunction
    
    public interface Handle
        public integer h
        public hashtable memory
        
        public method getX takes nothing returns real defaults 0.0
        public method getY takes nothing returns real defaults 0.0
        public method getPlayer takes nothing returns player defaults null
        public method getTypeId takes nothing returns integer defaults 0
        public method getLife takes nothing returns real defaults 0.0
        public method getLevel takes nothing returns integer defaults 0
        public method getXP takes nothing returns integer defaults 0
        public method getFacing takes nothing returns real defaults 0.0
        
        public method setPosition takes real x, real y returns nothing defaults nothing
        public method setPlayer takes player p returns nothing defaults nothing
        public method setTypeId takes integer t returns nothing defaults nothing
        public method setLife takes real x returns nothing defaults nothing
        public method setLevel takes integer x returns nothing defaults nothing
        public method setXP takes integer x returns nothing defaults nothing
        public method setFacing takes real x returns nothing defaults nothing
        
        public static method create takes nothing
        
        public method make takes player p, integer typeId, real x, real y, real facing returns nothing defaults nothing
        public method getHandleId takes nothing returns integer defaults 0
        public method clean takes nothing returns nothing defaults nothing
        public method change takes integer typeId returns nothing defaults nothing
    endinterface
    
    public interface SpawnObject
        public method make takes player p, integer typeId, real x, real y, real facing returns nothing defaults nothing
        
        public static method create takes nothing
    endinterface
    
    public interface SpawnMethod
        public method setupEvents takes integer b returns nothing defaults nothing
        public method createNew takes nothing returns nothing defaults nothing
        public method cloneCustom takes integer s, integer b returns nothing defaults nothing
        public method mimicCustom takes integer s returns nothing defaults nothing
        public method spawnAction takes player p, real x, real y returns nothing defaults nothing
        public method resetCustom takes nothing returns nothing defaults nothing defaults nothing
        public method destroyCustom takes nothing returns nothing defaults nothing
    endinterface
    
    public interface BaseMethod
        public method modify takes integer s, integer addRemove returns nothing defaults nothing
        public method resetEventsCustom takes nothing returns nothing defaults nothing
        public method dieCustom takes integer b returns nothing defaults nothing
        public method mimicEventsCustom takes integer b returns nothing defaults nothing
        public method stopMimicEventsCustom takes nothing returns nothing defaults nothing
        public method mimicSpawnsCustom takes integer b returns nothing defaults nothing
        public method stopMimicSpawnsCustom takes integer b returns nothing defaults nothing
        public method mimicCustom takes integer b returns nothing defaults nothing
        public method stopMimicCustom takes integer b returns nothing defaults nothing
        public method cloneCustom takes integer b, player p, real x, real y, real facing returns nothing defaults nothing
        public method createNew takes nothing returns nothing defaults nothing
        public method destroyCustom takes nothing returns nothing defaults nothing
        public method resetCustom takes nothing returns nothing defaults nothing
        public method cloneDataCustom takes integer b returns nothing defaults nothing
        public method stopMimicHandleCustom takes nothing returns nothing defaults nothing
        public method mimicHandleCustom takes nothing returns nothing defaults nothing
        public method startMimicCustom takes integer b returns nothing defaults nothing
    endinterface
    
    public interface Base
        public Base container
        public delegate Handle base
        public delegate BaseMethod methodType
        public integer spawnIndex
        public trigger die
        public integer containerID
        public integer ownerIndex
        public integer lentIndex
        public integer borrowedIndex
        public integer borrowedSpawnTypeIndex
        public integer typeId
        public boolean mimicing
        public hashtable memory
        public hashtable memorySpawnLent
        public hashtable memorySpawnBorrowed
        
        public method engraveSpawn takes integer s returns nothing defaults nothing
        public method degraveSpawn takes integer s returns nothing defaults nothing
        public method createSpawn takes integer ft returns integer defaults 0
        public method addSpawn takes integer s returns integer defaults 0
        public method removeSpawn takes integer s returns nothing defaults nothing
        public method clearSpawns takes nothing returns nothing defaults nothing
        public method resetEvents takes nothing returns nothing defaults nothing
        
        public method disableSpawn takes integer s returns nothing defaults nothing
        public method enableSpawn takes integer s, boolean restart returns nothing defaults nothing
        public method enableSpawns takes boolean restart returns nothing defaults nothing
        public method disableSpawns takes nothing returns nothing defaults nothing
        public method clone takes player p, real x, real y, real facing returns integer defaults 0
        public method create2 takes nothing returns integer defaults 0
        public static method create takes nothing
        public method reset takes nothing returns nothing defaults nothing
        public method degraveSpawns takes nothing returns nothing defaults nothing
        public method isAttached takes nothing returns boolean defaults false
        public method new takes integer typeid, player p, integer typeId, real x, real y, real facing returns nothing defaults nothing
        public method revert takes nothing returns nothing defaults nothing
        public method original takes nothing returns nothing defaults nothing
        public method cloneData takes nothing returns integer defaults 0
        public method cloneSpawns takes integer c returns nothing defaults nothing
        
        public method mimicSpawns takes integer c returns integer defaults 0
        public method mimic takes integer b returns integer defaults 0
        public method mimicHandle takes integer b returns integer defaults 0
        public method stopMimicHandle takes nothing returns nothing defaults nothing
        public method stopMimicSpawns takes nothing returns nothing defaults nothing
        public method startMimic takes nothing returns integer defaults 0
        public method stopMimic takes nothing returns integer defaults 0
        
        public method transfer takes integer u returns nothing defaults nothing
        public method remove takes nothing returns nothing defaults nothing
        
        public method attach takes integer u returns nothing defaults nothing
        
        public method giveSpawn takes integer s, integer b returns nothing defaults nothing
        public method giveSpawns takes integer b returns nothing defaults nothing
        
        public method takeSpawn takes integer s, integer b returns nothing defaults nothing
        public method takeSpawns takes integer b returns nothing defaults nothing
        
        public method lend takes integer u returns nothing defaults nothing
        
        public method lendSpawn takes integer s, integer b returns nothing defaults nothing
        public method lendSpawns takes integer b returns nothing defaults nothing
        
        public method borrowSpawn takes integer s, integer b returns nothing defaults nothing
        public method borrowSpawns takes integer b returns nothing defaults nothing
        
        public method revertSpawns takes nothing returns nothing defaults nothing
        public method revertSpawn takes integer s returns nothing defaults nothing
        public method revertSpawnTo takes integer s, integer steps returns nothing defaults nothing
        public method revertSpawnsTo takes integer steps returns nothing defaults nothing
        public method originalSpawns takes nothing returns nothing defaults nothing
        public method originalSpawn takes integer s returns nothing defaults nothing
        
        public method swap takes integer b returns nothing defaults nothing
        public method trade takes handle u returns nothing defaults nothing
        public method tradeSpawn takes integer s, integer s2, integer b returns nothing defaults nothing
        public method tradeSpawnAll takes integer b returns nothing defaults nothing
        
        public method getBackSpawns takes nothing returns nothing defaults nothing
        public method getBackSpawn takes integer s returns nothing defaults nothing
        
        public method revertTo takes integer s returns nothing defaults nothing
        
        public method putSpawn takes integer s returns nothing defaults nothing
        public method setSpawnOwner takes integer s returns nothing defaults nothing
        public method retireSpawn takes integer s returns nothing defaults nothing
        public method unsetSpawnOwner takes integer s returns nothing defaults nothing
        public method disableSpawn2 takes integer s returns nothing defaults nothing
        public method enableSpawn2 takes integer s, boolean restart returns nothing defaults nothing
    endinterface
    
    public interface Spawn
        public Spawn container
        public timer t
        public integer base
        public real spawnTime
        public integer spawnType
        public integer spawnCount
        public integer id
        public integer objectType
        public trigger spawnEvent
        public delegate SpawnObject spawnHandle
        public delegate SpawnMethod methodType
        public integer ownerIndex
        public hashtable memory
        public boolean mimicing
        public method transfer takes integer b returns nothing defaults nothing
        public method clone takes integer b returns integer defaults 0
        public method mimic takes integer s returns integer defaults 0
        public method create2 takes nothing returns integer defaults 0
        public static method create takes nothing
        public method reset takes nothing returns nothing defaults nothing
        public method isAttached takes nothing returns boolean defaults false
        public method revert takes nothing returns nothing defaults nothing
        public method revertTo takes integer steps returns nothing defaults nothing
        public method original takes nothing returns nothing defaults nothing
        public method startMimic takes nothing returns integer defaults 0
        public method stopMimic takes nothing returns integer defaults 0
        public method mimicSpawnTime takes integer s returns integer defaults 0
        public method mimicSpawnType takes integer s returns integer defaults 0
        public method mimicSpawnCount takes integer s returns integer defaults 0
        public method mimicSpawnHandle takes integer s returns integer defaults 0
        public method mimicMethoType takes integer s returns integer defaults 0
        public method stopMimicSpawnTime takes nothing returns nothing defaults nothing
        public method stopMimicSpawnType takes nothing returns nothing defaults nothing
        public method stopMimicSpawnCount takes nothing returns nothing defaults nothing
        public method stopMimicSpawnHandle takes nothing returns nothing defaults nothing
        public method stopMimicMethodType takes nothing returns nothing defaults nothing
        
        public method disable takes nothing returns nothing defaults nothing
        public method enable takes boolean restart returns nothing defaults nothing
    endinterface
    
    public keyword SpawnPrototype
    public struct BasePrototype extends Base
        public Base container = -1
        public delegate Handle base
        public delegate BaseMethod methodType
        public integer ownerIndex = 0
        public integer spawnIndex = 0
        public integer lentIndex = 0
        public integer borrowedIndex = 0
        public integer borrowedSpawnTypeIndex = 0
        public trigger die
        public boolean mimicing = false
        public integer typeId = 0
        public hashtable memory
        public hashtable memorySpawnLent
        public hashtable memorySpawnBorrowed
        
        public method original takes nothing returns nothing
            local integer x
            if (.ownerIndex > 1) then
                set .base = LoadInteger(this.memory, Spawn_OWNERS, 0)
                call SaveInteger(memory, Mfn_UNIT, .getHandleId(), this)
                loop
                    exitwhen .ownerIndex <= 1
                    set .ownerIndex = .ownerIndex - 1
                    set x = Handle(LoadInteger(this.memory, Spawn_OWNERS, .ownerIndex)).getHandleId()
                    if HaveSavedInteger(memory, Spawn_LENT, x) then
                        call RemoveSavedInteger(memory, Spawn_LENT, x)
                    endif
                    call RemoveSavedInteger(memory, Spawn_BORROWED, x)
                    call RemoveSavedInteger(this.memory, Spawn_OWNERS, .ownerIndex)
                endloop
            elseif (.ownerIndex == 1) then
                set .base = LoadInteger(this.memory, Spawn_OWNERS, 0)
            endif
            if HaveSavedInteger(memory, Spawn_LENT, x) then
                call RemoveSavedInteger(memory, Spawn_LENT, x)
            endif
        endmethod
        
        public method revert takes nothing returns nothing
            local integer x = 0
            if (.ownerIndex > 1) then
                set .ownerIndex = .ownerIndex - 1
                call RemoveSavedInteger(memory, Spawn_BORROWED, .getHandleId())
                call RemoveSavedInteger(this.memory, Spawn_OWNERS, .ownerIndex)
                set .base = LoadInteger(this.memory, Spawn_OWNERS, .ownerIndex-1)
                set x = .getHandleId()
                call RemoveSavedInteger(memory, Spawn_LENT, x)
                call SaveInteger(memory, Mfn_UNIT, x, this)
            elseif (.ownerIndex == 1) then
                set .base = LoadInteger(this.memory, Spawn_OWNERS, 0)
            endif
            if HaveSavedInteger(memory, Spawn_LENT, x) then
                call RemoveSavedInteger(memory, Spawn_LENT, x)
            endif
        endmethod
        
        public method revertTo takes integer s returns nothing 
            local Handle u
            local integer x
            loop
                set .ownerIndex = .ownerIndex - 1
                set u = LoadInteger(this.memory, Spawn_OWNERS, .ownerIndex)
                exitwhen u == s
                call RemoveSavedInteger(memory, Spawn_BORROWED, u)
                call RemoveSavedInteger(this.memory, Spawn_OWNERS, .ownerIndex)
                call RemoveSavedInteger(memory, Spawn_LENT, u)
            endloop
            set .base = u
            set x = .getHandleId()
            call SaveInteger(memory, Mfn_UNIT, x, this)
            if HaveSavedInteger(memory, Spawn_LENT, x) then
                call RemoveSavedInteger(memory, Spawn_LENT, u)
            endif
        endmethod
        
        public method lend takes integer u returns nothing 
            call RemoveSavedInteger(memory, Mfn_UNIT, .getHandleId())
            call SaveInteger(memory, Spawn_LENT, .getHandleId(), this)
            call SaveInteger(memory, Spawn_BORROWED, Handle(u).getHandleId(), this)
            call .attach(u)
        endmethod
        
        public method new takes integer typeid, player p, integer typeId, real x, real y, real facing returns nothing 
            set .base = Handle.create(typeid)
            call .make(p, typeId, x, y, facing)
            call SaveInteger(memory, Mfn_UNIT, .getHandleId(), this)
            set .ownerIndex = .ownerIndex + 1
            call SaveInteger(this.memory, Spawn_OWNERS, .ownerIndex-1, .base)
        endmethod
        
        public method isAttached takes nothing returns boolean 
            return (.base > 0)
        endmethod
        
        public method putSpawn takes integer s returns nothing 
            local Spawn spawn = s
            local integer index
            set index = .spawnIndex
            call SaveInteger(this.memory, Spawn_SPAWN, index, s)
            set .spawnIndex = .spawnIndex + 1
            call .modify(s, 1)
            set spawn.id = index
            set spawn.base = this
        endmethod
        
        public method setSpawnOwner takes integer s returns nothing 
            local Spawn spawn = s
            local Base base = spawn.base
            local Base previousBase
            call SaveInteger(spawn.memory, Spawn_OWNERS, spawn.ownerIndex, this)
            set spawn.ownerIndex = spawn.ownerIndex + 1
            if (spawn.ownerIndex > 1) then
                set previousBase = LoadInteger(spawn.memory, Spawn_OWNERS, spawn.ownerIndex-2)
                
                if (not HaveSavedInteger(base.memory, Spawn_BORROWED_SPAWN_TYPE_R, spawn)) then
                    call SaveInteger(base.memory, Spawn_BORROWED_SPAWN_TYPE, base.borrowedSpawnTypeIndex, spawn)
                    call SaveInteger(base.memory, Spawn_BORROWED_SPAWN_TYPE_R, spawn, base.borrowedSpawnTypeIndex)
                    call SaveInteger(base.memory, Spawn_FIRST_BORROWED_SPAWN, spawn, spawn.ownerIndex-1)
                
                    set base.borrowedSpawnTypeIndex = base.borrowedSpawnTypeIndex + 1
                    debug call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 120000, "Base " + I2S(base) + " is now borrowing spawn type " + I2S(spawn) + " in " + I2S(base.borrowedSpawnTypeIndex-1))
                endif
                
                call SaveInteger(previousBase.memorySpawnLent, spawn, spawn.ownerIndex-2, previousBase.lentIndex)
                call SaveInteger(base.memorySpawnBorrowed, spawn, spawn.ownerIndex-1, base.borrowedIndex)
                
                call SaveInteger(previousBase.memory, Spawn_LENT_SPAWN, previousBase.lentIndex, spawn)
                call SaveInteger(base.memory, Spawn_BORROWED_SPAWN, base.borrowedIndex, spawn)
                debug call DisplayTextToPlayer(GetLocalPlayer(), 0, 0, "--------------------------------------------------")
                debug call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 120000, "Spawn " + I2S(spawn) + " Is now lent by " + I2S(previousBase) + " To " + I2S(base))
                debug call DisplayTextToPlayer(GetLocalPlayer(), 0, 0, " With Lent Id " + I2S(previousBase.lentIndex) + " for " + I2S(previousBase))
                debug call DisplayTextToPlayer(GetLocalPlayer(), 0, 0, " With Borrowed Id " + I2S(base.borrowedIndex) + " for " + I2S(this))
                debug call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 120000, "Spawn " + I2S(spawn) + " no longer has id " + I2S(s) + " for " + I2S(previousBase))
                debug call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 120000, "Spawn " + I2S(spawn) + " has id " + I2S(spawn.id) + " for " + I2S(base))
                
                if (HaveSavedInteger(previousBase.memory, Spawn_STEPS, spawn) == false) then
                    call SaveInteger(previousBase.memory, Spawn_STEPS, spawn, spawn.ownerIndex-2)
                endif

                set previousBase.lentIndex = previousBase.lentIndex + 1
                set base.borrowedIndex = base.borrowedIndex + 1
            endif
        endmethod
        
        public method engraveSpawn takes integer s returns nothing 
            call .putSpawn(s)
            call .setSpawnOwner(s)
        endmethod
        
        public method retireSpawn takes integer s returns nothing 
            local Spawn spawn = s
            set .spawnIndex = .spawnIndex - 1
            set spawn = LoadInteger(this.memory, Spawn_SPAWN, .spawnIndex)
            set spawn.id = Spawn(s).id
            call SaveInteger(this.memory, Spawn_SPAWN, spawn.id, spawn)
            set spawn = s
            call .modify(spawn, -1)
            set spawn.id = -1
            set spawn.base = -1
        endmethod
        
        public method unsetSpawnOwner takes integer s returns nothing 
            local Spawn spawn = s
            local Base owner
            local integer index
            local integer spawnIndexing
            local boolean doRevert = false
            debug call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 120000, "-----------------------------------------------------")
            if (spawn.ownerIndex == 1 and HaveSavedInteger(this.memory, Spawn_STEPS, spawn)) then
                call RemoveSavedInteger(this.memory, Spawn_STEPS, spawn)
            elseif (spawn.ownerIndex > 1) then
                set doRevert = true
                debug call DisplayTextToPlayer(GetLocalPlayer(), 0, 0, "----------------REVERTING SPAWN----------------")
                if (LoadInteger(this.memory, Spawn_FIRST_BORROWED_SPAWN, spawn) == spawn.ownerIndex-1) then
                    set .borrowedSpawnTypeIndex = .borrowedSpawnTypeIndex - 1
                    set index = LoadInteger(this.memory, Spawn_BORROWED_SPAWN_TYPE_R, spawn)
                    if index < .borrowedSpawnTypeIndex then
                        set spawnIndexing = LoadInteger(this.memory, Spawn_BORROWED_SPAWN_TYPE, .borrowedSpawnTypeIndex)
                        call SaveInteger(this.memory, Spawn_BORROWED_SPAWN_TYPE, index, spawnIndexing)
                        call SaveInteger(this.memory, Spawn_BORROWED_SPAWN_TYPE_R, spawnIndexing, index)
                        call RemoveSavedInteger(this.memory, Spawn_STEPS, spawn)
                        debug call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 120000, "Base " + I2S(this) + " got rid of steps for " + I2S(spawn))
                        debug call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 120000, "Base " + I2S(this) + " is no longer borrowing spawn type " + I2S(spawn))
                        debug call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 120000, "Spawn type " +I2S(spawn) + " Was in spawn type borrow slot " + I2S(index))
                        debug call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 120000, "Spawn type " + I2S(spawnIndexing) + " Is now moved from " + I2S(.borrowedSpawnTypeIndex) + " To " + I2S(index))
                    endif
                endif
            endif
            set spawn.ownerIndex = spawn.ownerIndex - 1
            if (doRevert) then
                set owner = LoadInteger(spawn.memory, Spawn_OWNERS, spawn.ownerIndex-1)
                
                debug call DisplayTextToPlayer(GetLocalPlayer(), 0, 0, "||||SPAWN " + I2S(spawn) + " BEING REVERTED FROM " + I2S(this) + " TO " + I2S(owner) + "||||")
                
                set .borrowedIndex = .borrowedIndex - 1
                set index = LoadInteger(this.memorySpawnBorrowed, spawn, spawn.ownerIndex)
                
                if index < .borrowedIndex then
                    set spawnIndexing = LoadInteger(this.memory, Spawn_BORROWED_SPAWN, .borrowedIndex)
                    call SaveInteger(this.memory, Spawn_BORROWED_SPAWN, index, spawnIndexing)
                    
                    debug call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 120000, "-----------------------------------------------------")
                    debug call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 120000, "Real spawn " + I2S(spawn) + " Is no longer being borrowed by " + I2S(this))
                    debug call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 120000, "Real spawn " +I2S(spawn) + " Was in borrow slot " + I2S(index))
                    debug call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 120000, "Spawn " + I2S(spawnIndexing) + " Is now moved from " + I2S(.borrowedIndex) + " To " + I2S(index))
                endif
                
                set owner.lentIndex = owner.lentIndex - 1
                set index = LoadInteger(owner.memorySpawnLent, spawn, spawn.ownerIndex-1)
                
                if index < owner.lentIndex then
                    set spawnIndexing = LoadInteger(owner.memory, Spawn_LENT_SPAWN, owner.lentIndex)
                    call SaveInteger(owner.memory, Spawn_LENT_SPAWN, index, spawnIndexing)
                    
                    debug call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 120000, "-----------------------------------------------------")
                    debug call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 120000, "Real spawn " + I2S(spawn) + " Is no longer being lent by " + I2S(owner))
                    debug call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 120000, "Real spawn " +I2S(spawn) + " Was in lent slot " + I2S(index))
                    debug call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 120000, "Spawn " + I2S(spawnIndexing) + " Is now moved from " + I2S(.lentIndex) + " To " + I2S(index))
                endif
            endif
        endmethod
        
        public method degraveSpawn takes integer s returns nothing 
            local Spawn spawn = LoadInteger(this.memory, Spawn_SPAWN, s)
            call spawn.disable()
            call .retireSpawn(spawn)
            call .unsetSpawnOwner(spawn)
        endmethod
        
        public method addSpawn takes integer s returns integer 
            local Spawn s2 = s
            set s2 = s2.clone(this)
            return s2
        endmethod
        
        public method removeSpawn takes integer s returns nothing 
            local Spawn s2 = LoadInteger(this.memory, Spawn_SPAWN, s)
            call .degraveSpawn(s)
            call s2.destroy()
        endmethod
        
        public method clearSpawns takes nothing returns nothing 
            loop
                exitwhen .spawnIndex == 0
                call .removeSpawn(.spawnIndex-1)
            endloop
        endmethod
        
        public method degraveSpawns takes nothing returns nothing 
            loop
                exitwhen .spawnIndex == 0
                call .degraveSpawn(.spawnIndex-1)
            endloop
        endmethod
        
        public method takeSpawn takes integer s, integer b returns nothing 
            call Base(b).giveSpawn(s, this)
        endmethod
        
        public method takeSpawns takes integer b returns nothing 
            call Base(b).giveSpawns(this)
        endmethod
        
        public method lendSpawn takes integer s, integer b returns nothing 
            local Spawn spawn = LoadInteger(this.memory, Spawn_SPAWN, s)
            call .retireSpawn(spawn)
            call Base(b).putSpawn(spawn)
            call Base(b).setSpawnOwner(spawn)
        endmethod
        
        public method lendSpawns takes integer b returns nothing 
            local integer x = .spawnIndex
            loop
                exitwhen x == 0
                call .lendSpawn(x-1, b)
                set x = x - 1
            endloop
        endmethod
        
        public method revertSpawns takes nothing returns nothing
            local integer x = .borrowedIndex - .spawnIndex
            loop
                exitwhen .borrowedIndex == x or .borrowedIndex == 0
                call .revertSpawn(Spawn(LoadInteger(this.memory, Spawn_BORROWED_SPAWN, .borrowedIndex-1)).id)
            endloop
        endmethod
        
        public method revertSpawn takes integer s returns nothing 
            local Spawn spawn = LoadInteger(this.memory, Spawn_SPAWN, s)
            local integer index
            local integer spawnIndexing
            local Base owner
            if (spawn.ownerIndex > 1) then
                call .retireSpawn(spawn)
                call .unsetSpawnOwner(spawn)
                set owner = LoadInteger(spawn.memory, Spawn_OWNERS, spawn.ownerIndex-1)
                call owner.putSpawn(spawn)
            endif
        endmethod
        
        public method originalSpawns takes nothing returns nothing 
            loop
                exitwhen .borrowedIndex == 0
                call .originalSpawn(Spawn(LoadInteger(this.memory, Spawn_BORROWED_SPAWN, .borrowedIndex)).id)
            endloop
        endmethod
        
        public method originalSpawn takes integer s returns nothing 
            local Spawn spawn = LoadInteger(this.memory, Spawn_SPAWN, s)
            local Base owner
            loop
                exitwhen spawn.ownerIndex == 1
                set owner = LoadInteger(spawn.memory, Spawn_OWNERS, spawn.ownerIndex-1)
                call owner.revertSpawn(spawn.id)
            endloop
        endmethod
        
        public method borrowSpawn takes integer s, integer b returns nothing 
            call Base(b).lendSpawn(s, this)
        endmethod
        
        public method revertSpawnTo takes integer s, integer steps returns nothing 
            local Spawn spawn = LoadInteger(this.memory, Spawn_SPAWN, s)
            local integer currentStep = spawn.ownerIndex
            local Base owner = LoadInteger(spawn.memory, Spawn_OWNERS, spawn.ownerIndex-1)
            local integer x
            set spawn = LoadInteger(owner.memory, Spawn_SPAWN, s)
            set x = spawn.ownerIndex
            loop
                exitwhen spawn.ownerIndex == currentStep-steps or spawn.ownerIndex == 1
                set owner = LoadInteger(spawn.memory, Spawn_OWNERS, spawn.ownerIndex-1)
                call owner.revertSpawn(spawn.id)
                if x == spawn.ownerIndex then
                    return
                endif
            endloop
        endmethod
        
        public method revertSpawnsTo takes integer steps returns nothing 
            local integer x = .borrowedSpawnTypeIndex
            loop
                exitwhen x == 0
                call .revertSpawnTo(Spawn(LoadInteger(this.memory, Spawn_BORROWED_SPAWN_TYPE, x-1)).id, steps)
                set x = x - 1
            endloop
        endmethod
        
        public method getBackSpawns takes nothing returns nothing 
            local integer x = .lentIndex
            loop
                exitwhen .lentIndex == 0
                call .getBackSpawn(LoadInteger(this.memory, Spawn_LENT_SPAWN, .lentIndex-1))
                if x == .lentIndex then
                    return
                else
                    set x = .lentIndex
                endif
            endloop
        endmethod
        
        public method getBackSpawn takes integer s returns nothing 
            local Spawn spawn = s
            call Base(Spawn(s).base).revertSpawnTo(Spawn(s).id, spawn.ownerIndex - (LoadInteger(this.memory, Spawn_STEPS, spawn)+1))
        endmethod
        
        public method borrowSpawns takes integer b returns nothing 
            call Base(b).lendSpawns(this)
        endmethod
        
        public method tradeSpawn takes integer s, integer s2, integer b returns nothing
            local Base base = b
            local Spawn spawn = LoadInteger(this.memory, Spawn_SPAWN, s)
            local Spawn spawn2 = LoadInteger(base.memory, Spawn_SPAWN, s2)
            call .retireSpawn(spawn)
            call base.retireSpawn(spawn2)
            call .unsetSpawnOwner(spawn)
            call base.unsetSpawnOwner(spawn2)
            call .putSpawn(spawn2)
            call base.putSpawn(spawn)
            call .setSpawnOwner(spawn2)
            call base.setSpawnOwner(spawn)
        endmethod
        
        public method tradeSpawnAll takes integer b returns nothing
            local integer array spawn1
            local integer array spawn2
            local integer spawn1Index = -1
            local integer spawn2Index = -1
            local integer x = 0
            local Spawn spawn
            local Base base = b
            loop
                exitwhen .spawnIndex == 0
                set spawn1Index = spawn1Index + 1
                set spawn1[spawn1Index] = LoadInteger(this.memory, Spawn_SPAWN, .spawnIndex-1)
                call .retireSpawn(spawn1[spawn1Index])
                call .unsetSpawnOwner(spawn1[spawn1Index])
            endloop
            loop
                exitwhen base.spawnIndex == 0
                set spawn2Index = spawn2Index + 1
                set spawn2[spawn2Index] = LoadInteger(base.memory, Spawn_SPAWN, base.spawnIndex-1)
                call base.retireSpawn(spawn2[spawn2Index])
                call base.unsetSpawnOwner(spawn2[spawn2Index])
            endloop
            loop
                call base.putSpawn(spawn1[x])
                call base.setSpawnOwner(spawn1[x])
                set x = x + 1
                exitwhen x > spawn1Index
            endloop
            set x = 0
            loop
                call .putSpawn(spawn2[x])
                call .setSpawnOwner(spawn2[x])
                set x = x + 1
                exitwhen x > spawn2Index
            endloop
        endmethod
        
        public method mimic takes integer b returns integer
            local Base base = b
            if not .mimicing then
                set this = .startMimic()
            endif
            set .methodType = base.methodType
            call Handle(.base).change(Handle(Base(b).base).getTypeId())
            call .mimicSpawns(b)
            call .resetEvents()
            call .mimicEventsCustom(b)
            call .mimicCustom(b)
            return this
        endmethod

        public method startMimic takes nothing returns integer
            local thistype b = thistype.create()
            set b.methodType = .methodType
            call .cloneSpawns(b)
            call .cloneDataCustom(b)
            set b.base = .base
            set b.container = this
            set b.mimicing = true
            set .typeId = Handle(.base).getTypeId()
            call .disableSpawns()
            call b.enableSpawns(true)
            call .startMimicCustom(b)
            return b
        endmethod
        
        public method stopMimic takes nothing returns integer
            local Base b = this
            if b.mimicing == true then
                set this = b.container
                set b.container = -1
                if Handle(b.base).getType() != .typeId then
                    call Handle(.base).change(.typeId)
                endif
                call .stopMimicCustom(b)
                call b.destroy()
                call .enableSpawns(true)
            endif
            return this
        endmethod
        
        public method stopMimicHandle takes nothing returns nothing
            call Handle(.base).change(Handle(Base(.container).base).getTypeId())
            call .stopMimicHandleCustom()
        endmethod
        
        public method mimicHandle takes integer b returns integer
            if not .mimicing then
                set this = .startMimic()
            endif
            call Handle(.base).change(Handle(Base(b).base).getTypeId())
            call .mimicHandleCustom()
            return this
        endmethod
        
        public method mimicSpawns takes integer c returns integer
            local integer x = 0
            local Base b = c
            if not .mimicing then
                set this = .startMimic()
            endif
            call .clearSpawns()
            loop
                exitwhen x >= b.spawnIndex
                call .addSpawn(LoadInteger(b.memory, Spawn_SPAWN, x))
                set x = x + 1
            endloop
            call .mimicSpawnsCustom(b)
            call .enableSpawns(true)
            return this
        endmethod
        
        public method stopMimicSpawns takes nothing returns nothing
            call .mimicSpawns(.container)
            call .stopMimicSpawnsCustom(.container)
        endmethod
        
        public method resetEvents takes nothing returns nothing 
            call TriggerClearActions(.die)
            call TriggerAddAction(.die, function thistype.dieA)
            call .resetEventsCustom()
        endmethod
        
        public static method dieA takes nothing returns nothing 
            local thistype b = LoadInteger(memory, Mfn_TRIGGER, GetHandleId(GetTriggeringTrigger()))
            call b.dieCustom.execute(b)
        endmethod
        
        public method giveSpawn takes integer s, integer b returns nothing 
            local Spawn spawn = LoadInteger(this.memory, Spawn_SPAWN, s)
            call .retireSpawn(spawn)
            call .unsetSpawnOwner(spawn)
            call Base(b).engraveSpawn(spawn)
        endmethod
        
        public method giveSpawns takes integer b returns nothing
            local integer x = .spawnIndex
            loop
                exitwhen x == 0
                call .giveSpawn(x-1, b)
                set x = x - 1
            endloop
        endmethod
        
        public method disableSpawn takes integer s returns nothing 
            local Spawn spawn = LoadInteger(this.memory, Spawn_SPAWN, s)
            call DisableTrigger(spawn.spawnEvent)
            if (spawn.spawnTime > 0) then
                call PauseTimer(spawn.t)
            endif
        endmethod
        
        public method enableSpawn takes integer s, boolean restart returns nothing 
            local Spawn spawn = LoadInteger(this.memory, Spawn_SPAWN, s)
            call EnableTrigger(spawn.spawnEvent)
            if (spawn.spawnTime > 0) then
                if (restart) then
                    call TimerStart(spawn.t, spawn.spawnTime, false, null)
                else
                    call ResumeTimer(spawn.t)
                endif
            endif
        endmethod
        
        public method enableSpawns takes boolean restart returns nothing 
            local integer x = 0
            local Spawn s
            loop
                exitwhen x >= .spawnIndex
                set s = LoadInteger(this.memory, Spawn_SPAWN, x)
                call EnableTrigger(s.spawnEvent)
                if (s.spawnTime > 0) then
                    if (restart) then
                        call TimerStart(s.t, s.spawnTime, false, null)
                    else
                        call ResumeTimer(s.t)
                    endif
                endif
                set x = x + 1
            endloop
        endmethod
        
        public method disableSpawns takes nothing returns nothing 
            local integer x = 0
            local Spawn s
            loop
                exitwhen x >= .spawnIndex
                set s = LoadInteger(this.memory, Spawn_SPAWN, x)
                call DisableTrigger(s.spawnEvent)
                if (s.spawnTime > 0) then
                    call PauseTimer(s.t)
                endif
                set x = x + 1
            endloop
        endmethod
        
        public method cloneSpawns takes integer c returns nothing 
            local integer x = 0
            local integer y = .spawnIndex
            local Base b = c
            loop
                exitwhen x >= y
                call b.addSpawn(LoadInteger(this.memory, Spawn_SPAWN, x))
                set x = x + 1
            endloop
        endmethod
        
        public method cloneData takes nothing returns integer 
            local thistype b = thistype.create()
            call b.attach(Handle.create(Handle(.base).getType()))
            set b.methodType = .methodType
            call .cloneSpawns(b)
            call .cloneDataCustom(b)
            return b
        endmethod
        
        public method clone takes player p, real x, real y, real facing returns integer 
            local thistype b = .cloneData()
            call b.make(p, .getTypeId(), x, y, facing)
            call .cloneCustom(b, p, x, y, facing)
            return b
        endmethod
        
        public method attach takes integer u returns nothing 
            set .base = u
            call SaveInteger(memory, Mfn_UNIT, .getHandleId(), this)
            set .ownerIndex = .ownerIndex + 1
            call SaveInteger(this.memory, Spawn_OWNERS, .ownerIndex-1, u)
        endmethod
        
        public method remove takes nothing returns nothing 
            call .disableSpawns()
            call RemoveSavedInteger(memory, Mfn_UNIT, .getHandleId())
            set .base = -1
            set .ownerIndex = .ownerIndex - 1
            call RemoveSavedInteger(this.memory, Spawn_OWNERS, .ownerIndex)
        endmethod
        
        public method transfer takes integer u returns nothing 
            call RemoveSavedInteger(memory, Mfn_UNIT, .getHandleId())
            set .ownerIndex = .ownerIndex - 1
            call .attach(u)
        endmethod
        
        public method swap takes integer b returns nothing 
            local Base b2 = b
            local Handle u1 = .base
            local Handle u2 = b2.base
            set .ownerIndex = .ownerIndex - 1
            set b2.ownerIndex = b2.ownerIndex - 1
            call .attach(u2)
            call b2.attach(u1)
        endmethod
        
        public method trade takes handle u returns nothing 
            local Base targetBase = getBase(u)
            local Handle base = .base
            local Handle base2 = targetBase.base
            set .ownerIndex = .ownerIndex - 1
            set targetBase.ownerIndex = targetBase.ownerIndex - 1
            call targetBase.attach(base)
            call .attach(base2)
        endmethod
        
        public method create2 takes nothing returns integer 
            return thistype.create()
        endmethod
        
        public static method create3 takes integer baseMethod returns thistype
            local thistype b = thistype.create()
            set b.methodType = baseMethod
            call b.createNew()
            return b
        endmethod
        
        public static method create takes nothing returns thistype 
            local thistype b = thistype.allocate()
            set b.memory = InitHashtable()
            set b.memorySpawnLent = InitHashtable()
            set b.memorySpawnBorrowed = InitHashtable()
            set b.die = CreateTrigger()
            call SaveInteger(memory, Mfn_TRIGGER, GetHandleId(b.die), b)
            call TriggerAddAction(b.die, function thistype.dieA)
            call b.createNew()
            return b
        endmethod
        
        public method onDestroy takes nothing returns nothing 
            local integer x = 0
            call .clearSpawns()
            if .container != -1 then
                call .container.destroy()
            endif
            call .destroyCustom()
            call TriggerClearActions(.die)
            if (.base > 0) then
                call RemoveSavedInteger(memory, Mfn_UNIT, .getHandleId())
            endif
            call FlushParentHashtable(this.memory)
            call FlushParentHashtable(this.memorySpawnLent)
            call FlushParentHashtable(this.memorySpawnBorrowed)
            set .die = null
        endmethod
    endstruct
    
    public struct SpawnPrototype extends Spawn
        public Spawn container = -1
        public timer t
        public integer base = -1
        public real spawnTime
        public integer spawnType
        public integer spawnCount
        public integer id
        public integer ownerIndex = 0
        public trigger spawnEvent
        public boolean mimicing = false
        public delegate SpawnObject spawnHandle
        public delegate SpawnMethod methodType
        public hashtable memory
        
        public method isAttached takes nothing returns boolean 
            return (.base > 0)
        endmethod
        
        public method transfer takes integer b returns nothing 
            call Base(.base).degraveSpawn(this)
            call Base(b).engraveSpawn(this)
        endmethod
        
        public method clone takes integer b returns integer 
            local thistype s = thistype.create()
            local Base b2 = b
            set s.spawnTime = .spawnTime
            set s.spawnType = .spawnType
            set s.spawnCount = .spawnCount
            set s.spawnHandle = .spawnHandle
            set s.methodType = .methodType
            call b2.engraveSpawn(s)
            call s.cloneCustom(this, b)
            return s
        endmethod
        
        public method startMimic takes nothing returns integer
            local thistype s = .clone(.base)
            set s.mimicing = true
            set s.container = this
            call .mimicCustom(s)
            call .disable()
            call s.enable(true)
            return s
        endmethod
        
        public method stopMimic takes nothing returns integer
            local Spawn s = this
            if s.mimicing == true then
                set this = s.container
                set s.container = -1
                call s.destroy()
                call .enable(true)
            endif
            return this
        endmethod
        
        public method mimic takes integer s returns integer
            if .mimicing == false then
                set this = .startMimic()
            endif
            set .spawnTime = Spawn(s).spawnTime
            set .spawnType = Spawn(s).spawnType
            set .spawnCount = Spawn(s).spawnCount
            set .spawnHandle = Spawn(s).spawnHandle
            set .methodType = Spawn(s).methodType
            call Spawn(s).mimicCustom(this)
            return this
        endmethod
        
        public method mimicSpawnTime takes integer s returns integer
            if .mimicing == false then
                set this = .startMimic()
            endif
            set .spawnTime = Spawn(s).spawnTime
            return this
        endmethod
        
        public method mimicSpawnType takes integer s returns integer
            if .mimicing == false then
                set this = .startMimic()
            endif
            set .spawnType = Spawn(s).spawnType
            return this
        endmethod
        
        public method mimicSpawnCount takes integer s returns integer
            if .mimicing == false then
                set this = .startMimic()
            endif
            set .spawnCount = Spawn(s).spawnCount
            return this
        endmethod
        
        public method mimicSpawnHandle takes integer s returns integer
            if .mimicing == false then
                set this = .startMimic()
            endif
            set .spawnHandle = Spawn(s).spawnHandle
            return this
        endmethod
        
        public method mimicMethodType takes integer s returns integer
            if .mimicing == false then
                set this = .startMimic()
            endif
            set .methodType = Spawn(s).methodType
            return this
        endmethod
        
        public method stopMimicSpawnTime takes nothing returns nothing
            set .spawnTime = Spawn(.container).spawnTime
        endmethod
        
        public method stopMimicSpawnType takes nothing returns nothing
            set .spawnType = Spawn(.container).spawnType
        endmethod
        
        public method stopMimicSpawnCount takes nothing returns nothing
            set .spawnCount = Spawn(.container).spawnCount
        endmethod
        
        public method stopMimicSpawnHandle takes nothing returns nothing
            set .spawnHandle = Spawn(.container).spawnHandle
        endmethod
        
        public method stopMimicMethodType takes nothing returns nothing
            set .methodType = Spawn(.container).methodType
        endmethod
        
        public method revertTo takes integer steps returns nothing 
            call Base(.base).revertSpawnTo(this.id, steps)
        endmethod
        
        public method revert takes nothing returns nothing 
            call Base(.base).revertSpawn(this.id)
        endmethod
        
        public method original takes nothing returns nothing 
            call Base(.base).originalSpawn(this.id)
        endmethod
        
        public method enable takes boolean restart returns nothing 
            call EnableTrigger(.spawnEvent)
            if (.spawnTime > 0) then
                if (restart) then
                    call TimerStart(.t, .spawnTime, false, null)
                else
                    call ResumeTimer(.t)
                endif
            endif
        endmethod
        
        public method disable takes nothing returns nothing 
            call DisableTrigger(.spawnEvent)
            if (.spawnTime > 0) then
                call PauseTimer(.t)
            endif
        endmethod
        
        public static method spawnAction2 takes nothing returns nothing 
            local thistype s = LoadInteger(memory, Mfn_TRIGGER, GetHandleId(GetTriggeringTrigger()))
            local Base b = s.base
            local integer x = 0
            local real tempCoord
            local real xBase = b.getX()
            local real yBase = b.getY()
            local player p = b.getPlayer()
            if (HaveSavedReal(b.memory, Mfn_X, s.id)) then
                set xBase = LoadReal(b.memory, Mfn_X, s.id)
            endif
            if (HaveSavedReal(b.memory, Mfn_Y, s.id)) then
                set yBase = LoadReal(b.memory, Mfn_Y, s.id)
            endif
            loop
                call s.make.execute(p, s.spawnType, xBase, yBase, 0)
                call s.spawnAction.execute(p, xBase, yBase)
                set x = x + 1
                exitwhen x >= s.spawnCount
            endloop
            if (s.spawnTime > 0) then
                call TimerStart(s.t, s.spawnTime, false, null)
            endif
        endmethod
        
        public method create2 takes nothing returns integer 
            return thistype.create()
        endmethod
        
        public static method create3 takes integer spawnMethod returns thistype
            local thistype s = thistype.create()
            set s.methodType = spawnMethod
            call s.createNew()
            return s
        endmethod
        
        public static method create takes nothing returns thistype 
            local thistype s = thistype.allocate()
            set s.memory = InitHashtable()
            set s.spawnEvent = CreateTrigger()
            call SaveInteger(memory, Mfn_TRIGGER, GetHandleId(s.spawnEvent), s)
            set s.t = CreateTimer()
            call TriggerRegisterTimerExpireEvent(s.spawnEvent, s.t)
            call TriggerAddAction(s.spawnEvent, function thistype.spawnAction2)
            return s
        endmethod
        
        public method onDestroy takes nothing returns nothing 
            local integer x = 0
            if .container != -1 then
                call .container.destroy()
            endif
            call TriggerClearActions(.spawnEvent)
            set .spawnEvent = null
            if (.spawnTime > 0) then
                call PauseTimer(.t)
            endif
            call DestroyTimer(.t)
            set .t = null
            call RemoveSavedInteger(memory, Mfn_TRIGGER, GetHandleId(.spawnEvent))
            if (.base > 0) then
                call Base(.base).removeSpawn(.id)
            endif
            call .destroyCustom()
            call FlushParentHashtable(this.memory)
        endmethod
    endstruct
    
    private function ini takes nothing returns nothing
        call Mfn_createCredit1(SYSTEM, VERSION, AUTHOR, HELPERS, TEXTURE_PATH, "The ultimate in spawning.")
        
        set memory = InitHashtable()
    endfunction
endlibrary

library RequiresSpawn requires Spawn
endlibrary
 
Last edited:
Level 31
Joined
Jul 10, 2007
Messages
6,306
In my opinion this is way to specific to be a system.
Maybe it could be a system in your own map, but... Spawns are simple things and this can only be used in systems like footies.

w/e, it's the most powerful spawning system at the moment and the only all purpose spawning system. I don't think you actually looked at it because everyone who has so far has said differently ^_^

Also the statement you made-
this can only be used in systems like footies.
: P - this can only be used in *maps* like footies.

That is completely wrong. This is the reason why I think you didn't look at it : ).
 
Last edited:
Level 11
Joined
Nov 4, 2007
Messages
337
Be careful calling this the most powerful spawn system in existance.
Really: spawns are a simple thing. Why would amybody need a system for them?
Also give a list of methods/functions including
description and the main code in the first post.
Also please explain things like floor and structure.
 
Level 31
Joined
Jul 10, 2007
Messages
6,306
Also give a list of methods/functions including
description and the main code in the first post.

Second post ^^

Also, I'm writing documentation for it.

Be careful calling this the most powerful spawn system in existance.
Really: spawns are a simple thing. Why would amybody need a system for them?

It's the only all purpose spawn system around making it the most powerful =).

Also please explain things like floor and structure.

I can't do a better description than what I had done because it's for a future version and I'm not even sure of what they'll fully entail yet. All I can say is that the names are exactly what you'd think they are : D.


Oh, and to answer further questions about what is all purpose spawning supposed to mean and why might it be the most powerful, refer to News 8 ^_^.
 
Last edited:
Top