Checking player class with ACS

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
Pandut
Posts: 231
Joined: Tue Mar 23, 2010 4:47 pm
Preferred Pronouns: No Preference
Graphics Processor: nVidia with Vulkan support
Location: existential dread

Checking player class with ACS

Post by Pandut »

Hiyo. So I'm a big dumbo when it comes down to ACS. I'm using a bit of code that Graf Zahl made in someone else's thread as an example of regenerating ammo. It's worked fine for me but I'm now having annoying issues where I want to change the regeneration rate depending on the current player class. Here are the scripts;
Spoiler:
The issue is that the code ignores all conditions and gives all classes *both* regeneration rates. So basically 2 every 14 ticks. There's 6 classes in my mod, 2 are designed specifically for the regenerating ammo and the other 4 are not.

What I've tried;
-Trying to combine the scripts using else if to separate the conditions/executions between the classes. No difference.
-Using CheckClass, no difference. Granted I think all CheckClass does is go "yep this class exists".

Clearly I'm doing something wrong but I can't make heads or tails of it.
User avatar
Player701
 
 
Posts: 1707
Joined: Wed May 13, 2009 3:15 am
Graphics Processor: nVidia with Vulkan support
Contact:

Re: Checking player class with ACS

Post by Player701 »

Pandut wrote: Thu Oct 27, 2022 10:21 pm

Code: Select all

if (PlayerClass(4))
{
}
This checks for a specific player class and then does nothing because {} on its own is an empty statement.

You need to either move the CheckInventory part inside the curly braces:

Code: Select all

if (PlayerClass(4))
{
    if (CheckInventory("ManaPool") < 200)
    {
        GiveInventory("ManaPool", 1);
    }
}
or use the && operator to combine the checks:

Code: Select all

if (PlayerClass(4) && CheckInventory("ManaPool") < 200)
{
    GiveInventory("ManaPool", 1);
}
The two code snippets above are almost equivalent: they will function exactly the same, but in the latter case, CheckInventory will be called regardless of the return value of PlayerClass because ACS does not have short-circuit evaluation.

Note that if you have only a single statement (e.g. function call) inside the {}'s, then you do not need them. E.g. this will work fine too:

Code: Select all

if (PlayerClass(4) && CheckInventory("ManaPool") < 200)
    GiveInventory("ManaPool", 1);
(I much prefer to use {}'s everywhere for consistency, though.)

You can use such constructs in both of your scripts, with different player classes/inventory amounts etc.
User avatar
Pandut
Posts: 231
Joined: Tue Mar 23, 2010 4:47 pm
Preferred Pronouns: No Preference
Graphics Processor: nVidia with Vulkan support
Location: existential dread

Re: Checking player class with ACS

Post by Pandut »

Thanks for the simple explanation, ACS and my brain aren't a good combo so I appreciate it being put into terms I can understand aha. I've applied the && formula to my code, but it's still rejecting the conditions and just giving all the classes the combined regeneration of each instance of GiveInventory. It gives 6 ammo every 6-8 ticks until 100, then 2 every 6 ticks until 200 regardless of class.

Code: Select all

#include "zcommon.acs"
script 1 ENTER 
{
if (PlayerClass(0) && CheckInventory("ManaPool") < 100)
{
    GiveInventory("ManaPool", 1);
}
if (PlayerClass(1) && CheckInventory("ManaPool") < 100)
{
    GiveInventory("ManaPool", 1);
}
if (PlayerClass(2) && CheckInventory("ManaPool") < 100)
{
    GiveInventory("ManaPool", 1);
}
if (PlayerClass(3) && CheckInventory("ManaPool") < 100)
{
    GiveInventory("ManaPool", 1);
}
	    delay (8);
	restart;
}

script 2 ENTER 
{
if (PlayerClass(4) && CheckInventory("ManaPool") < 200)
{
    GiveInventory("ManaPool", 1);
}
if (PlayerClass(5) && CheckInventory("ManaPool") < 200)
{
    GiveInventory("ManaPool", 1);
}
	    delay (6);
	restart;
}
Jarewill2

Re: Checking player class with ACS

Post by Jarewill2 »

PlayerClass's (https://zdoom.org/wiki/PlayerClass) argument takes the player number and returns the class of the specified player.
To make checks using PlayerClass, you should modify your code like this:

if (PlayerClass(PlayerNumber()) == <number> && CheckInventory("ManaPool") < 100)

Replacing <number> with the class number to check for.
PlayerNumber() will return the number of the current player the script works for.
User avatar
Player701
 
 
Posts: 1707
Joined: Wed May 13, 2009 3:15 am
Graphics Processor: nVidia with Vulkan support
Contact:

Re: Checking player class with ACS

Post by Player701 »

It seems you're using PlayerClass incorrectly. From the wiki article it's obvious that it's supposed to return the player class number as a result, not accept one as an argument. The argument is a player number, not a class number.

So you need to change all instances of PlayerClass(N) to PlayerClass(PlayerNumber()) == N, e.g.

Code: Select all

if (PlayerClass(PlayerNumber()) == 4 && CheckInventory("ManaPool") < 200)
{
    GiveInventory("ManaPool", 1);
}
The code can also be simplified by storing the result in a variable and using range checks and the || operator:

Code: Select all

int pc = PlayerClass(PlayerNumber());

if (pc >= 0 && pc <= 3 && CheckInventory("ManaPool") < 100)
{
    GiveInventory("ManaPool", 1);
}
The above code checks if the player class number is in range 0-3 (inclusive). For your second script, check for 4 or 5:

Code: Select all

int pc = PlayerClass(PlayerNumber());

if ((pc == 4 || pc == 5) && CheckInventory("ManaPool") < 200)
{
    GiveInventory("ManaPool", 1);
}
Note that you need ()'s around the first part (before the &&) due to operator precedence, otherwise, && will be evaluated first.
User avatar
Pandut
Posts: 231
Joined: Tue Mar 23, 2010 4:47 pm
Preferred Pronouns: No Preference
Graphics Processor: nVidia with Vulkan support
Location: existential dread

Re: Checking player class with ACS

Post by Pandut »

Ah, yeah that did it! Thanks a ton. Yeah looking back at the wiki entry, I completely missed the "returns the number of the player class" ... despite it being the first sentence. Oof. If you'd be willing to humor me a bit more, can I apply this class check logic to change max ammo (IE Inventory.MaxAmount and Backpack.MaxAmount) for each class? I messed around with it for a bit but again I'm clearly missing something obvious as it's not working;

Code: Select all

script 1 ENTER
{
int pc = PlayerClass(PlayerNumber());

if ((pc == 0 || pc == 1) && CheckInventory("Backpack") < 1)
{
    SetAmmoCapacity("PistolAmmo", 20);
	SetAmmoCapacity("RifleAmmo", 45);
	SetAmmoCapacity("ShotgunAmmo", 30);
	SetAmmoCapacity("BowAmmo", 30);
	SetAmmoCapacity("ManaPool", 100);
	SetAmmoCapacity("IronBombAmmo", 8);
}
}

script 2 ENTER
{
int pc = PlayerClass(PlayerNumber());

if ((pc == 0 || pc == 1) && CheckInventory("Backpack") > 0)
{
    SetAmmoCapacity("PistolAmmo", GetAmmoCapacity("PistolAmmo") + 20);
	SetAmmoCapacity("RifleAmmo", GetAmmoCapacity("RifleAmmo") + 45);
	SetAmmoCapacity("ShotgunAmmo", GetAmmoCapacity("ShotgunAmmo") + 30);
	SetAmmoCapacity("BowAmmo", GetAmmoCapacity("BowAmmo") + 30);
	SetAmmoCapacity("ManaPool", GetAmmoCapacity("ManaPool") + 100);
	SetAmmoCapacity("IronBombAmmo", GetAmmoCapacity("IronBombAmmo") + 8);
}
}
I'm assuming I'm missing something like an activation cue of some sort?
Jarewill
 
 
Posts: 1853
Joined: Sun Jul 21, 2019 8:54 am

Re: Checking player class with ACS

Post by Jarewill »

What exactly is the problem you are experiencing?

Trying your code in game does change the ammo capacity at the start of the map, but doesn't do it after picking up a backpack, resetting to the default amounts.
That's caused by the lack of looping in your script. (The delay and restart used in your previous ones)

There's also the issue that using GetAmmoCapacity will result in the ammo count getting increased by that amount each time the script is called.
To fix that you should change SetAmmoCapacity("PistolAmmo", GetAmmoCapacity("PistolAmmo") + 20);
Into just SetAmmoCapacity("PistolAmmo", 40);
User avatar
Pandut
Posts: 231
Joined: Tue Mar 23, 2010 4:47 pm
Preferred Pronouns: No Preference
Graphics Processor: nVidia with Vulkan support
Location: existential dread

Re: Checking player class with ACS

Post by Pandut »

The issue on my end is that both scripts are ignored and uses the default DECORATE capacities, even if they're all set to 0. I added the looping to post-backpack script and it still gets ignored. Since I forget frequently, double checked to make sure this code was included in LOADACS and it is.
User avatar
Player701
 
 
Posts: 1707
Joined: Wed May 13, 2009 3:15 am
Graphics Processor: nVidia with Vulkan support
Contact:

Re: Checking player class with ACS

Post by Player701 »

Please show us the updated version of your code.
User avatar
Pandut
Posts: 231
Joined: Tue Mar 23, 2010 4:47 pm
Preferred Pronouns: No Preference
Graphics Processor: nVidia with Vulkan support
Location: existential dread

Re: Checking player class with ACS

Post by Pandut »

Code: Select all

script 4 ENTER
{
int pc = PlayerClass(PlayerNumber());

if ((pc == 0 || pc == 1) && CheckInventory("Backpack") < 1)
{
    SetAmmoCapacity("PistolAmmo", 20);
	SetAmmoCapacity("RifleAmmo", 45);
	SetAmmoCapacity("ShotgunAmmo", 30);
	SetAmmoCapacity("BowAmmo", 30);
	SetAmmoCapacity("IronBombAmmo", 8);
}
}

script 5 ENTER
{
int pc = PlayerClass(PlayerNumber());

if ((pc == 0 || pc == 1) && CheckInventory("Backpack") > 0)
{
    SetAmmoCapacity("PistolAmmo", 40);
	SetAmmoCapacity("RifleAmmo", 90);
	SetAmmoCapacity("ShotgunAmmo", 60);
	SetAmmoCapacity("BowAmmo", 60);
	SetAmmoCapacity("IronBombAmmo", 16);
}
	    delay (10);
	restart;
}
Jarewill
 
 
Posts: 1853
Joined: Sun Jul 21, 2019 8:54 am

Re: Checking player class with ACS

Post by Jarewill »

I copied both scripts, compiled them and they also run fine for me.
Please upload your project here so we can look into other factors that can affect it.
Post Reply

Return to “Scripting”