[ZScript]While loop error[SOLVED]

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!)
User avatar
Laskow
Posts: 66
Joined: Tue Feb 16, 2021 7:35 am
Preferred Pronouns: He/Him

[ZScript]While loop error[SOLVED]

Post by Laskow »

Hello. Sorry for posting in a row. I've been making the Duke Nukem-like medkit in ZScript that will not need ACS.

Code: Select all

version "4.6.1"

class FirstAidKit : Inventory
{
	default
	{
		+INVENTORY.UNDROPPABLE;
		+INVENTORY.INVBAR;
		Inventory.Amount 100;
		Inventory.MaxAmount 100;
		Inventory.InterHubAmount 100;
		Inventory.PickUpMessage "Picked up First Aid Kit";
		Inventory.Icon "TNT1A0";
	}

    override bool Use (bool pickup)
    {
		bool result = Super.Use(pickup);

		int firstAidAmount;
		firstAidAmount = owner.CountInv ("FirstAidKit");

		if (!owner || !owner.player || owner.player.Health > 100 || !owner.FindInventory("FirstAidKit"))
		return false;

		if (owner.player.Health < 100 && firstAidAmount != 0)
		{
			owner.A_StartSound ("Inventory/PKUP_Potion", CHAN_ITEM); 
		}

		while (owner.player.Health < 100 && firstAidAmount != 0)
		{
			owner.GiveBody (1);
			owner.A_TakeInventory ("FirstAidKit", 1);
		}

		return result;
	}

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

}
However, when the inventory amount is 0, the game is crushed. The error message is:
VM execution aborted: tried to read from address zero.
And the line occurs this error is:

Code: Select all

while (owner.player.Health < 100 && firstAidAmount != 0)
I've tested this mod in GZdoom 4.6.1, 4.8.2 and 4.10 and always crashes by the same reason, so probably not a problem related the engine.
I like this script personally because it doesn't require long states codes and easy to read though, I have no idea how to solve this issue. Any help appreciated.
Last edited by Laskow on Mon Dec 05, 2022 11:31 am, edited 1 time in total.
Jarewill
Posts: 1422
Joined: Sun Jul 21, 2019 8:54 am

Re: [ZScript]While loop error

Post by Jarewill »

The item gets removed from inventory the moment its amount reaches 0, which means the check in the while loop will have a null pointer and cause a VM abort.
To fix this, you will need to alter your code so the loop ends once the item gets removed or use a different method instead of a while loop, for example:

Code: Select all

    override bool Use (bool pickup)
    {
		bool result = Super.Use(pickup);

		int firstAidAmount;
		firstAidAmount = owner.CountInv ("FirstAidKit");

		if (!owner || !owner.player || owner.player.Health > 100 || !owner.FindInventory("FirstAidKit"))
		return false;

		if (owner.player.Health < 100 && firstAidAmount != 0)
		{
			owner.A_StartSound ("Inventory/PKUP_Potion", CHAN_ITEM); 
			int toheal = 100 - owner.player.health; //Check how much to heal
			If(toheal > firstAidAmount){toheal = firstAidAmount;} //If that amount is larger than the amount of charge, set it to be equal
			owner.GiveBody (toheal); //Heal the player that amount
			owner.A_TakeInventory ("FirstAidKit", toheal); //Take that amount of charge
		}
		

		return result;
	}
User avatar
Laskow
Posts: 66
Joined: Tue Feb 16, 2021 7:35 am
Preferred Pronouns: He/Him

Re: [ZScript]While loop error

Post by Laskow »

Jarewill wrote: Mon Dec 05, 2022 10:14 am The item gets removed from inventory the moment its amount reaches 0, which means the check in the while loop will have a null pointer and cause a VM abort.
To fix this, you will need to alter your code so the loop ends once the item gets removed or use a different method instead of a while loop, for example:

Code: Select all

    override bool Use (bool pickup)
    {
		bool result = Super.Use(pickup);

		int firstAidAmount;
		firstAidAmount = owner.CountInv ("FirstAidKit");

		if (!owner || !owner.player || owner.player.Health > 100 || !owner.FindInventory("FirstAidKit"))
		return false;

		if (owner.player.Health < 100 && firstAidAmount != 0)
		{
			owner.A_StartSound ("Inventory/PKUP_Potion", CHAN_ITEM); 
			int toheal = 100 - owner.player.health; //Check how much to heal
			If(toheal > firstAidAmount){toheal = firstAidAmount;} //If that amount is larger than the amount of charge, set it to be equal
			owner.GiveBody (toheal); //Heal the player that amount
			owner.A_TakeInventory ("FirstAidKit", toheal); //Take that amount of charge
		}
		

		return result;
	}
I couldn't come up with this method... I made this item almost a year ago and IDK why I hadn't noticed this error though, finally it works without any errors!
Thanks a lot.

Return to “Scripting”