But what if we went back to the old days before there were RandomSpawners to find a more customizable method? Well, that's exactly what i will do today.
Since it is a method from those days, i also took the chance to do a ZDoom Classic (2.1.4) compatible version.
Spoiler: Simple method (RECOMMENDED)
This method works too with GZDoom 1.8.6 and Zandronum, and is the recommended way to do it as long as you don't need toggleable spawns or spawning 2 items at a time
First we define an actor and make it inherit from RandomSpawnerTo add more items to drop, just add another dropitem line with your specified item. In this case, 255 is the chance of spawning out of 255, so it will always spawn in this case. And 2 or 1 is the chance to be picked out of the list, the higher the more likely the actor will appear instead of some other.Code: Select all
Actor SpawnSomething : RandomSpawner { dropitem "Item1", 255, 2 dropitem "Item2", 255, 1 }
Spoiler: GZDoom 1.8.6 to current versionThis GZDoom 1.8.6 method works with all modern versions too, i tried to make the spoiler title self-explanatory, but apparently it isn't obvious enough.
THIS IS A HACKY TACKY METHOD AND YOU SHOULD ONLY USE IT WHEN STRICTLY NEEDED AND WHEN AIMING FOR ZANDRONUM COMPATIBILITY/A VERSION WITHOUT ZSCRIPT
YOU HAVE BEEN WARNED
This version has a major advancement over the ZDoom Classic method: Toggleable spawns! I will probably detail these later.
What are we waiting for?, let's get right into it!
First we define the actor (the following example is for weapons and pickups):Here is the example code for any other type of actor spawnedCode: Select all
Actor CustomSpawner : Inventory //This gives us access to the following two properties and also makes it respawn after a period of time { +INVENTORY.ALWAYSPICKUP //So that it can be picked up indefinitely Inventory.PickupMessage "" //This is so we don't know we picked up an actor besides our weapon/item States { Spawn: TNT1 A 0 TNT1 A 0 A_Jump(128,2) //50-50 chance to spawn the next item TNT1 A 1 A_SpawnItemEx("Item1", 0, 0, 0, 0, 0, 0, 0,SXF_TRANSFERSPECIAL|SXF_TRANSFERPOINTERS, 0, tid) //Spawn item inbetween quotes Goto Death TNT1 A 0 A_Jump(128,2) //50-50 chance to spawn next item again TNT1 A 1 A_SpawnItemEx("Item2", 0, 0, 0, 0, 0, 0, 0,SXF_TRANSFERSPECIAL|SXF_TRANSFERPOINTERS, 0, tid) //Spawn item again Goto Death TNT1 A 0 A_Jump(128,2) TNT1 A 1 A_SpawnItemEx("Item3", 0, 0, 0, 0, 0, 0, 0,SXF_TRANSFERSPECIAL|SXF_TRANSFERPOINTERS, 0, tid) Goto Death TNT1 A 1 A_SpawnItemEx("Item4", 0, 0, 0, 0, 0, 0, 0,SXF_TRANSFERSPECIAL|SXF_TRANSFERPOINTERS, 0, tid) Goto Death Death: TNT1 A -1 //Wait to be picked up Stop } }
That's a pretty simple actor, right? But just in case i will break it down so everyone can understand what's going on:Code: Select all
Actor CustomSpawnerMonsters //Don't inherit from anything { //No property has to be defined States { Spawn: TNT1 A 0 TNT1 A 0 A_Jump(128,2) //50-50 chance to spawn the next item TNT1 A 1 A_SpawnItemEx("Item1", 0, 0, 0, 0, 0, 0, 0,SXF_TRANSFERSPECIAL|SXF_TRANSFERPOINTERS, 0, tid) //Spawn item inbetween quotes Goto Death TNT1 A 0 A_Jump(128,2) //50-50 chance to spawn next item again TNT1 A 1 A_SpawnItemEx("Item2", 0, 0, 0, 0, 0, 0, 0,SXF_TRANSFERSPECIAL|SXF_TRANSFERPOINTERS, 0, tid) //Spawn item again Goto Death TNT1 A 0 A_Jump(128,2) TNT1 A 1 A_SpawnItemEx("Item3", 0, 0, 0, 0, 0, 0, 0,SXF_TRANSFERSPECIAL|SXF_TRANSFERPOINTERS, 0, tid) Goto Death TNT1 A 1 A_SpawnItemEx("Item4", 0, 0, 0, 0, 0, 0, 0,SXF_TRANSFERSPECIAL|SXF_TRANSFERPOINTERS, 0, tid) Goto Death Death: TNT1 A 0 //Remove this spawner Stop } }
The comments should tell you most of what this does, but for a more accurate description of the A_Jump line; Basically it checks the chance (in this case, 128 out of 255) and then jumps a certain amount of states/lines of code. In this example, 2 lines, the A_SpawnItemEx and Goto Death lines, the last of which would skip to a state where it either waits to be picked up, or dissapears if it's a monster spawner.Code: Select all
TNT1 A 0 A_Jump(128,2) //50-50 chance to spawn the next item TNT1 A 1 A_SpawnItemEx("Item1", 0, 0, 0, 0, 0, 0, 0,SXF_TRANSFERSPECIAL|SXF_TRANSFERPOINTERS, 0, tid) //Spawn item inbetween quotes Goto Death
So if we were to make two different items spawn, we would do:Note how A_Jump has been adjusted to take the extra state into account.Code: Select all
TNT1 A 0 A_Jump(128,3) TNT1 A 1 A_SpawnItemEx("Item1", 0, 0, 0, 0, 0, 0, 0,SXF_TRANSFERSPECIAL|SXF_TRANSFERPOINTERS, 0, tid) TNT1 A 1 A_SpawnItemEx("Item1", 0, 0, 0, 0, 0, 0, 0,SXF_TRANSFERSPECIAL|SXF_TRANSFERPOINTERS, 0, tid) Goto Death
It's also useful to know that A_SpawnItemEx has many parameters, making it possible to move our spawned item(s) a slight distance from where they would normally be.
Here's a full list of parameters
The last random spawn definition must NOT have the A_Jump line!
The reason for A_SpawnItemEx being so long compared to the ZDoom Classic version is because it needs to transfer the Thing ID, Thing Specials and Pointers, for max compatibility with all maps.
Problems
-Weapon stay isn't possible with this method, instead they always respawn (but hey, it's better than no DM right?)
-Monster respawning doesn't work (not like anyone plays nightmare difficulty for the respawning though)
Spoiler: ZDoom 2.1.4 (OLD) version
SAME AS ABOVE, BUT THIS IS EVEN HACKIER AND SHOULD BE USED ONLY WHEN AIMING FOR ZDOOM 2.1.4 COMPATIBILITY (If you want, because there isn't any source port that is this outdated)
This version comes with more problems than the GZDoom 1.8.6 version, if you plan on making your mod compatible with 2.1.4, i recommend releasing two separate versions of the mod, one for GZDoom 1.8.6 and other for ZDoom 2.1.4.
You might wonder, why bother to make a 2.1.4 compatible mod? Well, 1) It can be fun to restrict yourself and see what can you come up with on such a limited version, and 2) It runs on more computers, for instance, a 486 40MHz is able to run ZDoom Classic at 320x200 in low detail mode. Along with more computers, support for the Wii and Wii U consoles is likely coming in the near future
With all that said, let's get right into it:
First we define the actor (the following example is for weapons and pickups):Here is the example code for any other type of actor spawnedCode: Select all
Actor CustomSpawner : Inventory //This gives us access to the following two properties and also makes it respawn after a period of time { Inventory.Maxamount 9999 //So that it can be picked up 9999 times (only the best Doomers will reach this in a real Deathmatch!) Inventory.PickupMessage "" //This is so we don't know we picked up an actor besides our weapon/item States { Spawn: TNT1 A 0 TNT1 A 0 A_Jump(128,2) //50-50 chance to spawn the next item TNT1 A 1 A_SpawnItem("Item1") //Spawn item inbetween quotes Goto Death TNT1 A 0 A_Jump(128,2) //50-50 chance to spawn next item again TNT1 A 1 A_SpawnItem("Item2") //Spawn item again Goto Death TNT1 A 0 A_Jump(128,2) TNT1 A 1 A_SpawnItem("Item3") Goto Death TNT1 A 1 A_SpawnItem("Item4") //No Jump state because this is the last spawn definition Goto Death Death: TNT1 A -1 //Wait to be picked up Stop } }
That's a pretty simple actor, right? But just in case i will break it down so everyone can understand what's going on:Code: Select all
Actor CustomSpawnerMonsters //Don't inherit from anything { //No property has to be defined States { Spawn: TNT1 A 0 TNT1 A 0 A_Jump(128,2) //50-50 chance to spawn the next item TNT1 A 1 A_SpawnItem("Item1") //Spawn item inbetween quotes Goto Death TNT1 A 0 A_Jump(128,2) //50-50 chance to spawn next item again TNT1 A 1 A_SpawnItem("Item2") //Spawn item again Goto Death TNT1 A 0 A_Jump(128,2) TNT1 A 1 A_SpawnItem("Item3") Goto Death TNT1 A 1 A_SpawnItem("Item4") //No Jump state because this is the last spawn definition Goto Death Death: TNT1 A 0 //Remove this spawner Stop } }
The comments should tell you most of what this does, but for a more accurate description of the A_Jump line; Basically it checks the chance (in this case, 128 out of 255) and then jumps a certain amount of states/lines of code. In this example, 2 lines, the A_SpawnItem and Goto Death lines, the last of which would skip to a state where it either waits to be picked up, or dissapears if it's a monster spawner.Code: Select all
TNT1 A 0 A_Jump(128,2) //50-50 chance to spawn the next item TNT1 A 1 A_SpawnItem("Item1") //Spawn item inbetween quotes Goto Death
So if we were to make two different items spawn, we would do:Note how A_Jump has been adjusted to take the extra state into account.Code: Select all
TNT1 A 0 A_Jump(128,3) TNT1 A 1 A_SpawnItem("Item1") TNT1 A 1 A_SpawnItem("Item2") Goto Death
It's also useful to know that A_SpawnItem has parameters for height and distance, making it possible to move our spawned item(s) a slight distance from where they would normally be.
The format for those parameters is as follows: A_SpawnItem("ItemName", distanceoffset, heightoffset), both parameters are floating point numbers, so you can write 1.0 or 1.2 or whatever value you can think about (don't go over 32767 though, or bad things will happen) The distanceoffset will move the object forwards in the actor's current angle, and in 2.1.4 you may need to set that angle via ACS.
The last random spawn definition must NOT have the A_Jump line!
It's also important to notice that A_Jump is limited to one jump per call, which means that you can't do A_Jump(256, 3, 4, 6, 8) like you can in later versions. You also can't
use state labels.
Problems
-Weapon stay isn't possible with this method, instead they always respawn (but hey, it's better than no DM right?)
-Boss monster spawning won't work properly unless it's the original actor (this isn't really my fault, it's because of ZDoom's 2.1.4 hardcoded stuff)
-Monster respawning doesn't work either (not like anyone plays nightmare difficulty for the respawning though)