"How do I ZScript?"

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
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

Re: "How do I ZScript?"

Post by Matt »

I've got the following:

Code: Select all

if(
	!countinv("Infrared")&&
	!countinv("PowerInvulnerable")&&
	(!countinv("PowerLightAmpP")||player.readyweapon.getclass()=="HDPistol")&&
	!(getplayerinput(MODINPUT_BUTTONS)&&BT_RELOAD)&&
	!(getplayerinput(MODINPUT_BUTTONS)&&BT_ZOOM)&&
	!(getplayerinput(MODINPUT_BUTTONS)&&BT_USER1)&&
	!(getplayerinput(MODINPUT_BUTTONS)&&BT_USER2)&&
	!(getplayerinput(MODINPUT_BUTTONS)&&BT_USER3)&&
	!(getplayerinput(MODINPUT_BUTTONS)&&BT_USER4)&&
	!(getplayerinput(MODINPUT_BUTTONS)&&BT_SPEED)&&
	!(getplayerinput(MODINPUT_BUTTONS)&&BT_JUMP)&&
	player.readyweapon.instatesequence(
		player.readyweapon.curstate,player.readyweapon.resolvestate("Ready"))&&
	abs(getplayerinput(MODINPUT_YAW))<4096 &&
	80<getcvar(fov)<120
)...
which gives me the following errors and I have no idea why on earth it should:

1. "Cannot access userinfo CVARs directly. Use GetCVar() instead." wrt the line where I have "getcvar(fov)" (the exact same error appears if I just use "fov" there)

2. "Unknown class name 'HDPistol' of type 'Weapon'" even though HDPistol is a valid class that inherits from Weapon (no error if I replace this with 'self.getclass()=="HDPlayerPawn"')

Are these bugs or am I missing something?
User avatar
ZZYZX
 
 
Posts: 1384
Joined: Sun Oct 14, 2012 1:43 am
Location: Ukraine

Re: "How do I ZScript?"

Post by ZZYZX »

'fov', not fov.
Also, player's current FOV is stored in the player struct.
Also, use GetClassName.
Also, ReadyWeapon can be null.

Also, why not if(HDPistol(player.readyweapon))? Would also help against null.
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

Re: "How do I ZScript?"

Post by Matt »

Thanks, this seems to be a collection of a large number of the things I never remember the syntax for. (also it turns out the logic on this was backwards)

The class name apparently doesn't work because HDPistol is only defined in the DECORATE...
User avatar
DenisBelmondo
Posts: 381
Joined: Fri Jun 06, 2008 6:26 pm
Location: Two-Key Return

Re: "How do I ZScript?"

Post by DenisBelmondo »

Vaecrius wrote:Not that I know an eventhandler from a hole in the ground at this point, but would something like

Code: Select all

if(thing.instatesequence(thing.curstate,thing.resolvestate("xdeath")))
work?
Thanks for the tip! It definitely worked, sort of. I wrapped it in the WorldThingDamaged event instead of WorldThingDied since it doesn't want to cooperate with the former and in this particular application of resolvestate, that is, detecting whether or not the actor is in its xdeath state executes the block on an actor that has a death state but no xdeath state. I'd also rather not use a thinkeriterator or some other method of explicitly stating every actor defined in the engine that has an xdeath state to work around this odd behavior. Here's the code (with ugly if statement):

Code: Select all

class GibsHandler : EventHandler
{
	override void WorldThingDamaged(WorldEvent e) // WorldThingDamaged works but not WorldThingDied
	{
		if ( e.thing.bIsMonster && !e.thing.bNoBlood && e.thing.InStateSequence(e.thing.CurState, e.thing.ResolveState("XDeath")) ) {
			e.thing.A_SpawnItemEx("GibsHack");
		}
	}
}
With this code, actors like demons and cacodemons spawn the "GibsHack" actor which, as you probably could imagine, looks really bizarre.
User avatar
ZZYZX
 
 
Posts: 1384
Joined: Sun Oct 14, 2012 1:43 am
Location: Ukraine

Re: "How do I ZScript?"

Post by ZZYZX »

You can check if monster's health is under XDeath threshold. There's some DECORATE property for it I believe.
User avatar
DenisBelmondo
Posts: 381
Joined: Fri Jun 06, 2008 6:26 pm
Location: Two-Key Return

Re: "How do I ZScript?"

Post by DenisBelmondo »

Yeah, that's what I was thinking too but I think I ruled out the idea since it can be globally altered by mapinfo/gameinfo and I don't know if I have a way of accessing that data just yet with ZScript, or if that gibhealth value is applied to every actor in the game which I can then access if I had the ability to grab the value of a property.
User avatar
Major Cooke
Posts: 8215
Joined: Sun Jan 28, 2007 3:55 pm
Preferred Pronouns: He/Him
Operating System Version (Optional): Windows 10
Graphics Processor: nVidia with Vulkan support
Location: GZBoomer Town

Re: "How do I ZScript?"

Post by Major Cooke »

Vaecrius, suggestion.

Code: Select all

   !(getplayerinput(MODINPUT_BUTTONS)&&BT_RELOAD)&&
   !(getplayerinput(MODINPUT_BUTTONS)&&BT_ZOOM)&&
   !(getplayerinput(MODINPUT_BUTTONS)&&BT_USER1)&&
   !(getplayerinput(MODINPUT_BUTTONS)&&BT_USER2)&&
   !(getplayerinput(MODINPUT_BUTTONS)&&BT_USER3)&&
   !(getplayerinput(MODINPUT_BUTTONS)&&BT_USER4)&&
   !(getplayerinput(MODINPUT_BUTTONS)&&BT_SPEED)&&
   !(getplayerinput(MODINPUT_BUTTONS)&&BT_JUMP)&&
You can avoid calling the function over and over by doing this, I believe.

Code: Select all

int getInput = GetPlayerInput(MODINPUT_BUTTONS)

if (!(getInput & (BT_RELOAD|BT_ZOOM|BT_USER1|BT_USER2|BT_USER3|BT_USER4|BT_SPEED|BT_JUMP))
{
     //...
}
To explain, that in short says 'if none of the following is found', or so I think. Haven't tested it but it should work, as the inverse says 'if any of the following'.
DenisBelmondo wrote:Yeah, that's what I was thinking too but I think I ruled out the idea since it can be globally altered by mapinfo/gameinfo and I don't know if I have a way of accessing that data just yet with ZScript, or if that gibhealth value is applied to every actor in the game which I can then access if I had the ability to grab the value of a property.
There's also DamageTypeReceived on actors.
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

Re: "How do I ZScript?"

Post by Matt »

It works, thanks!

Is there any particular reason to use that local int instead of just calling getplayerinput there?
(I ask because this is part of a much larger function that checks the same input elsewhere - if defining a local variable is more efficient than calling it several times I should do that for everything in this function.)
User avatar
Gutawer
Posts: 469
Joined: Sat Apr 16, 2016 6:01 am
Preferred Pronouns: She/Her

Re: "How do I ZScript?"

Post by Gutawer »

I'm not too sure about the efficiency, but I think the variable system is better just because it's a bit cleaner to look at when you have multiple input checks.
User avatar
Major Cooke
Posts: 8215
Joined: Sun Jan 28, 2007 3:55 pm
Preferred Pronouns: He/Him
Operating System Version (Optional): Windows 10
Graphics Processor: nVidia with Vulkan support
Location: GZBoomer Town

Re: "How do I ZScript?"

Post by Major Cooke »

8 versus 1 GetPlayerInput calls. Think about it~.

It's better to practice efficiency. Otherwise, one may wind up making the same mistake thinking things like sqrt aren't a drag in Java, when going from ZScript (an example, mind you) and throwing that into the mix instead of donning it onto one local var. :P

Sure, Graf optimized sqrt (again, just using this as an example) and you may be able to get away with doing:

Code: Select all

if (sqrt(vel.length()) > 10 && sqrt(vel.length()) < 20)
But it's still a drag on performance regardless. Why be wasteful when you can be efficient?

Code: Select all

Vector2 velsqr = sqrt(vel.length());
if (velsqr > 10 && velsqr < 20)
This is especially important considering if, for another example, you have to use subfunctions.
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

Re: "How do I ZScript?"

Post by Matt »

The question is more: why would getplayerinput be noticeably more expensive than reading a variable, when the engine is presumably getting and keeping the input information in memory anyway? I've been assuming getplayerinput would not actually re-poll the actual input each time it's called, given how well optimized everything else in GZDoom is.

I'll make a note to myself to try this on that old benchmark thing.
User avatar
Major Cooke
Posts: 8215
Joined: Sun Jan 28, 2007 3:55 pm
Preferred Pronouns: He/Him
Operating System Version (Optional): Windows 10
Graphics Processor: nVidia with Vulkan support
Location: GZBoomer Town

Re: "How do I ZScript?"

Post by Major Cooke »

It's hard to leave it at just one function when the same could be said for the rest of them. My main point is redundancy reduction, and getplayerinput might not be a worthy choice -- hence I chose sqrt instead.
User avatar
Nash
 
 
Posts: 17505
Joined: Mon Oct 27, 2003 12:07 am
Location: Kuala Lumpur, Malaysia

Re: "How do I ZScript?"

Post by Nash »

This also works. :D

Code: Select all

int getInput = GetPlayerInput(MODINPUT_BUTTONS);

// check that the player isn't pressing anything
bool bNoInput = (!(getInput & (BT_RELOAD |BT_ZOOM| BT_USER1| BT_USER2| BT_USER3 | BT_USER4 | BT_SPEED | BT_JUMP));

if (bNoInput)
{
    // do stuff
}
The whole point is to write cleaner code. You can reuse that bNoInput elsewhere and it would look very clean.
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

Re: "How do I ZScript?"

Post by Matt »

Code: Select all

class Cru:Actor{
	double blah1;
	states{
	spawn:
		BAL1 A 1 nodelay{
			for(int i=0;i<1000000;i++){
				blah1=getplayerinput(MODINPUT_BUTTONS)+random(-1,1);
			}
// 7290 ms
		}wait;
	}
}
class Fin:Actor{
	double blah1;
	states{
	spawn:
		BAL1 A 1 nodelay{
			int blah0=getplayerinput(MODINPUT_BUTTONS);
			for(int i=0;i<1000000;i++){
				blah1=blah0+random(-1,1);
			}
// 4044 ms
		}wait;
	}
}
Apparently it is a lot faster!
User avatar
ZZYZX
 
 
Posts: 1384
Joined: Sun Oct 14, 2012 1:43 am
Location: Ukraine

Re: "How do I ZScript?"

Post by ZZYZX »

frandom.
Also, local variables in ZScript translate to local variables in the VM. Obviously they're faster than issuing method calls.

Return to “Scripting”