Spawn (ZScript)

From ZDoom Wiki
Jump to navigation Jump to search

Note: This feature is for ZScript only.

native static Actor Spawn(class<Actor> type[, vector3 pos = (0,0,0), int replace = NO_REPLACE])


Spawns an actor class at the specified absolute coordinates. Unlike other spawn functions like A_SpawnItem or A_SpawnItemEx, this function is completely barebones, and does nothing else. Allowing you to write any sort of custom spawning behavior you want. This also means that it is incredibly lightweight, which is good for performance critical code that doesn't need the additional functionality of the other actor spawn functions.


  • type - The class name of the actor to spawn.
  • pos - The absolute Vector3 coordinates to spawn the actor at, to use non-absolute coordinates to offset where the actor spawns, you can use Vec3Offset.
  • replace - Should the actor be replaced by whatever actor replaces it ? e.g If DoomImp should be spawned specifically, instead of whatever other actor replaces it.

Return value

Returns a pointer to the actor that was spawned, allowing for post-spawn modifications and the like.


This is a spawner powerup that uses Spawn() to spawn 5 friendly replacements of the Demon to assist the player when they select and use the item, and then stores the pointer that the function returns to perform the required status changes and checks to each of the spawned demons.

//The custom Pinky replacement that we will make Spawn() create.
Class HyperDemon : Demon Replaces Demon
		Speed 16;
		PainChance 150;
		HitObituary "%o was too slow to avoid a Hyper Demons' jaws !";

Class SummonerPower : CustomInventory
	Const NumPinkies = 5; //How many friendly fast pinkies to spawn.
		Inventory.Amount 1;
		Inventory.MaxAmount 5;
		Scale 0.5;
		Radius 20;
		Height 45;
		RenderStyle "Add";
		FloatBobStrength 0.5;
		Inventory.PickupSound "misc/p_pkup";
		Inventory.PickupMessage "Picked up the Summon Powerup !";
	Actor Spawnee; //A pointer to each of the pinkies we'll spawn. To make the needed status changed to them.
	Vector3 SpawnPos; //Stores the coordinates that each pinky will be spawned at.
			TNT1 A 0 NoDelay A_AttachLight ('PowerupLight',DynamicLight.PulseLight,"FFAC35",48,46,DynamicLight.LF_Attenuate,param:0.2);
			SARG A 1 Bright A_SetAngle (Angle+5);
			SARG A 0 Bright A_SpawnParticle ("FFAC35",SPF_FULLBRIGHT|SPF_RELATIVE,size:2,xoff:FRandom(Radius,-Radius),FRandom(Radius,-Radius),FRandom(Height,-Height),velz:FRandom(0.2,2.0));
			SARG A 0 Bright A_SpawnParticle ("FFAC35",SPF_FULLBRIGHT|SPF_RELATIVE,size:2,xoff:FRandom(Radius,-Radius),FRandom(Radius,-Radius),FRandom(Height,-Height),velz:FRandom(0.2,2.0));
			SARG A 0 Bright A_SpawnParticle ("FFAC35",SPF_FULLBRIGHT|SPF_RELATIVE,size:2,xoff:FRandom(Radius,-Radius),FRandom(Radius,-Radius),FRandom(Height,-Height),velz:FRandom(0.2,2.0));
			Goto Spawn+1;
			TNT1 A 0
				A_RemoveLight ('PowerupLight');
				//Spawn demons until "I" reaches the value specified in NumPinkies.
				For (Int I = 0; I < Invoker.NumPinkies; I++)
					//While Spawn() uses absolute coordinates. You can use Vec3Offset to make it spawn actors relative to whatever caller calls the function.
					Invoker.SpawnPos = Vec3Offset (FRandom(256,-256),FRandom(256,-256),0);
					This line will spawn a demon at the specified random coordinates relative to the player. Which were calculated above.
					And the replace parameter is also set to ALLOW_REPLACE, so that instead of spawning the vanilla demon, the function
					will spawn whatever actor replaces the demon, which in this case is the HyperDemon actor.
					And then the pointer to the demon that was spawned will be added to the Spawnee variable, so that we can performn
					checks and status changes to the newly spawned demon.
					Invoker.Spawnee = Spawn ("Demon",Invoker.SpawnPos,ALLOW_REPLACE);
					Spawn ("TeleportFog",Invoker.SpawnPos); //We will also spawn a teleport effect at the demons' position, no need to care about it not obeying any custom replacements or about storing a pointer to it.
					Level.Total_Monsters--; //Subtract the demons from the monster count, as they are allies to the player.
					//If the demon was spawned in the void or stuck in anything, then remove it.
					If (!Level.IsPointInLevel(Invoker.Spawnee.Pos) || !Invoker.Spawnee.TestMobjLocation())
						Invoker.Spawnee.Angle = Angle; //Face the same direction as the player.
						Invoker.Spawnee.bFriendly = True; //Make the demon friendly.
						Invoker.Spawnee.SetFriendPlayer(Player); //And make it work for the player that activated the powerup.
						//And at last, if the player had an actor that last attacked them.
						If (Player.Attacker)
							//Then make the demons attack the players' attacker immediately if it isn't a friendly monster at all,
							//or if we are in a deathmatch game, and the attacker is a friendly monster that works for an enemy player.
							If (!(Player.Attacker.bFriendly) ||
							Deathmatch && Invoker.Spawnee.FriendPlayer != 0 && Player.Attacker.FriendPlayer != Invoker.Spawnee.FriendPlayer)
								Invoker.Spawnee.LastHeard = Invoker.Spawnee.Target = Player.Attacker;

Do note that this code is only meant to be used as an example of how Spawn() can be used, and otherwise has several flaws to it, such as the powerups' dynamic light sometimes not being removed, or the extended spawning code making no attempts to try and spawn a pinky that failed to spawn again.