Spawning Conditions
Moderator: GZDoom Developers
Forum rules
Before asking on how to use a ZDoom feature, read the ZDoom wiki first. If you still don't understand how to use a feature, then ask here.
Please bear in mind that the people helping you do not automatically know how much you know. You may be asked to upload your project file to look at. Don't be afraid to ask questions about what things mean, but also please be patient with the people trying to help you. (And helpers, please be patient with the person you're trying to help!)
Before asking on how to use a ZDoom feature, read the ZDoom wiki first. If you still don't understand how to use a feature, then ask here.
Please bear in mind that the people helping you do not automatically know how much you know. You may be asked to upload your project file to look at. Don't be afraid to ask questions about what things mean, but also please be patient with the people trying to help you. (And helpers, please be patient with the person you're trying to help!)
Spawning Conditions
Can you create a conditional for an item to spawn only when the player isn't "looking," i.e. ammo that respawns every minute or so, but if the player is looking, or is in the sector, the item will wait until the player leaves, or isn't looking, or both?
- Sir Robin
- Posts: 537
- Joined: Wed Dec 22, 2021 7:02 pm
- Graphics Processor: Intel (Modern GZDoom)
- Location: Medellin, Colombia
Re: Spawning Conditions
The actor class has a [wiki=CheckIfSeen]CheckIfSeen()[/wiki] function that tells if any player can see it.
Re: Spawning Conditions
So I would have to create a copy of the items with that particular ZScript function? And if so, how would I implement that to prevent spawning on the condition that the player can see the item?
- Sir Robin
- Posts: 537
- Joined: Wed Dec 22, 2021 7:02 pm
- Graphics Processor: Intel (Modern GZDoom)
- Location: Medellin, Colombia
Re: Spawning Conditions
You'd probably want to create a subclass, yes.Misery wrote:So I would have to create a copy of the items with that particular ZScript function? And if so, how would I implement that to prevent spawning on the condition that the player can see the item?
It's pretty simple. I'm guessing your spawner does something like this:
- Spawn an item
- wait for player to pick up item
- start countdown
- at the end of countdown go to #1
- Spawn an item
- wait for player to pick up item
- start countdown
- at the end of countdown check if player is looking
- if so, go to #3
- else go to #1
Re: Spawning Conditions
I couldn't find any examples to confirm the syntax, so this is as close as I got. Also, it won't have a sprite, so I put NONE, 'cause I don't know what to put if there is no sprite.
Code: Select all
Class DemonSpawner : RandomSpawner
{
bool CheckIfSeen()
{
if (CheckSight (target) == true)
{
return;
}
}
Default
{
//$Category Monsters/Special Monsters
//$Title Demon Spawner
DropItem "Demon"
}
States
{
Spawn:
NONE A 10;
Loop;
See:
NONE A 1 CheckIfSeen();
NONE A 70 A_SpawnItemEx ("Demon");
Loop;
}
}
- Sir Robin
- Posts: 537
- Joined: Wed Dec 22, 2021 7:02 pm
- Graphics Processor: Intel (Modern GZDoom)
- Location: Medellin, Colombia
Re: Spawning Conditions
My bad, I've never actually used spawners before. Looking at the code of RandomSpawner, I completely misunderstood how they work. Let me try something and I'll post it when it works, if someone else doesn't beat me to it
- Sir Robin
- Posts: 537
- Joined: Wed Dec 22, 2021 7:02 pm
- Graphics Processor: Intel (Modern GZDoom)
- Location: Medellin, Colombia
Re: Spawning Conditions
Ok, threw this together copying code from RandomSpawner. Stripped out some code, so don't use it to spawn items directly, instead use it to a spawn another spawner which has all the appropriate code.
It will spawn the specified object when not seen, and also if activated. So you can give it a TID and activate it with a line trigger if you'd prefer it that way.
EDIT I forgot that CheckIfSeen() logic is flipped, edited the code to negate it.
Code: Select all
class ShySpawner : actor
{
const MAX_RANDOMSPAWNERS_RECURSION = 32; // Should be largely more than enough, honestly.
default
{
SpawnerWhenSeen.ClassToSpawn "unknown";
}
string ClassToSpawn;
property ClassToSpawn : ClassToSPawn;
override void tick()
{
super.tick();
if (!CheckIfSeen()) return;
DoSpawn();
}
override Activate(actor activator)
{
DoSpawn();
}
actor DoSpawn()
{
if (ClassToSpawn ~== "Unknown") // Spawn error markers immediately.
{
Spawn(ClassToSpawn, Pos, NO_REPLACE);
Destroy();
return null;
}
if (ClassToSpawn ~== "None") // ChooseSpawn chose to spawn nothing.
{
Destroy();
return null;
}
Class<Actor> cls = ClassToSpawn;
if (cls != null)
{
Class<Actor> rep = GetReplacement(cls);
if (rep != null)
{
cls = rep;
}
}
if (cls == null)
{
A_Log(TEXTCOLOR_RED .. "Unknown item class ".. ClassToSpawn .." to drop from SpawnerWhenSeen\n");
Destroy();
return null;
}
if (bouncecount >= MAX_RANDOMSPAWNERS_RECURSION) // Prevents infinite recursions
{
Spawn("Unknown", Pos, NO_REPLACE); // Show that there's a problem.
Destroy();
return null;
}
Actor newmobj = Spawn(cls, Pos, NO_REPLACE);
bool boss = false;
if (newmobj != null)
{
// copy everything relevant
newmobj.SpawnAngle = SpawnAngle;
newmobj.Angle = Angle;
newmobj.Pitch = Pitch;
newmobj.Roll = Roll;
newmobj.SpawnPoint = SpawnPoint;
newmobj.special = special;
newmobj.args[0] = args[0];
newmobj.args[1] = args[1];
newmobj.args[2] = args[2];
newmobj.args[3] = args[3];
newmobj.args[4] = args[4];
newmobj.special1 = special1;
newmobj.special2 = special2;
newmobj.SpawnFlags = SpawnFlags & ~MTF_SECRET; // MTF_SECRET needs special treatment to avoid incrementing the secret counter twice. It had already been processed for the spawner itself.
newmobj.HandleSpawnFlags();
newmobj.SpawnFlags = SpawnFlags;
newmobj.bCountSecret = SpawnFlags & MTF_SECRET; // "Transfer" count secret flag to spawned actor
newmobj.ChangeTid(tid);
newmobj.Vel = Vel;
newmobj.master = master; // For things such as DamageMaster/DamageChildren, transfer mastery.
newmobj.target = target;
newmobj.tracer = tracer;
newmobj.CopyFriendliness(self, false);
// This handles things such as projectiles with the MF4_SPECTRAL flag that have
// a health set to -2 after spawning, for internal reasons.
if (health != SpawnHealth()) newmobj.health = health;
if (!bDropped) newmobj.bDropped = false;
// Handle special altitude flags
if (newmobj.bSpawnCeiling)
{
newmobj.SetZ(newmobj.ceilingz - newmobj.Height - SpawnPoint.Z);
}
else if (newmobj.bSpawnFloat)
{
double space = newmobj.ceilingz - newmobj.Height - newmobj.floorz;
if (space > 48)
{
space -= 40;
newmobj.SetZ((space * random[randomspawn]()) / 256. + newmobj.floorz + 40);
}
newmobj.AddZ(SpawnPoint.Z);
}
if (newmobj.bMissile && !(newmobj is 'SpawnerWhenSeen'))
newmobj.CheckMissileSpawn(0);
// Bouncecount is used to count how many recursions we're in.
if (newmobj is 'SpawnerWhenSeen')
newmobj.bouncecount = ++bouncecount;
}
Destroy();
return newmobj;
}
}
EDIT I forgot that CheckIfSeen() logic is flipped, edited the code to negate it.
Last edited by Sir Robin on Sun Jul 17, 2022 3:03 pm, edited 1 time in total.
Re: Spawning Conditions
Sorry, I don't understand ZScript with that level of complexity. How do I utilize it that way? I jus' needed a spawner that spawned monsters and ammo when the player wasn't looking. If the player not looking wasn't a requirement, I would jus' use a Map Spot. Is it possible to create a subclass of Map Spot that goes dormant when the player is looking? And reactivates after the player turns away?Sir Robin wrote:Stripped out some code, so don't use it to spawn items directly, instead use it to a spawn another spawner which has all the appropriate code.
- Sir Robin
- Posts: 537
- Joined: Wed Dec 22, 2021 7:02 pm
- Graphics Processor: Intel (Modern GZDoom)
- Location: Medellin, Colombia
Re: Spawning Conditions
Pretty easy:
The way it works is that ShySpawner will spawn whatever you tell it as soon as the players aren't looking, so now spawn that instead of the random spawner directly.
Code: Select all
//first create your random spawner:
class MyZombieSpawner : RandomSpawner
{
default
{
DropItem "ZombieMan", 255, 7;
DropItem "ShotgunGuy", 255, 3;
}
}
//Then create a shy spawner:
class MyShyZombieSpawner : ShySpawner
{
default
{
SpawnerWhenSeen.ClassToSpawn "MyZombieSpawner";
}
}
Re: Spawning Conditions
Is it possible to create the subclass of Map Spot, instead? One that will become dormant when the player can see it, and become active when the player turns away? If I inherited from Map Spot, could I use the bool CheckIfSeen to cause the Actor to become dormant if it returns true? And become active once it returns false?
- Sir Robin
- Posts: 537
- Joined: Wed Dec 22, 2021 7:02 pm
- Graphics Processor: Intel (Modern GZDoom)
- Location: Medellin, Colombia
Re: Spawning Conditions
yeah, that's pretty easy to do:
Code: Select all
class ShyMapSpot : MapSpot
{
override void tick()
{
if (CheckIfSeen())
{
if (bDormant)
{
bDormant = false;
console.printf("ShyMapSpot Activated");//DEBUG
}
}
else
{
if (!bDormant)
{
bDormant = true;
console.printf("ShyMapSpot Deactivated");//DEBUG
}
}
Super.Tick();
}
}
Re: Spawning Conditions
Thanks, that one seems much easier to understand. Sorry if I was difficult, I jus' didn't understand the first one. My ZScript skills are fairly rudimentary.
Re: Spawning Conditions
How exactly does CheckIfSeen() work? It seems to affect the Actor only when there's geometry between it and the player. If I'm only facin' away from it, it doesn't change its behavior.
- Sir Robin
- Posts: 537
- Joined: Wed Dec 22, 2021 7:02 pm
- Graphics Processor: Intel (Modern GZDoom)
- Location: Medellin, Colombia
Re: Spawning Conditions
I don't understand everytihng in the code either, I just copied it out of zscript\actors\shared\randomspawner.zs in the gzdoom.pk3 file, then took out anything related to missiles and bosses since that's not what I was designing it to spawn.Misery wrote:Thanks, that one seems much easier to understand. Sorry if I was difficult, I jus' didn't understand the first one. My ZScript skills are fairly rudimentary.
Yeah, it basically draws a line between the actor and each player and if there is no geometry blocking that line then it is considered seen. It doesn't actually check the angle and fov. For that I think you can use [wiki=CheckSight_(ZScript)]CheckSight[/wiki] or one of the other [wiki=ZScript_actor_functions#Checks]checks[/wiki] but I haven't tried that out myself yet.Misery wrote:How exactly does CheckIfSeen() work? It seems to affect the Actor only when there's geometry between it and the player. If I'm only facin' away from it, it doesn't change its behavior.
I actually need that feature in a mod I'm writing, so I'm about to try it out and will post what I find out.
Re: Spawning Conditions
I wonder if I can get a clarification on this:
"Checks if the Actor is visible to any players or cameras a player is looking through. " (from the Wiki [wiki]CheckIfSeen[/wiki] page)
How does this handle camera textures? I mean, if the map has a camera texture, and the actor concerned is in view of the camera texture, does the CheckIfSeen register as the thing is seen all the time (because a camera that is actively being cast to a texture can see it) or would it only register as seen if a player could see the camera texture?
Reason I ask is that camera textures sometimes seem to reveal parts of a map on the automap even if the player has not yet been to the part of the map where either the camera or the camera texture are.
"Checks if the Actor is visible to any players or cameras a player is looking through. " (from the Wiki [wiki]CheckIfSeen[/wiki] page)
How does this handle camera textures? I mean, if the map has a camera texture, and the actor concerned is in view of the camera texture, does the CheckIfSeen register as the thing is seen all the time (because a camera that is actively being cast to a texture can see it) or would it only register as seen if a player could see the camera texture?
Reason I ask is that camera textures sometimes seem to reveal parts of a map on the automap even if the player has not yet been to the part of the map where either the camera or the camera texture are.