[ZScript]Control oxygen left with ZScript?

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
Silentdarkness12
Posts: 1555
Joined: Thu Aug 15, 2013 5:34 pm
Location: Plains of Pride

[ZScript]Control oxygen left with ZScript?

Post by Silentdarkness12 »

So i've been fiddling around a bit and ZScript, and trying to make a ZScript version of the air canister, for use in Hideous Destructor, instead of having to use an ACS script for it, but I seem to be having an extreme level of difficulty pulling it off. Is it actually possible to do so, or am I just trying for the impossible? I've been trying my hardest to set up a cast to access the right variable, but it doesn't seem to ever work, just throwing what's presumably some null pointer 'Read from Address Zero' error.

Code: Select all

Class PortableAirCan : HDPickup
{
default
{
//$Category "Items/Hideous Destructor/Supplies"
//$Title "Air Canister"
//$Sprite "OXYCA0"
Inventory.MaxAmount 8;
Inventory.Amount 1;
Inventory.PickupMessage "Acquired a Portable Air Canister.";
Inventory.Icon "OXYCA0";
hdpickup.bulk 15;
}
States
{
Spawn:
	OXYC A -1;
	use:
		TNT1 A 0{
		A_GiveInventory("HDOxygener");
		A_SelectWeapon("HDOxygener");
		}
		fail;
	}
}

Class HDOxygener : HDWoundFixer
{
class<actor> injecttype;
class<actor> spentinjecttype;
class<inventory> inventorytype;
string noerror;
property injecttype:injecttype;
property spentinjecttype:spentinjecttype;
property inventorytype:inventorytype;
property noerror:noerror;
default{
		hdoxygener.injecttype "InjectOxyDummy";
		//hdoxygener.spentinjecttype "SpentAirCan";
		hdoxygener.inventorytype "PortableAirCan";
		hdoxygener.noerror "No Air Cans.";
		weapon.selectionorder 1003;
	}
States
{
Spawn:
TNT1 A 1;
Stop;
select:
		TNT1 A 0{
			if(!countinv(invoker.inventorytype)){
				if(getcvar("hd_helptext"))A_WeaponMessage(invoker.noerror);
				A_SelectWeapon("Ring");
			}else if(getcvar("hd_helptext"))A_WeaponMessage("\cd<<< \cjAIR CANISTER \cd>>>\c-\n\n\nAir Canisters restore the o2 tanks \n for extended time in airless \n environments. \n\n\Press altfire to use on someone else.");
		}
		goto super::select;
		deselecthold:
		TNT1 A 1;
		TNT1 A 0 A_Refire("deselecthold");
		TNT1 A 0{
			A_SelectWeapon("Ring");
			A_WeaponReady(WRF_NOFIRE);
		}goto nope;
	fire:
	hold:
		TNT1 A 1;
		TNT1 A 0{
			if(!countinv(invoker.inventorytype)){
				if(getcvar("hd_helptext"))A_WeaponMessage(invoker.noerror);
				A_Refire("deselecthold");
}
				if(pitch<55){
					A_MuzzleClimb(0,8);
					A_Refire();
			}else{
				A_Refire("inject");
			}
		}
	goto nope;
	inject:
		TNT1 A 1{
			A_TakeInventory(invoker.inventorytype,1);
			A_SetBlend("7a 3a 18",0.1,4);
			A_MuzzleClimb(0,2);
			A_PlaySound("Oxygen/Refill",CHAN_VOICE);
			actor a=spawn(invoker.injecttype,pos);
}
TNT1 AAAA 1 A_MuzzleClimb(0,-0.5);
		TNT1 A 6;
		TNT1 A 0{
			actor a=spawn(invoker.spentinjecttype,pos+(0,0,height-8));
			a.angle=angle;a.vel=vel;a.A_ChangeVelocity(3,1,2,CVF_RELATIVE);
			a.A_PlaySound("weapons/grenopen",CHAN_VOICE);
		}
		goto nope;
	altfire:
		TNT1 A 10;
		TNT1 A 0 A_Refire();
		goto nope;
	althold:
		TNT1 A 0{
			if(!countinv(invoker.inventorytype)){
				if(getcvar("hd_helptext"))A_WeaponMessage(invoker.noerror);
				A_Refire("deselecthold");
			}
		}
		TNT1 A 8{
			flinetracedata injectorline;
			linetrace(
				angle,42,pitch,
				offsetz:height-12,
				data:injectorline
			);
			let c=HDPlayerPawn(injectorline.hitactor);
			if(!c){
				if(getcvar("hd_helptext"))A_WeaponMessage("Nothing to be done here.",2);
				return resolvestate("nope");
			}
			else{
				//and now...
				A_TakeInventory(invoker.inventorytype,1);
				c.A_PlaySound("Oxygen/Refill",CHAN_VOICE);
				c.A_SetBlend("7a 3a 18",0.1,4);
				actor a=spawn(invoker.injecttype,c.pos);
				a.accuracy=40;a.target=c;
				if(!countinv(invoker.inventorytype))return resolvestate("deselecthold");
				return resolvestate("injected");
			}
		}
	injected:
		TNT1 A 0{
			actor a=spawn(invoker.spentinjecttype,pos+(0,0,height-8));
			a.angle=angle;a.vel=vel;a.A_ChangeVelocity(-2,1,4,CVF_RELATIVE);
			a.A_PlaySound("weapons/grenopen",CHAN_VOICE);
		}
		goto nope;
	}}

class InjectOxyDummy:IdleDummy{

int GetAirTime()
{
    if(!target || !target.player || target.waterlevel < 3)
        return level.airsupply;
    else
        return max(target.player.air_finished - level.time, 0);
}
	hdplayerpawn tg;
	states{
	spawn:
		TNT1 A 6 nodelay{
			tg=HDPlayerPawn(target);
			Target.Player.Air_Finished = Target.Player.Air_Finished;
			//Target.Player.Air_Finished = (GetAirTime() + 4200);
		}
		TNT1 A 1{
			if(target.bkilled||accuracy<1){destroy();return;}
		}wait;
	}
}
I've been trying a number of different options to try to get the cast to work, but it apparently is just going null on me immediately. Not sure what to do here.
User avatar
Xaser
 
 
Posts: 10773
Joined: Sun Jul 20, 2003 12:15 pm

Re: [ZScript]Control oxygen left with ZScript?

Post by Xaser »

Trying to learn ZScript by looking at Hideous Destructor is like trying to learn how to ride a bike by entering a BMX racing tournament.

Judging from that code example, the air canister is a pickup that gives a weapon that grants the player/an ally some oxygen when fired/altfired. That's a huge set of problems to solve, and the code has a ton of extra complexity (InjectOxyDummy, et.al) which make things even trickier.

If your goal is indeed to learn ZScript, this isn't the way to do it -- I'd suggest starting something from scratch, rather than trying to tinker with an existing project, and especially don't try and cut your teeth on ZScript by converting DECORATE+ACS code over. A lot of things that were built using the older tech do things that are often no longer necessary in ZScript (e.g. inventory item counters, state jump logic, etc.), and they'll get in the way. Trust me -- I've done that. It's hard. :P

Having said all this, I know this doesn't do anything at all to answer the question at hand, so for the sake of solving the immediate need, could you tell us what line is failing (if GZDoom is giving you one)? That would help loads, 'cause that's a pretty big web to untangle otherwise.
User avatar
Silentdarkness12
Posts: 1555
Joined: Thu Aug 15, 2013 5:34 pm
Location: Plains of Pride

Re: [ZScript]Control oxygen left with ZScript?

Post by Silentdarkness12 »

Xaser wrote:Trying to learn ZScript by looking at Hideous Destructor is like trying to learn how to ride a bike by entering a BMX racing tournament.

Judging from that code example, the air canister is a pickup that gives a weapon that grants the player/an ally some oxygen when fired/altfired. That's a huge set of problems to solve, and the code has a ton of extra complexity (InjectOxyDummy, et.al) which make things even trickier.

If your goal is indeed to learn ZScript, this isn't the way to do it -- I'd suggest starting something from scratch, rather than trying to tinker with an existing project, and especially don't try and cut your teeth on ZScript by converting DECORATE+ACS code over. A lot of things that were built using the older tech do things that are often no longer necessary in ZScript (e.g. inventory item counters, state jump logic, etc.), and they'll get in the way. Trust me -- I've done that. It's hard. :P

Having said all this, I know this doesn't do anything at all to answer the question at hand, so for the sake of solving the immediate need, could you tell us what line is failing (if GZDoom is giving you one)? That would help loads, 'cause that's a pretty big web to untangle otherwise.
Sigh. Fine. Well, suppose I wanted to ZScript it for just regular Doom? How would I go about handling that?

Also the crashing line was this

Code: Select all

 Target.Player.Air_Finished = Target.Player.Air_Finished;
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: [ZScript]Control oxygen left with ZScript?

Post by Matt »

A lot of that code you've copied from other actors does some really specific stuff that has nothing to do with what you're trying to accomplish here. If you don't need it it's a useless distraction at best, a "gift that keeps on giving" fountain of glitches and crashes at worst.

It would be a lot better to try to get this working for vanilla first, then make the necessary changes for HD compatibility (especially since right now HD doesn't do anything about air supply at all).
Well, suppose I wanted to ZScript it for just regular Doom? How would I go about handling that?
First, lay out what exactly it is you want to accomplish, then break it down into simpler things that can function fully and be tested at each step.

In this case, we want:

1. a usable item
2. that, if used, gives the player a resource
3. that prevents the player from drowning
4. but counts down over time until it is depleted

Code an item that satisfies criterion 1 first, then start working on 2, etc. until you've got everything functional on all 4 points before fine-tuning the details (interface, balance, etc.).
User avatar
Silentdarkness12
Posts: 1555
Joined: Thu Aug 15, 2013 5:34 pm
Location: Plains of Pride

Re: [ZScript]Control oxygen left with ZScript?

Post by Silentdarkness12 »

Matt wrote:A lot of that code you've copied from other actors does some really specific stuff that has nothing to do with what you're trying to accomplish here. If you don't need it it's a useless distraction at best, a "gift that keeps on giving" fountain of glitches and crashes at worst.

It would be a lot better to try to get this working for vanilla first, then make the necessary changes for HD compatibility (especially since right now HD doesn't do anything about air supply at all).
Well, suppose I wanted to ZScript it for just regular Doom? How would I go about handling that?
First, lay out what exactly it is you want to accomplish, then break it down into simpler things that can function fully and be tested at each step.

In this case, we want:

1. a usable item
2. that, if used, gives the player a resource
3. that prevents the player from drowning
4. but counts down over time until it is depleted

Code an item that satisfies criterion 1 first, then start working on 2, etc. until you've got everything functional on all 4 points before fine-tuning the details (interface, balance, etc.).
1. That's nothing. I have that more or less already, minus the sprite offset ruining my life
2. Yeah, I get that.
3. I have no idea how to do that.
4. Right.
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: [ZScript]Control oxygen left with ZScript?

Post by Matt »

Right, so the big challenge now is to focus on 3.

How does drowning work in vanilla anyway? I've never even looked at it.
(also a primitive part of my brain recoils very hard at the thought of trying to test it, to the point where I have never done so)


EDIT: We know, at least, that it's common to PlayerPawn and it's opened to ZScript.


EDIT: Let's lay out some of the reasoning I can infer from this:
This function calls "ResetAirSupply" if the player is invulnerable or above water.
I can take a wild guess that "ResetAirSupply" resets the air supply counter.

If your resource can have its owner playerpawn call "ResetAirSupply();" every tic, then that playerpawn will never be able to drown.....



EDIT: I've done up an item that does this, and will post it with a good deal of commentary explaining the purpose behind each function call. I don't want to post it untested so watch this space later tonight/tomorrow.
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: [ZScript]Control oxygen left with ZScript?

Post by Matt »

Matt wrote:If your resource can have its owner playerpawn call "ResetAirSupply();" every tic, then that playerpawn will never be able to drown.....

Code: Select all

class AirSupplyResetter:CustomInventory
{
    //create a variable that tracks
    //how many ticks' worth of air have been activated
    int ticker;

    default
    {
        +inventory.invbar //needs to be usable
        +inventory.keepdepleted //without this flag it'll stop working once you use the last one

        inventory.icon "BON1A0"; //just a placeholder
        inventory.maxamount 100; //another placeholder
    }
    override void DoEffect()
    {
        //if there's no air injected, nothing to do
        if(ticker<1)
        {
            if(amount<1) destroy(); //except a bit of cleanup
            return; //skip all the stuff in the function below this line
        }

        //create a pointer for the owner that is casted as a playerpawn
        let pwner = playerpawn(owner);

        //if there's no owner OR it's not properly cast, abort
        if(!pwner) return;

        //count down the ticker
        ticker--;

        //reset the playerpawn's air supply
        pwner.ResetAirSupply();

        //provide some feedback
        //obviously the final product should do something cleaner than log,
        //but we can worry about that later
        pwner.A_LogInt(ticker,true);
    }
    states
    {
    use:
        TNT1 A 0
        {
            //EDIT: bugfix
            //check if there's actually any left first since we've got +keepdepleted
            if(amount<1) return;

            //inject some air
            //add to the inventory actor's own ticker
            invoker.ticker+=1000;
        }
        stop;
    }
}
Last edited by Matt on Fri Oct 05, 2018 2:22 pm, edited 1 time in total.
User avatar
Silentdarkness12
Posts: 1555
Joined: Thu Aug 15, 2013 5:34 pm
Location: Plains of Pride

Re: [ZScript]Control oxygen left with ZScript?

Post by Silentdarkness12 »

Matt wrote:
Matt wrote:If your resource can have its owner playerpawn call "ResetAirSupply();" every tic, then that playerpawn will never be able to drown.....

Code: Select all

class AirSupplyResetter:CustomInventory
{
    //create a variable that tracks
    //how many ticks' worth of air have been activated
    int ticker;

    default
    {
        +inventory.invbar //needs to be usable
        +inventory.keepdepleted //without this flag it'll stop working once you use the last one

        inventory.icon "BON1A0"; //just a placeholder
        inventory.maxamount 100; //another placeholder
    }
    override void DoEffect()
    {
        //if there's no air injected, nothing to do
        if(ticker<1)
        {
            if(amount<1) destroy(); //except a bit of cleanup
            return; //skip all the stuff in the function below this line
        }

        //create a pointer for the owner that is casted as a playerpawn
        let pwner = playerpawn(owner);

        //if there's no owner OR it's not properly cast, abort
        if(!pwner) return;

        //count down the ticker
        ticker--;

        //reset the playerpawn's air supply
        pwner.ResetAirSupply();

        //provide some feedback
        //obviously the final product should do something cleaner than log,
        //but we can worry about that later
        pwner.A_LogInt(ticker,true);
    }
    states
    {
    use:
        TNT1 A 0
        {
            //inject some air
            //add to the inventory actor's own ticker
            invoker.ticker+=1000;
        }
        stop;
    }
} 
Sure enough, that seems to work just fine. I mean, it doesn't use up the item on use like I had imagined, but I guess that's fixed easily enough. The end goal is to tailor this a bit more to HD, but I guess it's best to take the baby steps...

....actually I think I got it now. Moooostly. The rest of this is HD-specific, so i'll just ask Matt personally about it. Thanks for the pointers.
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: [ZScript]Control oxygen left with ZScript?

Post by Matt »

I've fixed the bug that you pointed out on the HD discord.

I still strongly recommend you familiarize yourself with general ZScript weapons generally before trying to do this as one.

Return to “Scripting”