Actor make a sound when player walks through it - how?

Ask about ACS, DECORATE, ZScript, or any other scripting questions here!
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
Enjay
 
 
Posts: 27393
Joined: Tue Jul 15, 2003 4:58 pm
Location: Scotland

Actor make a sound when player walks through it - how?

Post by Enjay »

I have a very simple ZScript decoration. It has no collision and minimal height, and it simply exists to allow a flat-plane model to be placed in game. The model looks like a drain cover and doing it this way allows me to place drain covers wherever I need them to be without being tied to the appearance of background flats and flat offsets.

However, it would be nice if, as the player walked "on" (i.e. through - but bear in mind the actor is only around 1 or 2 units tall IIRC) the actor made the "clang" sound of the player walking on a metal surface.

What would be the best way to do that? I'm sure that a bit of cunning ZScript code could probably check that the player had entered the actor's bounding box and make a sound, but I don't know how to do it. Can anyone suggest/share code for that feature?

I could do it by making a 64x64 sector everywhere that I place the actor and just use ACS scripting to make the sound when the player enters the sector, but that kind of defeats some of the purpose of having a flexible actor that can be placed anywhere.
JaedenDuhreis
Posts: 12
Joined: Sun Jan 02, 2022 7:19 am

Re: Actor make a sound when player walks through it - how?

Post by JaedenDuhreis »

I would give +SPECIAL flag to the decoration and override its Touch() virtual to make the sound.
User avatar
Enjay
 
 
Posts: 27393
Joined: Tue Jul 15, 2003 4:58 pm
Location: Scotland

Re: Actor make a sound when player walks through it - how?

Post by Enjay »

Sorry that I've taken so long to get back to this.

I suspect what I'm doing is a crass mess, but here goes...

Both examples replace the Zombieman simply to make it easy to test in map01 of Doom2 (I just need to load the ZScript lump and then go bump into a zombieman).
The sounds and message are obviously just debug/testing code.

This one is quite close to what I want:

Code: Select all

Class Test01 : Actor replaces zombieman
{
	Default
	{
		Height 1;
		Radius 32;
		+SOLID;
		+BUMPSPECIAL;
		Activation THINGSPEC_Switch;
	}
	
	States
	{
		Spawn:
		POSS A 1;
		Loop;
	}
	
	override void Activate (Actor activator)
	{
		Console.MidPrint(null, "Activate.");
		A_StartSound ("misc/chat", CHAN_ITEM, CHANF_DEFAULT, 1.0, ATTN_NORM, 0, 0);
	}
	
	override void Deactivate(Actor activator)
	{
		Console.MidPrint(null, "DeActivate.");
		A_StartSound ("misc/chat2", CHAN_ITEM, CHANF_DEFAULT, 1.0, ATTN_NORM, 0, 0);
	}
}
That *almost* does what I want. The problems are:
1) I needed to use activate and deactivate because with just Activate, the sound only played about once every 2 seconds. With activate and deactivate, it plays twice as often. However, that strikes me as hacky.
2) the actor has to be solid for the bumpspecial to work and I'd rather that it wasn't.
3) If you stand still on the item, it continues to activate/deactivate over and over.

There is an alternative which is probably better, but it still strikes me as hacky:

Code: Select all

class Test : Inventory replaces Zombieman
{
		
	Default
	{
		Height 1;
		Radius 32;
		+INVENTORY.ALWAYSPICKUP
	}
	
	States
	{
		Spawn:
		POSS A 1;
		Loop;
	}

	override void Touch (Actor toucher)
	{
		let player = toucher.player;
		if (player)
		{
			Console.MidPrint(null, "Touching.");
			A_StartSound ("misc/chat", CHAN_ITEM, CHANF_DEFAULT, 1.0, ATTN_NORM, 0, 0);
		}
	}
}
The reason it feels hacky is that the only way I could get it to work was to inherit from Inventory and, given that this is not a pickup of any sort, that feels wrong. At least it uses the Touch virtual like JaedenDuhreis suggested.

The other problem with it is that as soon as the player comes within the radius of the actor, the sound starts playing repeatedly and rapidly and doesn't stop until either the player leaves the radius of the thing, or comes to a complete halt on it. So, actually, that's very close to what I want - if I can just slow down how frequently the sound plays. i.e. if the player is moving within the thing, the sound will be played over and over, it's just repeating too rapidly.


So, am I barking up the wrong tree with this?
Have I committed any hideous ZScript crimes (probably)?
Is there a better way to be doing this (presumably "yes" seeing as how neither option works perfectly)?
User avatar
fakemai
Posts: 411
Joined: Mon Feb 12, 2018 12:26 am
Location: Australia

Re: Actor make a sound when player walks through it - how?

Post by fakemai »

For the SFX spamming issue you'd have to incorporate some kind of cooldown variable. So give your object an int "lasttouched" and then do a test like if(lasttouched < self.GetAge()) play your sound, and then set lasttouched to self.GetAge() + x, where x is how many tics you want the cooldown to last. The downside of this over using TERRAIN definitions to my mind is player footsteps not being in sync.
User avatar
Enjay
 
 
Posts: 27393
Joined: Tue Jul 15, 2003 4:58 pm
Location: Scotland

Re: Actor make a sound when player walks through it - how?

Post by Enjay »

Thanks. I'll try that when I get a chance.

The sync thing is not a major issue in this case. It's just manhole cover that I usually place in a map scaled so that it is just under 64 units in diameter. So, all the really needs to happen is for the the thing to go "clang" once or maybe twice as the player runs over it.

I do also have terrain footsteps enabled, but a single "clang" being out of sync (or even happening at the same time as a normal footstep) shouldn't be an issue. In fact, it's because I have footsteps that I want the clang. It seems odd for the player to be running over something that looks very metallic but to still just hear the normal sound of footsteps on the road surface. So, even if that still happens, an additional metallic noise would just be enough to signal "you ran over the manhole cover".

Is it OK to inherit from Inventory for this purpose like I did with the second example?

[edit]
OK, I think I got the sound spamming thing done on my test actor:

Code: Select all

class Test : Inventory replaces Zombieman
{
		
	int lasttouched;
	
	Default
	{
		Height 1;
		Radius 32;
		+INVENTORY.ALWAYSPICKUP
	}
	
	States
	{
		Spawn:
		POSS A 1;
		Loop;
	}

	override void Touch (Actor toucher)
	{
		let player = toucher.player;
		if (player)
		{
			if(lasttouched < self.GetAge())
			{
				Console.MidPrint(null, "Touching.");
				A_StartSound ("misc/chat", CHAN_ITEM, CHANF_DEFAULT, 1.0, ATTN_NORM, 0, 0);
			}
		lasttouched = self.GetAge() + 16;
		}
	}
}
It has certainly stopped the sound spamming. The sound usually only plays once and, because by the time it was due to play again the player has usually stopped, it doesn't just keep repeating, but if the player moves off, there is another sound played - which is fine.
User avatar
Enjay
 
 
Posts: 27393
Joined: Tue Jul 15, 2003 4:58 pm
Location: Scotland

Re: Actor make a sound when player walks through it - how?

Post by Enjay »

OK, slight change of tack. As I mentioned, I got the delay working, but I discovered that inheriting from inventory means that if you drop down directly onto a pickup, it doesn't activate. You need some horizontal movement. So, if you stood on the manhole cover just pressing the jump button but not otherwise moving, there was no sound, and that seemed odd when jumping up and down on a metal plate.

So, I decided to go back to the other option of an item that activates/deactivates when you are touching it, but also try to use the "lasttouched" method to make it so that the thing doesn't keep activating/deactivating while you are standing on it.

This seems to do what I want:

Code: Select all

Class Test01 : Actor replaces zombieman
{
	int lasttouched;
	
	Default
	{
		Height 1;
		Radius 32;
		+SOLID;
		+BUMPSPECIAL;
		Activation THINGSPEC_Switch;
	}
	
	States
	{
		Spawn:
		POSS A 1;
		Loop;
	}
	
	override void Activate (Actor activator)
	{
		if(lasttouched < self.GetAge())
		{
			Console.MidPrint(null, "Activate.");
			A_StartSound ("misc/chat", CHAN_ITEM, CHANF_DEFAULT, 1.0, ATTN_NORM, 0, 0);
		}
		
		lasttouched = self.GetAge() + 36;
	}
	
	override void Deactivate(Actor activator)
	{
		if(lasttouched < self.GetAge())
		{
			Console.MidPrint(null, "DeActivate.");
			A_StartSound ("misc/chat2", CHAN_ITEM, CHANF_DEFAULT, 1.0, ATTN_NORM, 0, 0);
		}
		
		lasttouched = self.GetAge() + 36;
	}
}
Does that seem reasonable, or is there a more efficient way of doing it?


FWiW, I tried what I hoped would be a simpler approach:

Code: Select all

Class Test01 : SwitchableDecoration replaces zombieman
{
	Default
	{
		Height 1;
		Radius 32;
		+SOLID;
		+BUMPSPECIAL;
		Activation THINGSPEC_Switch;
	}
	
	States
	{
		Spawn:
		POSS A 1;
		Loop;
		Active:
		SPOS A 1 A_StartSound ("misc/chat", CHAN_ITEM, CHANF_DEFAULT, 1.0, ATTN_NORM, 0, 0);
		goto Spawn;
		Inactive:
		SPOS A 1 A_StartSound ("misc/chat2", CHAN_ITEM, CHANF_DEFAULT, 1.0, ATTN_NORM, 0, 0);
		goto Spawn;
	}
}
Obviously that one just constantly activates and deactivates while you are standing on it but I thought if I could figure out some way of testing if the player was still in contact with the thing, then I could pause activating/deactivating until the player moved away. However, I couldn't figure it out. I did try a few things using TestMobjLocation() but nothing I tried actually worked (if it even allowed UZDoom to run - which most attempts didn't).
User avatar
Enjay
 
 
Posts: 27393
Joined: Tue Jul 15, 2003 4:58 pm
Location: Scotland

Re: Actor make a sound when player walks through it - how?

Post by Enjay »

Seeing as how I felt my efforts were hacky and maybe not right, I decided to give ChatGPT a chance. Yes, I know, I know.

I just asked it:
Me to an evil AI wrote:Code an actor in ZSCript that makes a sound when you step on it, doesn't repeat the sound while you remain within the actor's bounding box but if you leave and come back it will make the sound again.
Much to my surprise, it came back with something that looked like it might even work.

It didn't.

However, with a couple of syntax tweaks that even I could spot, it actually created a working actor that appears to do what I want. When I step on/in the actor, a sound plays and it won't repeat while I remain in there. If I leave and come back (including jumping up and down) it makes a sound every time I land back in the actor.

I guess the only refinement I could want is if I was still moving in the box, there would be a chance of another footstep being played after a few tics.

Logic-wise, it is using a totally different method to the suggestions here and what I have tried so far. I'm not 100% sure but I *think* what it does is track when the player enters the actor's bounding box, plays the sound, marks the player as inside the bounding box and refuses to play the sound again while the player is in there. It looks like it resets things when the player leaves so that the sound can be repeated if the player re-enters.

Is that a correct interpretation?
Has my little AI "friend" done something that's actually reasonable or is there something in there that is potentially problematic?

Like I said, it appears to work, but the syntax errors it made initially were very basic (e.g. a 0 duration loop in the spawn state sequence) that I worry it might have done something else nasty elsewhere.

Code: Select all

class Test01 : Actor replaces Zombieman
{
    bool playerInside;

    Default
    {
        Radius 32;
        Height 1;
    }

    States
    {
    Spawn:
        POSS A -1;
        Stop;
    }

    override void Tick()
    {
        super.Tick();

        PlayerPawn p = PlayerInBox();

        if (p != null)
        {
            if (!playerInside)
            {
                A_StartSound("misc/chat", CHAN_AUTO);
                playerInside = true;
            }
        }
        else
        {
            playerInside = false;
        }
    }

    PlayerPawn PlayerInBox()
    {
        ThinkerIterator it = ThinkerIterator.Create("PlayerPawn");
        PlayerPawn pp;

        while ((pp = PlayerPawn(it.Next())) != null)
        {
            Actor a = pp;

            if (a.pos.x >= pos.x - radius && a.pos.x <= pos.x + radius &&
                a.pos.y >= pos.y - radius && a.pos.y <= pos.y + radius &&
                a.pos.z >= pos.z - 1      && a.pos.z <= pos.z + height)
            {
                return pp;
            }
        }

        return null;
    }
}
Edit:

OK, I asked it to allow a second instance of the sound to be played if the player was still inside the bounding box and moving after 1 second, and also to account for small player movements that shouldn't make a sound. I also asked it to comment its code.

Again, it seems to have come up with something that works.

Code: Select all

class Test01 : Actor replaces Zombieman
{
    // Tracks whether the player is currently inside the trigger
    bool playerInside;

    // Counts down tics until the next allowed sound
    int repeatTimer;

    // Stores the last position of the player to detect movement
    Vector3 lastPlayerPos;

    Default
    {
        // Bounding box dimensions (adjust as needed)
        Radius 32;
        Height 2;
    }

    States
    {
    // Spawn state — displays the actor's sprite
    Spawn:
        POSS A 1;  // Show POSSA frame A for 1 tic
        Loop;      // Loop the state indefinitely
    }

    override void Tick()
    {
        super.Tick();  // Call base Tick for normal actor behavior

        // Check if any player is inside the bounding box
        PlayerPawn p = PlayerInBox();

        if (p != null)
        {
            Vector3 currentPos = p.pos;  // Store current player position

            if (!playerInside)
            {
                // Player just entered the trigger
                A_StartSound("misc/chat", CHAN_AUTO);  // Play sound
                playerInside = true;                   // Mark as inside
                repeatTimer = 35;                      // 1-second cooldown
            }
            else
            {
                // Player is still inside the box
                repeatTimer--;  // Decrease cooldown timer each tic

                // Compute distance moved since last tick
                float moveDistance = (currentPos - lastPlayerPos).Length();

                // If cooldown expired AND player moved more than threshold
                if (repeatTimer <= 0 && moveDistance > 1.0)
                {
                    A_StartSound("misc/chat", CHAN_AUTO);  // Play sound again
                    repeatTimer = 35;                      // Reset cooldown
                }
            }

            // Update last player position
            lastPlayerPos = currentPos;
        }
        else
        {
            // Player left the bounding box — reset variables
            playerInside = false;
            repeatTimer = 0;
        }
    }

    // Helper function: returns a PlayerPawn if inside the bounding box, else null
    PlayerPawn PlayerInBox()
    {
        // Iterate over all PlayerPawn actors in the map
        ThinkerIterator it = ThinkerIterator.Create("PlayerPawn");
        PlayerPawn pp;

        while ((pp = PlayerPawn(it.Next())) != null)
        {
            Actor a = pp;  // Treat player as generic Actor for position checks

            // Axis-aligned bounding box check
            if (a.pos.x >= pos.x - radius && a.pos.x <= pos.x + radius &&
                a.pos.y >= pos.y - radius && a.pos.y <= pos.y + radius &&
                a.pos.z >= pos.z - 1      && a.pos.z <= pos.z + height)
            {
                // Player is inside the box
                return pp;
            }
        }

        // No players found inside
        return null;
    }
}
I do feel a bit icky about doing it this way but it does seem to have produced a working actor. Morality aside, it is quite impressive.
ZzZombo
Posts: 332
Joined: Mon Jul 16, 2012 2:02 am

Re: Actor make a sound when player walks through it - how?

Post by ZzZombo »

Do you want it to work only for the player passing over? Or any actor? Does it have to trigger for several at once?
User avatar
Enjay
 
 
Posts: 27393
Joined: Tue Jul 15, 2003 4:58 pm
Location: Scotland

Re: Actor make a sound when player walks through it - how?

Post by Enjay »

Yes, just the player.

I am implementing footsteps for the player anyway, but not the monsters. I know that's an inconsistency but I don't want hundreds of footstep sounds being played. So, my logic is that the player is closest to their own feet and can hear them. Enemies will have an occasional footstep sound randomly thrown into their active sounds and they can make sounds if they drop onto a surface (using terrain splash logic).

So, anyway, given that this item is meant to be a metal drain cover, I just want it to "clang" as the player walks over it to seem a bit like terrain footsteps. It just felt odd to have the player make "walking on a hard surface" sounds with their feet that just continued when they stepped on to something that was clearly meant to be a metal plate on the ground. However, the flexibility of being able to place the drain cover anywhere, and on any surface, was more important than having a bunch of specific flats set up with different background textures that had their own terrain sound definitions. A single actor that can be placed anywhere and also made a sound when you walk on it seemed like an ideal solution.

In this case, I'm aiming at single player and the drain cover is only normal size (proportional to the Doom player). So, even in multiplayer, it would be hard to get two players on to the actor at the same time and for it to be obvious that their footsteps weren't making the noises separately. Also, an occasional missed footstep isn't a deal-breaker anyway. I *think* the ChatGPT code just makes the sound for the first player on to the actor, but it's not a problem because (like I said) it's not really big enough for two players to be wandering around on it at the same time anyway.

However, if it was ever to be used in multiplayer (unlikely), then different players triggering different drain-cover actors would be important. I have tested it using the built-in ZCajun bots and a corridor full of the drain-cover actors and triggering of several different drain-cover actors at the same time seems to be working with the ChatGPT code. Like I said, it's not that important for my current plans, but it does seem to work in multiplayer - or at least as well as I need it to.

Here's a quick video of a test of it working in MAP01 (just replacing Zombiemen) using the ChatGPT code - slightly tweaked because a 1 second delay was too long. Obviously, it will look better in the final thing - it will have better lighting, be on more suitable surfaces etc. Assuming I get around to finishing it. Initially, it's just me in the map, but I also spawned in some bots. (Check your volume - the video makes the sound seem much louder than it actually is in game for some reason.)

So, that's actually doing pretty much what I need it to now. Sounds and volumes may need tweaking but, code-wise, the actor is behaving much as I hoped it would. I'm still open to improvements though, especially as I don't trust the AI to have not put in something that is prone to a VM abort under certain circumstances or whatever.
ZzZombo
Posts: 332
Joined: Mon Jul 16, 2012 2:02 am

Re: Actor make a sound when player walks through it - how?

Post by ZzZombo »

The code the LLM gave you is overly complicated. I'm somewhat rusty, but if I were you, I'd just make the actor a monster with only a melee attack, `-SOLID`, `+INVULNERABLE`, `-COUNTKILL`; the range of the attack and sight range is set to slightly less range than its radius so that you'd need to actually step into it, also make it deaf by consulting the parameters of `A_LookEx()`. The attack state sequence only consists of the state that plays the sound with the needed delay between "activations" being the duration of the state in tics, and goes back to the `See` state sequence; if the player is still stepping on it, it would re-trigger the attack, playing the sound again. Now, if you wish it would only trigger if the player is moving, you can check the player's velocity, if I'm not mistaken, it would be something like `A_JumpIf(target.z != z || (target.vel.x == 0 && target.vel.y == 0 && target.vel.z == 0), "See.Wait")`, that is, go to the `See.Wait` state if the player (target) doesn't stand on the same elevation (melee attacks are performed in a sphere unless a compat. option for infinitely tall monster melee attacks is on) or is standing still. Otherwise it proceeds to play the sound. The state it jumps to should wait some time before it returns to the `See` state in order to avoid infinite recursion. One last bit of this setup is to clear the monster's target if in a given `See` state sequence it didn't attempt to attack a player, so that another player could trigger it, as otherwise it would stick indefinitely to the first player; `A_ClearTarget()` IIRC does the job. You'd also probably want not to have it affected by difficulty levels such as "Nightmare!".
User avatar
Enjay
 
 
Posts: 27393
Joined: Tue Jul 15, 2003 4:58 pm
Location: Scotland

Re: Actor make a sound when player walks through it - how?

Post by Enjay »

Thanks for the suggestion. I have tried a few "mechanical" options, relying on state jumps and so on, but eventually I thought that an actual ZScript code solution was likely to be more reliable/predictable.

I haven't tried exactly what you suggested, but I have gone some way along the line of setting it up. My problem was that I couldn't figure out a way of letting the actor "know" that the player had left its bounding box (which your suggestion covers, of course). I did try a melee attack along the lines of what you suggest but one problem was that it didn't trigger as reliably as the LLM code does. It was perfectly possible for the player to enter the bounding box and for the "monster" to simply decide not to attack. I tweaked aggressiveness and so on, and got it happening most of the time, but it still wasn't that reliable.

A fun side effect of making the actor a monster was that when I typed "kill monsters" on my test map to get rid of any enemies that would mess up the test, all the drain covers vanished too. :lol: (I know there are ways around that.)

What you suggest does seem more reliable than my own experiments with a similar method though, and I'll give it a go to see if I can set it up, but - at least from description alone, it doesn't actually seem that much simpler than the code that the LLM came up with. As I understand the LLM code, its logic is essentially:

A player has entered the bounding box, play a sound immediately and wait (I have now set this to 10 tics - that's what's in the video)
The player is still here and still moving (at least 1 unit), play a sound and wait or
The player is still here, but not moving, don't play a sound or
The player has left, do nothing.

So, the basic logic seems pretty simple and easy to follow (assuming that I have it right). It's just the syntax that I can't come up with myself because I have minimal coding experience, and a lot of the terms are actually not particularly apparent if you don't have a coding background. If code exists, I can generally follow it (if it's simple; otherwise I need help) but coming up with it from scratch is another story. I'm trying to get there though. :)
ZzZombo
Posts: 332
Joined: Mon Jul 16, 2012 2:02 am

Re: Actor make a sound when player walks through it - how?

Post by ZzZombo »

How exactly was it not reliable? I've done similar things in the past in just Decorate in Skulltag of all ports, so I'm genuinely curious, because if I had any problems with my approach, I'd never suggest it.

However, I also just remembered how I did mines in the past, and one implementation was a `CustomInventory` item which you already tried, but you want it to trigger even if the player has no horizontal velocity. Well, it's a hack, but because the player doesn't have to be the one moving in order to pick items up, you can make the item alternate between moving one unit in two opposite directions, by overriding `Tick()` and writing something like `vel.x += GameTic % 2 ? 1 : -1`, preferably first checking that it isn't moving already.
User avatar
phantombeta
Posts: 2198
Joined: Thu May 02, 2013 1:27 am
Operating System Version (Optional): Windows 10
Graphics Processor: nVidia with Vulkan support
Location: Brazil

Re: Actor make a sound when player walks through it - how?

Post by phantombeta »

As far as I can tell, the LLM code is fine, just a bit inefficient (ThinkerIterator is not very efficient for this). It's also not portal-aware at all.

Edit: Here's my own version of it. IMO it's cleaner than the LLM version (though slightly more complicated- mine handles multiplayer :P), and it's definitely more efficient.
Bonus points: My version also makes the manhole cover round :P

Code: Select all

class Test : Actor {
    struct PlayerStepData {
        // Used to determine if the player is still touching the actor- if the difference is >1 tic, the player got off it
        int lastTouchTime;
        // Used to filter out small steps (we only check 2D to make it more reliable)
        Vector2 lastPos;
        int cooldown;
    }

    const MIN_STEP_DISTANCE = 1;
    const COOLDOWN_TIME = 10;

    Default {
        Radius 32;
        Height 2;

        YScale 0.2;
    }

    PlayerStepData stepData [MAXPLAYERS];

    override void Tick () {
        Super.Tick ();

        for (int pNum = 0; pNum < MAXPLAYERS; pNum++) {
            if (!playeringame [pNum] || !players [pNum].mo)
                continue;

            let toucher = players [pNum].mo;

            // Handle the Z axis first (since it's the simplest one)
            // We check if the player's "feet" (i.e. the bottom of its bounding box) are inside this actor
            if (toucher.Pos.Z < Pos.Z || toucher.Pos.Z > Pos.Z + Height)
                continue;

            let diff = Vec2To (toucher);
            let dist = diff.Length ();
            // Check if we have roughly the same center position
            if (dist ~== 0) {
                CheckStep (pNum, toucher);
                continue;
            }

            // Check if the closest point of the actor is inside the player's bounding box
            let closestPointOnCircle = Pos.XY + (diff / dist) * min (Radius, dist);
            if (abs (closestPointOnCircle.X - toucher.Pos.X) > toucher.Radius ||
                abs (closestPointOnCircle.Y - toucher.Pos.Y) > toucher.Radius)
                continue;

            CheckStep (pNum, toucher);
        }
    }

    void CheckStep (int pNum, Actor toucher) {
        let curTime = GetAge ();
        if ((curTime - stepData [pNum].lastTouchTime) > 1) {
            // Just stepped on
            stepData [pNum].lastTouchTime = curTime;
            OnStepped (pNum);
            return;
        }

        stepData [pNum].lastTouchTime = curTime;

        // We fetch the current "last position" here and then store the new one to simplify the rest of the code
        // (So we don't need to store it whenever we exit early)
        let lastPos = stepData [pNum].lastPos;
        stepData [pNum].lastPos = toucher.Pos.XY;

        // Handle cooldown between steps
        if (stepData [pNum].cooldown > 0) {
            stepData [pNum].cooldown--;
            return;
        }

        // Check the distance the player moved and ignore it if it's too small
        let stepDist = level.Vec2Diff (toucher.Pos.XY, lastPos);
        if ((stepDist dot stepDist) < MIN_STEP_DISTANCE * MIN_STEP_DISTANCE)
            return;

        OnStepped (pNum);
    }

    void OnStepped (int pNum) {
        stepData [pNum].cooldown = COOLDOWN_TIME;

        // Do whatever you want to happen when it gets stepped on here (e.g., play a sound, alert monsters, etc.)
        A_StartSound ("misc/chat");
    }

    States {
    Spawn:
        POSS A 1;
        Loop;
    }
}
User avatar
Enjay
 
 
Posts: 27393
Joined: Tue Jul 15, 2003 4:58 pm
Location: Scotland

Re: Actor make a sound when player walks through it - how?

Post by Enjay »

ZzZombo wrote: Thu Nov 20, 2025 8:31 pm How exactly was it not reliable? I've done similar things in the past in just Decorate in Skulltag of all ports, so I'm genuinely curious, because if I had any problems with my approach, I'd never suggest it.
Sorry, I should have been clearer. I was referring to my own attempts, rather than exactly what you had suggested. By reliability I meant that the LLM code guarantees as soon as the player enters the bounding box, the sound will be played that tic. If the player is still there and moving 10 tics later, the sound will be played again. That's versus my attempt where the logic was more like "the player has entered the bounding box, I will now decided whether to attack or not". So, the "unreliability" I was getting was because I was introducing some potential latency in the system when the enemy was going through whatever logic an enemy goes through when deciding to make an attack, versus the code unconditionally saying "the player is here, so we make a noise."
User avatar
Enjay
 
 
Posts: 27393
Joined: Tue Jul 15, 2003 4:58 pm
Location: Scotland

Re: Actor make a sound when player walks through it - how?

Post by Enjay »

phantombeta wrote: Fri Nov 21, 2025 4:37 am As far as I can tell, the LLM code is fine, just a bit inefficient (ThinkerIterator is not very efficient for this). It's also not portal-aware at all.
But, but the LLM assured me that it had given me robust, efficient code. :lol:

phantombeta wrote: Fri Nov 21, 2025 4:37 am Edit: Here's my own version of it. IMO it's cleaner than the LLM version (though slightly more complicated- mine handles multiplayer :P), and it's definitely more efficient.
Bonus points: My version also makes the manhole cover round :P
Much appreciated. I look forward to trying that later today.

I didn't even think it was possible to make the actor round. Presumably the underlying actor is still square but the area being checked for player presence is round?

Funny thing about multiplayer (which, at the moment, is a "nice to have" rather than an essential - given my current plans) the LLM offered to make the code multiplayer friendly (I hadn't asked about it), made several attempts (each of which G/UZDoom objected to) and eventually gave up saying that ZScript didn't have the kind of data structures that would allow them to code for a multiplayer-aware version. :roll:

(One of my biggest gripes with how LLMs present their information is how they often make bold statements, claim to be right and will not shift that position even when presented with evidence (I know it's because they are just going off scraped data and text prediction rather than actual intelligence).)

I guess they're not quite ready to replace people just yet. :lol:

Return to “Scripting”