3D Actor-use and Inventory-get

Post your example zscripts/ACS scripts/etc here.
Forum rules
The Projects forums are only for projects. If you are asking questions about a project, either find that project's thread, or start a thread in the General section instead.

Got a cool project idea but nothing else? Put it in the project ideas thread instead!

Projects for any Doom-based engine (especially 3DGE) are perfectly acceptable here too.

Please read the full rules for more details.
User avatar
Sir Robin
Posts: 537
Joined: Wed Dec 22, 2021 7:02 pm
Graphics Processor: Intel (Modern GZDoom)
Location: Medellin, Colombia

3D Actor-use and Inventory-get

Post by Sir Robin »

If you want to use a usable actor (for example, a switched decoration) there is no Z check on it. You can use it way up on a ledge or way down in a pit. So I wanted to constrain that to an overlapping Z range:
(note: any line of code that ends with //DEBUG is for test/demo only and can be removed or replaced with your own code)

Code: Select all

class UsableZ : actor //usable with a z check
{
	default {height 14;radius 9;}//DEBUG
	states {spawn: BON1 ABCDCB 5; loop;}//DEBUG
	
	override bool used(actor user)
	{
		if (!user) return false;
		
		//TODO: Could check Level.CheckSwitchRange to turn this on and off
		if (user.pos.z > pos.z+height) return false;
		if (user.pos.z+user.height < pos.z) return false;
		return usedz(user);
	}
	
	//override this to put your actual usage code in
	virtual bool usedz(actor user)
	{
		console.printf(level.time..": "..GetCharacterName()..": usedz by "..(user?user.GetCharacterName():"Something"));//DEBUG
		return false;
	}
}
I'm also wanting use-to-get inventory items, and they need that z check too:

Code: Select all

class UseMeToGetMe : Inventory //Inventory that must be used to be picked up
{
	default {+inventory.invbar;}//DEBUG
	states {spawn: BON1 ABCDCB 5; loop;}//DEBUG
	
	override void touch(actor toucher){}//disable touch-to-get

	override bool used(actor user)
	{
		console.printf(level.time..": "..GetCharacterName()..": Used");//DEBUG
		super.touch(user);
		return true;
	}
}

class UseMeToGetMeZ : UseMeToGetMe //use-to-get with a z check
{
	override bool used(actor user){
		if (!user) return false;
		
		//TODO: Could check Level.CheckSwitchRange to turn this on and off
		if (user.pos.z > pos.z+height) return false;
		if (user.pos.z+user.height < pos.z) return false;
		return super.used(user);
	}
}
That's all well and good, but what if I want an actor that can only be used if the player is looking directly at it? How is that useful? Imagine you want an elevator, and it has an up button and a down button. You can create each button as an actor and place one above the other. The standard GZDoom use tracer won't differentiate between them, it'll just pick the first one it encounters in 2d. So you want an actor to only accept being used if the player is looking directly at it.
Here's a quick line-seg-to-3d-hitbox collision library:
Spoiler:
And then it's pretty easy:

Code: Select all

class Usable3d : actor
{
	default{height 14;radius 9;}//DEBUG
	states{spawn:BON2 ABCDCB 5;loop;}//DEBUG
	
	override bool used(actor user)
	{
		if (!user || !user.player) return false;
		
		//TODO: Could check Level.CheckSwitchRange to turn this on and off
		if (SegHitBox.CheckIfPlayerIsUsingAtHitbox(user, self)) return used3d(user);
		
		return false;
	}
	
	//override this to put your actual usage code in
	virtual bool used3d(actor user)
	{
		console.printf(level.time..": "..GetCharacterName()..": used3d by "..(user?user.GetCharacterName():"[NULL]"));//DEBUG
		return true;
	}

}

class UseMeToGetMe3d : UseMeToGetMe
{
	override bool used(actor user){
		if (!user) return false;
		
		//TODO: Could check Level.CheckSwitchRange to turn this on and off
		if (SegHitBox.CheckIfPlayerIsUsingAtHitbox(user, self)) return super.used(user);
		
		return false;
	}
}
Use Radius Debugger to check it for yourself
User avatar
Sir Robin
Posts: 537
Joined: Wed Dec 22, 2021 7:02 pm
Graphics Processor: Intel (Modern GZDoom)
Location: Medellin, Colombia

Re: 3D Actor-use and Inventory-get

Post by Sir Robin »

Ok, so this technically works. All my math and logic check out. The issue is that I'm still at the mercy of the engine to decide the order of hit checks.

So all my code works beautifully if you're using one object at a time. If there are two or more, and for example object2 is behind object1, there are some cases where the engine will check object2 before checking object1, sees a successful hit, then never checks object1.

I'll have to rethink my logic on how to work around this. But it works right like 95% of the time.

Return to “Script Library”