Spawning Conditions

Ask about ACS, DECORATE, ZScript, or any other scripting questions here!

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!)
User avatar
Sir Robin
Posts: 399
Joined: Wed Dec 22, 2021 7:02 pm
Graphics Processor: Intel (Modern GZDoom)
Location: Medellin, Colombia

Re: Spawning Conditions

Post by Sir Robin »

Enjay wrote: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.
IDK, I think I remember reading somewhere that actual cameras will trigger the seen checks but textured ones won't. That's easy enough for you to make a map and test that out though.
Again I haven't looked at the code, but I remember someone saying that the automap works by watching the renderer, any line sent to the renderer is considered seen and marked as such on the automap. That might be why you see that behavior. But I myself haven't messed with cameras much, can't really answer that.

Ok, so about the sight checks, I just checked and both CheckSight and IsVisible functions return true when the object is unobstructed, regardless if it's in the player's FOV. IsVisible even has a boolean to turn off LOOKALLAROUND, but that doesn't seem to change anything.

If there's no built-in way, the way I'd do it is:
  1. first use CheckSight to decide if the target is even worth considering
  2. if so, check the angle from the viewer to the target. I know there is a function to do this that even considers portals and cameras, but I don't recall it's name.
  3. get the viewer's fov (it's in playerinfo)
  4. check if the angle to the target is within the fov range
Care will need to be taken with considering the angles since they can wrap (eg 0 = 360 = 720 = ...)
User avatar
Misery
Posts: 157
Joined: Sun Nov 04, 2018 4:57 pm

Re: Spawning Conditions

Post by Misery »

Sir Robin wrote: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.
How do you write the syntax for CheckSight in ZScript? Is each flag you want spelled out? Or is it like DMFlags, where you "add" up all the numbers.

Code: Select all

Class InvisibleMapSpot : MapSpot

{

	override void tick()
	{
		if (CheckSight (0, "SF_IGNOREVISIBILITY", "SF_SEEPASTSHOOTABLELINES", "SF_SEEPASTBLOCKEVERYTHING", "SF_IGNOREWATERBOUNDARY"))
		{
			if (bDormant)
			{
				bDormant = false;
				console.printf ("Activated");  //Debug purposes only
			}
		}

		else
		{
			if (!bDormant)
			{
				bDormant = true;
				console.printf ("Deactivated");  //Debug purposes only
			}
		}
		
		Super.Tick();
	}
	
	Default
	{
		//$Category ZDoom
		//$Title Map Spot (Invisible)
	}
}
This is what I have. Hopefully, this isn't the wrong syntax.
User avatar
Sir Robin
Posts: 399
Joined: Wed Dec 22, 2021 7:02 pm
Graphics Processor: Intel (Modern GZDoom)
Location: Medellin, Colombia

Re: Spawning Conditions

Post by Sir Robin »

Well, first, you want to call it from the player, not the mapspot, because you want to see if the player can see the mapspot, not if the mapspot can see the player.
so call it like this for example:
players[consoleplayer].mo.checksight()
And the target parameter wants an actual actor not a TID, so:
players[consoleplayer].mo.checksight(self)
And to combine flags you use a "binary or" character: "|"
players[consoleplayer].mo.checksight(self, SF_IGNOREVISIBILITY | SF_SEEPASTSHOOTABLELINES | SF_SEEPASTBLOCKEVERYTHING | SF_IGNOREWATERBOUNDARY)

But see my post above. In my testing CeheckSight() and IsVisible() both gave the same behavior as CheckIfSeen()

Also be aware that the output is reversed - CheckIfSeen returns true if it is NOT seen, and CheckSight and IsVisible return true when it IS seen, so adjust your logical accordingly.
User avatar
Misery
Posts: 157
Joined: Sun Nov 04, 2018 4:57 pm

Re: Spawning Conditions

Post by Misery »

So, if it's called from the player, how do I write it to affect the Map Spot? Do I keep the modified Map Spot from before, and have it be the "affectee?" Or jus' create a new Player Class with the CheckSight() function that "targets" all Map Spots? If it has to affect all Map Spots, I can use ACS for the specific Map Spots I want to affect. The problem is this information jus' doesn't exist. If I could have least find a WAD that used this function, I could pro'bly figure it out myself.
User avatar
Sir Robin
Posts: 399
Joined: Wed Dec 22, 2021 7:02 pm
Graphics Processor: Intel (Modern GZDoom)
Location: Medellin, Colombia

Re: Spawning Conditions

Post by Sir Robin »

Misery wrote:So, if it's called from the player, how do I write it to affect the Map Spot? Do I keep the modified Map Spot from before, and have it be the "affectee?" Or jus' create a new Player Class with the CheckSight() function that "targets" all Map Spots? If it has to affect all Map Spots, I can use ACS for the specific Map Spots I want to affect. The problem is this information jus' doesn't exist. If I could have least find a WAD that used this function, I could pro'bly figure it out myself.
I think it's best to make the call from within the mapspot, because how would the player even know what mapspot(s) to target? You could keep a list or build a list with a TID, but that's just not necessary. Call the sight check in the MapSpot and let it worry about it's own visibility.

The CheckSight() function needs to be called form the actor whose vision you want to check and it needs to target the actor whom you want to check against. You can write that differently depending on where in the code you put the call. I suggested it should be in should be put in the MapSpot object, but here are your options:

1) Call it in the MapSpot object:
players[consoleplayer].mo.CheckSight(self); //just an example, this will probably break in multi-player

2) Call it in the player:
CheckSight(MapSpotObject)

3) Call it in some 3rd party object:
players[consoleplayer].mo.CheckSight(MapSpotObject); //just an example, this will probably break in multi-player
User avatar
Misery
Posts: 157
Joined: Sun Nov 04, 2018 4:57 pm

Re: Spawning Conditions

Post by Misery »

Code: Select all

Class InvisibleMapSpot : MapSpot

{

	override void tick()
	{
		if (Players [consoleplayer].mo.CheckSight (Self, SF_IGNOREVISIBILITY | SF_SEEPASTSHOOTABLELINES | SF_SEEPASTBLOCKEVERYTHING | SF_IGNOREWATERBOUNDARY))
		{
			if (bDormant)
			{
				bDormant = true;
				console.printf ("Activated");  //Debug purposes only
			}
		}

		else
		{
			if (!bDormant)
			{
				bDormant = false;
				console.printf ("Deactivated");  //Debug purposes only
			}
		}
		
		Super.Tick();
	}
	
	Default
	{
		//$Category ZDoom
		//$Title Map Spot (Invisible)
	}
}
This is what I have so far, but the Map Spot is spawnin' regardless of conditions, even if I leave the area. If I can jus' make it dormant, that's all I need. I know Dormant doesn't work for non-interactive Actors, so I have an ACS function that checks for a Dormant Flag, and stops spawning if it returns true.
User avatar
Sir Robin
Posts: 399
Joined: Wed Dec 22, 2021 7:02 pm
Graphics Processor: Intel (Modern GZDoom)
Location: Medellin, Colombia

Re: Spawning Conditions

Post by Sir Robin »

Are you seeing the "activated" and "deactivated" messages when you enter and leave the area?
User avatar
Sir Robin
Posts: 399
Joined: Wed Dec 22, 2021 7:02 pm
Graphics Processor: Intel (Modern GZDoom)
Location: Medellin, Colombia

Re: Spawning Conditions

Post by Sir Robin »

Wait, I see the problem. You're not setting the dormant flag properly. Go back and look at my original code, your booleans are switched
User avatar
Misery
Posts: 157
Joined: Sun Nov 04, 2018 4:57 pm

Re: Spawning Conditions

Post by Misery »

Sir Robin wrote: Also be aware that the output is reversed - CheckIfSeen returns true if it is NOT seen, and CheckSight and IsVisible return true when it IS seen, so adjust your logical accordingly.
You said to switch them :roll:
Sir Robin wrote: Are you seeing the "activated" and "deactivated" messages when you enter and leave the area?
No, it jus' says "deactivated," and doesn't change even if I'm outside the map.
User avatar
Sir Robin
Posts: 399
Joined: Wed Dec 22, 2021 7:02 pm
Graphics Processor: Intel (Modern GZDoom)
Location: Medellin, Colombia

Re: Spawning Conditions

Post by Sir Robin »

Because CheckSight behaves differently than CheckIfSeen does, you have to use the opposite logic. So either switch the logic in the IF statement:

Code: Select all

      if (!Players[consoleplayer].mo.CheckSight(Self, SF_IGNOREVISIBILITY | SF_SEEPASTSHOOTABLELINES | SF_SEEPASTBLOCKEVERYTHING | SF_IGNOREWATERBOUNDARY))
      {
         if (bDormant)
         {
            bDormant = false;
            console.printf ("Activated");  //Debug purposes only
         }
      }
      else
      {
         if (!bDormant)
         {
            bDormant = true;
            console.printf ("Deactivated");  //Debug purposes only
         }
      }
or switch the code block entirely:

Code: Select all

      if ( Players[consoleplayer].mo.CheckSight(Self, SF_IGNOREVISIBILITY | SF_SEEPASTSHOOTABLELINES | SF_SEEPASTBLOCKEVERYTHING | SF_IGNOREWATERBOUNDARY))
      {
         if (!bDormant)
         {
            bDormant = true;
            console.printf ("Deactivated");  //Debug purposes only
         }
      }
      else
      {
         if (bDormant)
         {
            bDormant = false;
            console.printf ("Activated");  //Debug purposes only
         }
      }
User avatar
Misery
Posts: 157
Joined: Sun Nov 04, 2018 4:57 pm

Re: Spawning Conditions

Post by Misery »

Oh, nevermind. I got confused on what you meant to switch. I altered my code to match the first one.

Edit: I changed it, but it works the same as before. It only stops spawning when I leave the area. It says activated and deactivated, and also says the message I scripted in ACS, too.

Code: Select all

Class InvisibleMapSpot : MapSpot

{

	override void tick()
	{
		if (!Players [consoleplayer].mo.CheckSight (Self, SF_IGNOREVISIBILITY | SF_SEEPASTSHOOTABLELINES | SF_SEEPASTBLOCKEVERYTHING | SF_IGNOREWATERBOUNDARY))
		{
			if (bDormant)
			{
				bDormant = false;
				console.printf ("Activated");  //Debug purposes only
			}
		}

		else
		{
			if (!bDormant)
			{
				bDormant = true;
				console.printf ("Deactivated");  //Debug purposes only
			}
		}
		
		Super.Tick();
	}
	
	Default
	{
		//$Category ZDoom
		//$Title Map Spot (Invisible)
	}
}

Code: Select all

script "DEATH" (void)

{
	if (CheckFlag (308, "DORMANT") == True)
	{
		print (s: "Don't look at me!");
	}

	else
	{
		SpawnSpotFacing ("Demon", 308, 401);
		Thing_Hate (401, 0, 6);
		Delay (70);
	}

	Delay (35);
	restart;
}
User avatar
Sir Robin
Posts: 399
Joined: Wed Dec 22, 2021 7:02 pm
Graphics Processor: Intel (Modern GZDoom)
Location: Medellin, Colombia

Re: Spawning Conditions

Post by Sir Robin »

That tells you that all your logic and code is all working the way that it should. The only thing holding you up now is you don't have a function to check if the mapspot is actually in the player FOV. As I said earlier, I've tested CheckIfSeen, CheckSight, and IsVisible, and none of them seem to respect the player's FOV.
User avatar
Misery
Posts: 157
Joined: Sun Nov 04, 2018 4:57 pm

Re: Spawning Conditions

Post by Misery »

Sir Robin wrote:As I said earlier, I've tested CheckIfSeen, CheckSight, and IsVisible, and none of them seem to respect the player's FOV.
My apologies, I missed that. Okay, so it's that the function doesn't check for the condition that I need it to. So, I guess that means there's no way to create a condition that allows an action only if the player is unable to view it. But either way, I do really appreciate the assistance. Really.
User avatar
Sir Robin
Posts: 399
Joined: Wed Dec 22, 2021 7:02 pm
Graphics Processor: Intel (Modern GZDoom)
Location: Medellin, Colombia

Re: Spawning Conditions

Post by Sir Robin »

try this:

Code: Select all

    override void Tick()
    {
        bool seen = isPlayerLooking(consoleplayer);
        
        if (bDormant)
        {
            if (!seen)
            {
                bDormant = false;
                console.printf("Shy Actor is active");//DEBUG
            }
        }
        else
        {
            if (seen)
            {
                bDormant = true;
                console.printf("Shy Actor is dormant");//DEBUG
            }
        }
    }
    
    bool isPlayerLooking(int PlayNum)
    {
        if (!players[playnum].mo.CheckSight(self, SF_IGNOREVISIBILITY | SF_SEEPASTSHOOTABLELINES | SF_SEEPASTBLOCKEVERYTHING | SF_IGNOREWATERBOUNDARY)) return false;

        double PlayAng = players[playnum].mo.angle;  
        double AngleToMe = players[playnum].mo.AngleTo(self);
        double AngleDiff = AbsAngle(AngleToMe, PlayAng);
        double PlayFovRange = players[playnum].fov / 2;

        return AngleDiff < PlayFovRange;
    }
 
It's not perfect but gives you something to test with until you get something better.
Most obvious limitations:
  1. Doesn't consider pitch (height) only the angle (width) of the view
  2. Only checks if player can see the center base of the object
  3. Doesn't consider widescreen view - object at the edges of the widescreen will not detect correctly
Like I said, not perfect, but you can use it until you find something better
User avatar
Misery
Posts: 157
Joined: Sun Nov 04, 2018 4:57 pm

Re: Spawning Conditions

Post by Misery »

Code: Select all

Class InvisibleMapSpot : MapSpot

{

	override void tick()
	{
		bool seen = IsPlayerLooking (ConsolePlayer);
		
		if (bDormant)
		{
			if (!seen)
			{
				bDormant = false;
				console.printf ("Activated");  //Debug purposes only
			}
		}

		else
		{
			if (seen)
			{
				bDormant = true;
				console.printf ("Deactivated");  //Debug purposes only
			}
		}
	}
	
	bool IsPlayerLooking (int PlayNum)
	{
		if (!Players [PlayNum].mo.CheckSight (Self, SF_IGNOREVISIBILITY | SF_SEEPASTSHOOTABLELINES | SF_SEEPASTBLOCKEVERYTHING | SF_IGNOREWATERBOUNDARY))
		
		double PlayAng = Players [PlayNum].mo.angle;
		double AngleToMe = Players [PlayNum].mo.AngleTo (Self);
		double AngleDiff = AbsAngle (AngleToMe, PlayAng); (Line 34)
		double PlayFOVRange = Players [PlayNum].FOV / 2;
		
		return AngleDiff < PlayFOVRange; (Line 37)
	}
	
	Default
	{
		//$Category ZDoom
		//$Title Map Spot (Invisible)
	}
}

Code: Select all

Script error, "Monster Spawner.wad:ZSCRIPT" line 34:
Unknown identifier 'PlayAng'
Script error, "Monster Spawner.wad:ZSCRIPT" line 37:
Unknown identifier 'anglediff'

Execution could not continue.

2 errors while parsing DECORATE scripts
I tried to google the two identifiers, and I looked for them in the Advanced ZScripts I got from GitHub, but I couldn't find them.
Last edited by Misery on Sun Jul 24, 2022 3:06 pm, edited 3 times in total.

Return to “Scripting”