Spawn (ZScript)

From ZDoom Wiki
Jump to navigation Jump to search
Note: This function is for ZScript only. For the ACS function of the same name, see Spawn. For DECORATE, see A_SpawnItemEx


Actor

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

Usage

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.

Note: Remember that, when calling this function from a class that isn't based on Actor (such as from an EventHandler), it must be called as Actor.Spawn().


Parameters

  • class<Actor> type
The class name of the actor to spawn.
  • Vector3 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. For relative offsets (taking another actor's position and facing angle into account), A_SpawnItemEx may be preferable.
  • int replace
The value determines if the spawned actor can be replaced by another actor (if a replacement is provided through the replaces keyword or the CheckReplacement() event). Possible values:

Return value

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

Examples

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
{
	Default
	{
		Speed 16;
		PainChance 150;
		HitObituary "%o was too slow to avoid a Hyper Demons' jaws!";
		+AlwaysFast
		+QuickToRetaliate
		+JumpDown
	}
	States
	{
	See:
		SARG AABBCCDD 2 A_Chase (flags:CHF_FASTCHASE|CHF_NORANDOMTURN);
		Loop;
	}
}

class SummonerPower : CustomInventory
{
	Const NUMPINKIES = 5; //How many friendly fast pinkies to spawn.
	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.
	
	Default
	{
		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!";
		+Inventory.InvBar
		+Inventory.BigPowerup
		+Floatbob
		+NoGravity
	}

	States
	{
	Spawn:
		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;
	Use:
		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.Destroy();
				}
				//Otherwise
				else
				{
					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;
						}
					}
				}
			}
		}
		Stop;
	}
}

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.