Jump to content

[ZScript] Help with creating objects (Casting?)


Recommended Posts

Edit: I'm trying to set-up some ZScript so that if the player presses some keys, say X or C, that a few things can happen. So far I have been able to create methods within a child of the DoomPlayer class that are called when the player hits these keys. The next step is for these methods to call other methods within objects that are created within this child. These objects (do correct me if I'm wrong, but I think the term might be 'controllers') have getter/setter methods that I would like to access.

 

I'm apologising now if this thread breaks forum etiquette, I'm not familiar with starting these. Also, I know that this issue is very much programming 101 but I'm no programmer. I was trying to resolve this issue by myself some months ago, but I simply cannot do this and I've been putting off asking for help ever since.

 

As the title states, I need some help instantiating some classes so that I can call some methods/functions from them. Specifically, I'm trying to create two objects within a child of the DoomPlayer class, with these objects being related to each other. Declaring them is fine, but I cannot seem to assign them a value (that is, 'Var object = Class();' or something like that); the error of 'unexpected '=' Expecting identifier' is printed in the terminal with GZDoom not launching.

 

I have been using https://github.com/jekyllgrim/ZScript_Basics/ and while their guide has helped me with a few bits here and there, the section regarding pointers has not helped much, unfortunately.

 

I'm providing some reference/example code that, hopefully, might explain things a little better than the above.

Class P : DoomPlayer {

	Children ch1, ch2;
  
	Default {
	}

  	override void BeginPlay () {
      
    	self.ch1 = //this is where I'm now stuck...
	} //Also, I'm guessing that I should be using 'self'.
  
	void C_Key () {
      
      	self.ch1.get();
	}
  
  	void X_Key () {
      
     	self.ch2.set(); 
    }
}

Just a little note, creating the objects via 'Child1 ch1;' and the same for the second also seems to work, I just like using the parent (which I'm guessing is probably the incorrect way of doing things...)

Class Children : Inventory {

	virtual void Get () {
	}
  
  	virtual void Set () {
	}
}
Class Child1 : Children {

	override void Get () {
	}
}

Child2 is the same as Child1 for the purpose of this post.

 

Thank you for your time.

Edited by CyberosLeopard
This is now more specific to my problem, at the cost of maybe being less helpful to others in the future (not that anyone would likely have this much difficulty).

Share this post


Link to post

Creating a new (non-actor) object in ZScript is done by syntax new("<class name>"). So yours would be ch1 = new("Child1");

 

Also you cannot initialize variables in class body. You need to initialize them in a method (best is probably in a BeginPlay() method override)

 

Hopefully this helps.

Edited by jaeden

Share this post


Link to post

Thank you for your help. I've realised that I should have been less ambiguous and stated that the 'Children' class was inheriting from PowerupGiver; unfortunately the example you gave doesn't quite work. However, having been re-reading the ZDoom wiki article on PowerupGiver and I'm thinking it's probably a mistake to use it in the first place.

 

I think I should be able to work it out from here. Thanks again.

Share this post


Link to post

I am really, truly sorry for furthering this tread, but I don't think I'm able to work this out by myself. I'll update and amend the first post with a few additions, and to try and clarify some points; I think I was being a bit too ambiguous.

 

I have ran through a few different permutations of creating an object of Child1: with at best ch1 holding a null value and when one of its methods are called, GZDoom crashes; at worst, GZDoom is not launching due to errors relating to not being able to convert pointers or not finding a global identifier. I don't exactly understand what I need to do.

 

Ultimately looking at Jekyllgrim's ZScript basics (in the first post) and https://zdoom.org/wiki/Using_pointers_in_ZScript/ for reference, I think it is safe to say that a parameter is needed to instantiate the object. However, I am unsure to what parameter Inventory takes when being instantiated. I have had a quick look over on Github (https://github.com/coelckers/gzdoom/blob/master/wadsrc/static/zscript/actors/inventory/inventory.zs), but I'm not able to understand most of it, nor can I find Inventory's constructor (I've probably over looked it).

 

Thanks again.

Share this post


Link to post
  • 1 year later...

I am really sorry for necro-ing this thread, but this has been eating away at the back of my head for the last few weeks being as I have found a solution to this problem. Updating this thread might, might help someone else out there (and if it doesn't, at least I'm adding a conclusion).

 

I found the following ZDoom forum thread that held a fix to a different, but related problem regarding changing the value of variables within projectiles fired from a weapon: https://forum.zdoom.org/viewtopic.php?f=122&t=69719

 

Unfortunately, with me being a little on the slower side of things (a bit of an understatement, I know) I didn’t grasp that a ZDoom wiki page that I had read prior implicitly states that one is required to make a pointer and then cast said pointer: (https://zdoom.org/wiki/Using_pointers_in_ZScript). This is ultimately where I got stuck.

 

So... what worked for me is giving the children (Child1 and-or Child2) to the player via ‘GiveInventory’ within the player’s BeginPlay() method, and saving the result in a boolean. From here, check if said boolean is true (just a precaution) and if so call ‘FindInventory’ and saving its result in a global variable (I used a type ‘Actor’). Doing those steps will save a pointer, which can be cast. For example: ‘let varname = Child1 (self.globalvarname)’. Finally, accessing the cast’s functions is as simple as ‘varname.function()’.

 

Annoyingly, I’ve been trying to get this all working since around June/July of 2021, and in my typical stupidity it has taken around two years which would only really require another person a few hours at most…

 

Take care.

Share this post


Link to post

Well, show your code. It is quite impossible to give any advice from your description, sorry.

 

And for better, tells us what you want to make. Not the code side, just try your best to describe what you intent to achieve. Maybe there is another solution, that is completely oblivious to you. My experience with zscript is that one goal could be achieved through many completely valid and possible ways.

 

Here, take a look at code I used in one of my inventory items. The item could be activated and deactivated, has its own 'magazine' that acts as a energy for the said item, which could be recharged. That's not important here. You could take a look at how I've modified the Use() to have more than one output.

override bool Use (bool Pickup) {
		let pawn = wastelandRanger(owner);
		TextureID id_I_NED1 = TexMan.CheckForTexture("I_NED1", 0, 0);
		TextureID id_I_NED2 = TexMan.CheckForTexture("I_NED2", 0, 0);
		// check charge // checks for charge if player presses 'activate item' and 'use' keys together
		if ( pawn.GetPlayerInput(MODINPUT_BUTTONS)&BT_USE ) {
			pawn.A_Log(String.Format( "%s%i%s", stringtable.localize("$M_nightEyeDev_battsLeft1"), self.charge, stringtable.localize("$M_nightEyeDev_battsLeft2")));
		}
		// reload // reloads item if player presses 'activate item' and 'user1' 
		else if ( pawn.GetPlayerInput(MODINPUT_BUTTONS)&BT_USER1 ) {
			int finalLoad = 100 - self.charge;
			if ( self.charge == 100 || pawn.CountInv("EnergyPod") < finalLoad ) {
				pawn.A_Log("$M_nightEyeDev_cantReload");
			} else {
				if ( pawn.CountInv("EnergyPod") >= finalLoad ) {
					pawn.TakeInventory("EnergyPod", finalLoad);
					self.charge += finalload;
					pawn.A_Log(String.Format( "%s%i%s", stringtable.localize("$M_nightEyeDev_battsReloaded1"), finalload, stringtable.localize("$M_nightEyeDev_battsReloaded2")));
				}
			}
		}
		// turn off //
		else if ( self.inUse == 1 ) {
			self.inUse = 0;
			self.animCounter = 0;
			self.bUNDROPPABLE = 0;
			pawn.A_StartSound("flashlight/off", CHAN_5);
			self.icon = id_I_NED1;
		}
		// turn off if depleted //
		else if ( self.charge == 0 ) {
			pawn.A_Log("$M_nightEyeDev_battsDepleted");
			self.inUse = 0;
			self.animCounter = 0;
			self.bUNDROPPABLE = 0;
			pawn.A_StartSound("flashlight/off", CHAN_5);
			self.icon = id_I_NED1;
		}
		// start //
		else {
			self.inUse = 1;
			self.bUNDROPPABLE = 1;
			pawn.A_StartSound("flashlight/on", CHAN_5);
			self.icon = id_I_NED2;
		}

		return false; //disable normal use
	}

Also, you could use the keypress check in Tick() override. Like I said, many ways to achieve one goal :)

Edited by ramon.dexter

Share this post


Link to post

Key Configuration:

Spoiler

addkeysection "Mod" myMod

addmenukey "Do a thing" bind0

defaultbind e bind0

alias bind0 "netevent dothing"

 

Event Handler:

Spoiler

Class NewEventHandler : EventHandler {

	override void NetworkProcess (ConsoleEvent keyhit) { //I did try inputprocess, but there was a scope issue

		if (keyhit.Name == "dothing") { //This checks if a key has been hit, and if so, calls a function
			let p = DoomPlayer (players [keyhit.Player].mo); //within the player.
			p.DoThing ();
		}
	}
}

 

Player Class:

Spoiler

Class NewPlayer : DoomPlayer {

	Actor thing;

	override void BeginPlay () {

		Super.BeginPlay();

		bool temp = GiveInventory ("Child1", 1);
		if (temp == True) {

			self.thing = FindInventory ("Child1");
			if (self.thing == null) {
			A_Log ("Error");}
		}
	}

	override void DoThing () {

	if (Health >= 1) {
	let thisthing = Child1 (self.thing);
        thisthing.Execute ();
	}
	}
}

 

Child1:

Spoiler

Class Child1 : Inventory {

	Default {}

	void Execute () {

	A_Log ("Doing a thing!");
	owner.GiveInventory ("ArmorBonus", 1);
    }
}

 

I'm hoping that covers about everything.

 

In regards to what I'm trying to make, I hope you don't mind but I'd really rather not talk about it :) But for this thread, I simply was looking for a way to... well, do a thing via pressing a key.

Also thank you for your code and time. While I only have the faintest understanding of it, it's good to know of other possibilities. I'll have to look into GetPlayerInput() along with checking for key-presses in a Tick() method at some point.

Share this post


Link to post

Rather not talk about it? Good luck then. When asking for help, you have to answer all qustions required. Valid answer is not 'i want to keep it secret'. When you want to have secrets, you're on your own. Sorry.

Share this post


Link to post

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...