Globally accessible functions

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!)
Kzer-Za
Posts: 509
Joined: Sat Aug 19, 2017 11:52 pm
Graphics Processor: nVidia (Modern GZDoom)

Globally accessible functions

Post by Kzer-Za »

Can I set a function that can be accessed by all actors, not just the ones inheriting from the actor in which it was defined? I mean, I know how to create a function for a class:

Code: Select all

Class ClassName : Actor
{
	void SchismHeightClip
	{
		if (prevFloorclip != Floorclip)
			Height = Height - (Floorclip - prevFloorclip);
		prevFloorclip = Floorclip;
	}
...
}
But then this or any other such function can be accessed only by classes that inherit from ClassName. Where can I define functions that need global access, for classes that I can't all inherit from one class?
Blue Shadow
Posts: 4949
Joined: Sun Nov 14, 2010 12:59 am

Re: Globally accessible functions

Post by Blue Shadow »

Make it a static function. Example:

Code: Select all

class Blah // Inheriting from Actor isn't necessary.
{
    static void LogActorHealth (Actor other)
    {
        if (other != null)
        {
            Console.Printf("%d", other.health);
        }
    }
}

class DemonY : Demon
{
    States
    {
    Death:
        // Logs its killer's health.
        SARG A 0 { Blah.LogActorHealth(target); }
        Goto Super::Death;
    }
}
One thing to note is that static functions don't have an implicit caller. That's why you need to pass the actor on which the function is to be executed.
User avatar
3saster
Posts: 199
Joined: Fri May 11, 2018 2:39 pm
Location: Canada

Re: Globally accessible functions

Post by 3saster »

More specifically, static functions are can be though of as functions that "exist by themselves", and don't rely a particular instance of a class to be used. Thus, you can call them anywhere you like, but because they "exist by themselves", you have to explicitly pass them any variables you want it to use (or they have to be global). Static functions are not unique to ZScript btw; many other programming languages have the concept of static functions or variables.
SanyaWaffles
Posts: 806
Joined: Thu Apr 25, 2013 12:21 pm
Preferred Pronouns: They/Them
Operating System Version (Optional): Windows 11 for the Motorola Powerstack II
Graphics Processor: nVidia with Vulkan support
Location: The Corn Fields
Contact:

Re: Globally accessible functions

Post by SanyaWaffles »

Static functions are useful to put into a utilities class that you can call from any class. I have one in DD2 that's slowly being built for stuff I use across multiple classes.
Kzer-Za
Posts: 509
Joined: Sat Aug 19, 2017 11:52 pm
Graphics Processor: nVidia (Modern GZDoom)

Re: Globally accessible functions

Post by Kzer-Za »

Thanks!

But I'm having difficulties with accessing user variables from a static function. Using the same function as in my first post, that adjusts the actor's height when it is clipped into the floor: I need to access a variable "prevFloorclip" in actor "other", so I need to define a variable other2 with the class of this actor. Since I don't know the class (the whole point of creating a global function, to acces it from any class), I try to get the class name. But something is not working. Here is the code:

Code: Select all

Class SchLib : Actor
{
	int prevFloorclip;
	
	static void SchismHeightClip(Actor other)
	{
		if (other != null)
		{
			name OtherClassName = other.GetClassName();
			
			let other2 = OtherClassName(other);
			
			if (other2.prevFloorclip != other2.Floorclip)
				other2.Height = other2.Height - (other2.Floorclip - other2.prevFloorclip);
			other2.prevFloorclip = other2.Floorclip;
		}
	}
}
And I get an error

Code: Select all

Call to unknown function 'OtherClassName'
SanyaWaffles
Posts: 806
Joined: Thu Apr 25, 2013 12:21 pm
Preferred Pronouns: They/Them
Operating System Version (Optional): Windows 11 for the Motorola Powerstack II
Graphics Processor: nVidia with Vulkan support
Location: The Corn Fields
Contact:

Re: Globally accessible functions

Post by SanyaWaffles »

I don't think this will work either but did you try this?

Code: Select all

         Class<Actor> OtherClassName = other.GetClassName();
         
         let other2 = OtherClassName(other);
         
         if (other2.prevFloorclip != other2.Floorclip)
            other2.Height = other2.Height - (other2.Floorclip - other2.prevFloorclip);
         other2.prevFloorclip = other2.Floorclip;
I dunno if there's a way to cast stuff dynamically like this.
Kzer-Za
Posts: 509
Joined: Sat Aug 19, 2017 11:52 pm
Graphics Processor: nVidia (Modern GZDoom)

Re: Globally accessible functions

Post by Kzer-Za »

Still the same error :(
User avatar
Cherno
Posts: 1311
Joined: Tue Dec 06, 2016 11:25 am

Re: Globally accessible functions

Post by Cherno »

Code: Select all

 name OtherClassName = other.GetClassName();
         
         let other2 = OtherClassName(other);
This means that a new variable of type "name" called "OtherClassName" is initialized.
Then another variable called "other2" is initialized and assigned the return value of the function "OtherClassName" with the parameter of other passed.

See why this doesn't work? the compiler tells you the right thing; OtherClassName is not a function, but you try to use it as one. You want to cast other as other's class, but it won't work like this (by the way, GetClassName does not return a class). Actually, IO am not sure why you would want to do this anyway, since you are only accessing base actor variables like prevFloorclip, so you can just do away with other2 and access otehr directly.
Kzer-Za
Posts: 509
Joined: Sat Aug 19, 2017 11:52 pm
Graphics Processor: nVidia (Modern GZDoom)

Re: Globally accessible functions

Post by Kzer-Za »

Cherno wrote:so you can just do away with other2 and access otehr directly.
But how? From this topic viewtopic.php?f=122&t=68669 I got the impression that I can't. And indeed, if I try this:

Code: Select all

Class SchLib : Actor
{
	static void SchismHeightClip(Actor other)
	{
		if (other)
		{
			if (other.prevFloorclip != other.Floorclip)
				other.Height = other.Height - (other.Floorclip - other.prevFloorclip);
			other.prevFloorclip = other.Floorclip;
		}
	}
}
then I get the error

Code: Select all

Unknown identifier 'prevFloorclip'
like in the aforementioned topic.
_mental_
 
 
Posts: 3812
Joined: Sun Aug 07, 2011 4:32 am

Re: Globally accessible functions

Post by _mental_ »

Either cast other to your base actor class (where prevFloorclip is defined), or change argument type to that class.
Kzer-Za
Posts: 509
Joined: Sat Aug 19, 2017 11:52 pm
Graphics Processor: nVidia (Modern GZDoom)

Re: Globally accessible functions

Post by Kzer-Za »

_mental_ wrote:Either cast other to your base actor class (where prevFloorclip is defined), or change argument type to that class.
Then the whole idea loses its point. If I could inherit all the actors that need this function from one class, I would simply define this function in that class. One variable I can add to actors that inherit from different classes, but the code of the function I want to keep in one place, not in two or three different classes from which it is inherited by the actors that need it. Otherwise, if/when I decide to expand/change that function code I may change it in one class and forget about the other(s). It seems like a bad design to keep one code in more than one place.
_mental_
 
 
Posts: 3812
Joined: Sun Aug 07, 2011 4:32 am

Re: Globally accessible functions

Post by _mental_ »

Your approach cannot work by definition because ZScript is a statically-typed language. To access a member, the type of its class must be known at compile time.
Kzer-Za
Posts: 509
Joined: Sat Aug 19, 2017 11:52 pm
Graphics Processor: nVidia (Modern GZDoom)

Re: Globally accessible functions

Post by Kzer-Za »

So, for now I decided to use PainChance to store the value of the Floorclip during the previous tic, since PainChance is not gonna be used in my mod anyway and it is one of the values that can be accessed directly in any class via other.PainChance.
User avatar
KeksDose
 
 
Posts: 595
Joined: Thu Jul 05, 2007 6:13 pm
Contact:

Re: Globally accessible functions

Post by KeksDose »

You could wrap your var in a struct or class to get the function with it. Since you allow editing actors, this'll reduce work to just a few easy lines and reuses the same function for all cases. There's also mixins that kinda have the same result, but a potentially great benefit is being able to set default values for your vars.

Code: Select all

struct HeightClip { // or "mixin class HeightClip"
   double prevFloorclip;
   
   void Tick (Actor mo) {
      if(mo && mo.floorclip != prevFloorclip) {
         // ...
      }
   }
}

class Whatever : Actor {
   HeightClip height_clip; // or "mixin HeightClip"
   
   // You can then set height_clip.prevFloorclip = floorclip and call height_clip.Tick(self) to use your function.
   // If you use a mixin, you can skip writing height_clip. Rename Tick back to SchismHeightClip then haha.
}
User avatar
Apeirogon
Posts: 1605
Joined: Mon Jun 12, 2017 12:57 am

Re: Globally accessible functions

Post by Apeirogon »

Did you try to use virtual functions? Something like

Code: Select all

struct struct_data {int i;}

class monsta : actor
{
struct_data data_name;
//set data name somewhere
virtual void get_all_data(in out struct_data var)
{
if(data_name && var) {var.i = var.i;}
}

}

class player : playerpawn
{same as for monsta}
Then just call actors virtual function from static. IIRC you can call virtual functions without explicitly defining class type.
Post Reply

Return to “Scripting”