Enemy that only doesn't block the player - how?

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!)
Post Reply
User avatar
Enjay
 
 
Posts: 26534
Joined: Tue Jul 15, 2003 4:58 pm
Location: Scotland
Contact:

Enemy that only doesn't block the player - how?

Post by Enjay »

I'm sure there will be an easy answer to this and I'm sure it's been asked before but I can find it.

What's the best way to make an enemy that has normal blocking behaviour as far as everything in the game is concerned, but with one exception: players can walk right through as if it did not have the SOLID flag?

I'd prefer if the answer was for DECORATE because I'm using it on an existing actor, though if the only possibility is ZScript, I could convert it.

Thanks. :)
User avatar
Nash
 
 
Posts: 17439
Joined: Mon Oct 27, 2003 12:07 am
Location: Kuala Lumpur, Malaysia
Contact:

Re: Enemy that only doesn't block the player - how?

Post by Nash »

Only possible with ZScript.

Code: Select all

class LOLZombieMan : ZombieMan replaces ZombieMan
{
    override bool CanCollideWith(Actor other, bool passive)
    {
        if (passive && other && other is "PlayerPawn")
        {
            return false;
        }
        
        return true;
    }
}
User avatar
Void Weaver
Posts: 724
Joined: Thu Dec 18, 2014 7:15 am
Contact:

Re: Enemy that only doesn't block the player - how?

Post by Void Weaver »

What about using the same species as Player +THRUSPECIES flag?
User avatar
Enjay
 
 
Posts: 26534
Joined: Tue Jul 15, 2003 4:58 pm
Location: Scotland
Contact:

Re: Enemy that only doesn't block the player - how?

Post by Enjay »

Nash's code worked for me and the actor is now converted to ZScript too.

Thanks. :D
User avatar
Enjay
 
 
Posts: 26534
Joined: Tue Jul 15, 2003 4:58 pm
Location: Scotland
Contact:

Re: Enemy that only doesn't block the player - how?

Post by Enjay »

Just a thought, seeing as how this has now moved across to ZScript, would it be possible to write a custom code pointer for this actor that checks of a player is inside/touching it and, if the answer is no, then sets itself to be impassable to players too?

For a bit of context, the actor is a sentry gun (adapted from the ones in Stronghold) that is placed by the player via an inventory item. I was having all sorts of problems with the player getting stuck inside the spawned weapons, or the spawns failing or whatever. Making them non-solid to players solved all that because I can now spawn them exactly where the player is standing: if there is room for the player, there is room for the gun.

The icing on the cake would be if the gun could check to see if the player was still within its radius and if not, it could become solid to players too. The thing is, I have no idea how to do that, but it strikes me as something that might be possible.
User avatar
Matt
Posts: 9696
Joined: Sun Jan 04, 2004 5:37 pm
Preferred Pronouns: They/Them
Operating System Version (Optional): Debian Bullseye
Location: Gotham City SAR, Wyld-Lands of the Lotus People, Dominionist PetroConfederacy of Saudi Canadia
Contact:

Re: Enemy that only doesn't block the player - how?

Post by Matt »

I too would like to know if there's a simple built-in way to see if two arbitrarily selected actors' hitboxes are intersecting each other. If there is, then the sentry could just check that against its owner (or any colliding player) every so often and set a flag/give a CanCollideWith result accordingly.

I can imagine using if(min(abs(pos.x-other.pos.x),abs(pos.y-other.pos.y))>radius+other.radius) but I have this feeling that there's something better in native code somewhere.
User avatar
AFADoomer
Posts: 1325
Joined: Tue Jul 15, 2003 4:18 pm
Contact:

Re: Enemy that only doesn't block the player - how?

Post by AFADoomer »

Maybe spawn the turret with the -SOLID flag, and add something like this in the Tick function?

Code: Select all

if (!bSolid) { bSolid =  TestMobjLocation(); }
It's not technically as precise a check as what you're asking for - it checks for map geometry also - and I have no idea how intensive that check is, or if this will actually work in practice... I've done something similar to spawn effect-only actors with bNoInteraction, then unsetting that flag once the actor is clear of any other actor so that collision is restored with other actors or map geometry.
User avatar
Graf Zahl
Lead GZDoom+Raze Developer
Lead GZDoom+Raze Developer
Posts: 49067
Joined: Sat Jul 19, 2003 10:19 am
Location: Germany

Re: Enemy that only doesn't block the player - how?

Post by Graf Zahl »

Matt wrote: I can imagine using if(min(abs(pos.x-other.pos.x),abs(pos.y-other.pos.y))>radius+other.radius) but I have this feeling that there's something better in native code somewhere.
That won't work with portals anyway. You have to calculate the distance vector with the provided functions.
User avatar
Matt
Posts: 9696
Joined: Sun Jan 04, 2004 5:37 pm
Preferred Pronouns: They/Them
Operating System Version (Optional): Debian Bullseye
Location: Gotham City SAR, Wyld-Lands of the Lotus People, Dominionist PetroConfederacy of Saudi Canadia
Contact:

Re: Enemy that only doesn't block the player - how?

Post by Matt »

So no shortcut option involving a blockmap check then? (assuming that would be computationally less expensive than multiple portal-sensitive distance and square roots every tick)
User avatar
Enjay
 
 
Posts: 26534
Joined: Tue Jul 15, 2003 4:58 pm
Location: Scotland
Contact:

Re: Enemy that only doesn't block the player - how?

Post by Enjay »

AFADoomer wrote:Maybe spawn the turret with the -SOLID flag, and add something like this in the Tick function?

Code: Select all

if (!bSolid) { bSolid =  TestMobjLocation(); }
I tried to get that working (tried a few different ways) but I'm a complete ZScript n00b so I never managed to even get something that would run. :?

Have you got an example actor where you use this that I could look at?
User avatar
AFADoomer
Posts: 1325
Joined: Tue Jul 15, 2003 4:18 pm
Contact:

Re: Enemy that only doesn't block the player - how?

Post by AFADoomer »

Here's a quick and dirty example... I couldn't get it to work with SOLID, but changing the NOBLOCKMAP flag does what you want, I think...

Give yourself the "Dropper" item, then use the inventory item to spawn a "Dropped" tech lamp right in front of you that is effectively non-solid until you move away.

Code: Select all

version "4.2"

class Dropper : Inventory
{
	Default
	{
		+INVENTORY.INVBAR
	}

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

	override bool Use(bool pickup)
	{
		if (owner) { Spawn("Dropped", owner.pos + RotateVector((8, 0), owner.angle)); }

		return Super.Use(pickup);
	}
}

class Dropped : TechLamp2
{
	Default
	{
		+NOBLOCKMAP // Start out with other actors ignoring you for collision purposes
	}

	override void Tick()
	{
		if (bNoBlockMap && TestMobjLocation()) { A_ChangeLinkFlags(0); } // If the NOBLOCKMAP flag is set, but the actor's position is now valid, unset the flag.

		Super.Tick();
	}
}
User avatar
Enjay
 
 
Posts: 26534
Joined: Tue Jul 15, 2003 4:58 pm
Location: Scotland
Contact:

Re: Enemy that only doesn't block the player - how?

Post by Enjay »

OK, I think I can follow that. I can't check it right now, but I'll take a proper look tomorrow. Thank you.
User avatar
AFADoomer
Posts: 1325
Joined: Tue Jul 15, 2003 4:18 pm
Contact:

Re: Enemy that only doesn't block the player - how?

Post by AFADoomer »

Better solution, based on Nash's initial response:

Code: Select all

class Dropped : TechLamp2
{
	override bool CanCollideWith(Actor other, bool passive)
	{
		if (passive && other && other is "PlayerPawn" && !TestMobjLocation())
		{
			return false;
		}
		
		return true;
	}
}
This has the same apparent effect on the player (lamp spawns inside player radius but doesn't interfere with movement until you move outside of the lamp's radius), but this also lets projectiles still hit the lamp after you spawn it, even while the player is still overlapping with it... So you can drop this and hide from, say, imp projectiles behind it.
User avatar
Enjay
 
 
Posts: 26534
Joined: Tue Jul 15, 2003 4:58 pm
Location: Scotland
Contact:

Re: Enemy that only doesn't block the player - how?

Post by Enjay »

I was just about to check the earlier version when I saw your post. It works perfectly. It does what I originally wanted (which is what Nash's code did, of course) and extends it to cover my secondary goal too so that the dropped item makes more sense in the world (i.e. as soon as you move away, it behaves just like any other solid obstacle).

Thank you. :D
Post Reply

Return to “Scripting”