[Solved] ZScript global variables

Archive of the old editing forum
Forum rules
Before asking on how to use a ZDoom feature, read the ZDoom wiki first. This forum is archived - please use this set of forums to ask new questions.
User avatar
Nash
 
 
Posts: 17346
Joined: Mon Oct 27, 2003 12:07 am
Location: Kuala Lumpur, Malaysia

[Solved] ZScript global variables

Post by Nash »

Spoiler: old post
Solved. See attachment to learn how to do global, serializable variables. In plain English, it means variables that can be read and written into from anywhere, and its value is saved into saved games, as well as persisting between hub maps. If you worked heavily with ACS global and world variables, this is basically what it is, except in ZScript.

Only works with GZDoom commit b2a1e03 onwards
You do not have the required permissions to view the files attached to this post.
Last edited by Nash on Fri May 05, 2017 12:14 pm, edited 4 times in total.
User avatar
Matt
Posts: 9687
Joined: Sun Jan 04, 2004 5:37 pm
Location: Gotham City SAR, Wyld-Lands of the Lotus People, Dominionist PetroConfederacy of Saudi Canadia

Re: ZScript global variables

Post by Matt »

According to the wiki BeginPlay is only an Actor function while PostBeginPlay is for Thinker (and thus Actor as well of course).
User avatar
Nash
 
 
Posts: 17346
Joined: Mon Oct 27, 2003 12:07 am
Location: Kuala Lumpur, Malaysia

Re: ZScript global variables

Post by Nash »

Well okay, changing it to PostBeginPlay makes the thing run... and then... what? How do I get and assign that testVar from anywhere?

Am I supposed to Spawn this into the world somewhere or what? How would I be able to reference to it from any actor or class in the game?

[sorry I'm very frustrated, I just want simple global variables like what ACS allowed... I can't believe it's this complicated]
Gez
 
 
Posts: 17731
Joined: Fri Jul 06, 2007 3:22 pm

Re: ZScript global variables

Post by Gez »

Can you use console variables?
User avatar
Graf Zahl
Lead GZDoom+Raze Developer
Lead GZDoom+Raze Developer
Posts: 48542
Joined: Sat Jul 19, 2003 10:19 am
Location: Germany

Re: ZScript global variables

Post by Graf Zahl »

Nash wrote:
Graf Zahl wrote: So how do I actually do this, in plain, non-programmer English?
Here's a complete solution for you:

Code: Select all

class MyGlobalVariables : Thinker
{
    int testVar;

	MyGlobalVariables Init()
	{
		testVar = 0;
		SetStatNum(STAT_INFO);	// this is merely to let the thinker iterator find it quicker.
		return self;
	}
	
	static MyGlobalVariables Get()
	{
		ThinkerIterator it = ThinkerIterator.Create("MyGlobalVariables");
		let p = MyGlobalVariables(it.Next());
		if (p == null)
		{
			p = new("MyGlobalVariables").Init();
		}
		return p;
	}
}
You should only call the static Get function. Call it any time you want to access this and do not have a pointer at hand.
User avatar
Xaser
 
 
Posts: 10771
Joined: Sun Jul 20, 2003 12:15 pm

Re: ZScript global variables

Post by Xaser »

Heh, nice -- using ThinkerIterator to get the only thinker of this type.

This is the sort of thing that would be super-useful in the eventual library, so here's my (UNTESTED, MAY NOT WORK) first pass at this:

Code: Select all

/* -- base library class -- */

class SzlGlobal : Thinker
{
	SzlGlobal _InitBase()
	{
		SetStatNum(STAT_INFO); // this is merely to let the thinker iterator find it quicker.
		self.Init();
		return self;
	}

	virtual SzlGlobal Init()
	{
		// override to set custom variables.
	}

	static SzlGlobal _Get(class<SzlGlobal> type)
	{
		ThinkerIterator it = ThinkerIterator.Create(type);
		let p = SzlGlobal(it.Next());
		if (p == null)
		{
			p = new(type)._InitBase();
		}
		return p;
	}
}

Code: Select all

/* -- custom child class -- */

class CustomGlobal : SzlGlobal
{
	int customVar;

	override SzlGlobal Init()
	{
		customVar = 1337;
	}

	// [XA] just a convenience function, technically; one can
	//      call SzlGlobal._Get("CustomGlobal") directly and
	//      cast it, but I quite dislike the possibility of
	//      modder-side typos in the child class name.

	static CustomGlobal Get()
	{
		return CustomGlobal(SzlGlobal._Get("CustomGlobal"));
	}
}
Suggestions welcome -- this is a rough top-of-head draft (and there are probably errors). At the least, please forgive the pre-underscores -- that's a Javascript-ism for "you can technically call this function, but shouldn't." Felt it'd be appropriate here.

Related naming question: "SzlGlobal" or "SzlSingleton"? It's technically the latter, but modders will be accustomed to the former nomenclature.
User avatar
Nash
 
 
Posts: 17346
Joined: Mon Oct 27, 2003 12:07 am
Location: Kuala Lumpur, Malaysia

Re: ZScript global variables

Post by Nash »

Code: Select all

class MyGlobalVariables : Thinker
{
    int testVar;

    MyGlobalVariables Init()
    {
        testVar = 0;
        ChangeStatNum(STAT_INFO);
        return self;
    }

    static MyGlobalVariables Add(int i)
    {
        testVar += i;
    }

    static MyGlobalVariables Get()
    {
        ThinkerIterator it = ThinkerIterator.Create("MyGlobalVariables");
        let p = MyGlobalVariables(it.Next());
        if (p == null)
        {
            p = new("MyGlobalVariables").Init();
        }
        return p;
    }
}

class ZZ : ZombieMan replaces ZombieMan
{
    override void BeginPlay(void)
    {
        MyGlobalVariables.Add(1);
        Console.Printf(String.Format("I've seen %d zombiemen so far", MyGlobalVariables.Get()));

        Super.BeginPlay();
    }
}
 
Script error, "zscript global variables.pk3:zscript.txt" line 14:
self used outside of a member function


Thank you. One last question, how would I assign something to that variable from another actor? Let's say from a monster that wants to change that value. Pardon my noob questions, this stuff is really beyond me.
User avatar
Nash
 
 
Posts: 17346
Joined: Mon Oct 27, 2003 12:07 am
Location: Kuala Lumpur, Malaysia

Re: ZScript global variables

Post by Nash »

Code: Select all

class MyGlobalVariables : Thinker
{
    int testVar;

    MyGlobalVariables Init()
    {
        testVar = 0;
        ChangeStatNum(STAT_INFO);
        return self;
    }

    /*
    static MyGlobalVariables Add(int i)
    {
        testVar += i;
    }
    */

    static MyGlobalVariables Get()
    {
        ThinkerIterator it = ThinkerIterator.Create("MyGlobalVariables");
        let p = MyGlobalVariables(it.Next());
        if (p == null)
        {
            p = new("MyGlobalVariables").Init();
        }
        return p;
    }
}

class ZZ : ZombieMan replaces ZombieMan
{
    override void BeginPlay(void)
    {
        //MyGlobalVariables.Add(1);
        Console.Printf(String.Format("I've seen %d zombiemen so far", MyGlobalVariables.Get()));

        Super.BeginPlay();
    }
}
Well, even commenting out the Add function for now, if I do this... the game crashes when a level has ZombieMen... I'd expect to at least get a "I've seen 0 zombiemen" in the console...
User avatar
Graf Zahl
Lead GZDoom+Raze Developer
Lead GZDoom+Raze Developer
Posts: 48542
Joined: Sat Jul 19, 2003 10:19 am
Location: Germany

Re: ZScript global variables

Post by Graf Zahl »

That's because your code is wrong.

It should be

Code: Select all

        let g = MyGlobalVariables.Get();
        g.Add(1);
        Console.Printf(String.Format("I've seen %d zombiemen so far", g.testVar));
User avatar
Nash
 
 
Posts: 17346
Joined: Mon Oct 27, 2003 12:07 am
Location: Kuala Lumpur, Malaysia

Re: ZScript global variables

Post by Nash »

I'm still getting a compile error on the Add function though.

Script error, "zscript global variables.pk3:zscript.txt" line 14:
self used outside of a member function

Code: Select all

class MyGlobalVariables : Thinker
{
    int testVar;

    MyGlobalVariables Init()
    {
        testVar = 0;
        ChangeStatNum(STAT_INFO);
        return self;
    }

    static MyGlobalVariables Add(int i)
    {
        testVar += i;
    }

    static MyGlobalVariables Get()
    {
        ThinkerIterator it = ThinkerIterator.Create("MyGlobalVariables");
        let p = MyGlobalVariables(it.Next());
        if (p == null)
        {
            p = new("MyGlobalVariables").Init();
        }
        return p;
    }
}

class ZZ : ZombieMan replaces ZombieMan
{
    override void BeginPlay(void)
    {
        let g = MyGlobalVariables.Get();
        g.Add(1);
        Console.Printf(String.Format("I've seen %d zombiemen so far", g.testVar));

        Super.BeginPlay();
    }
}
 
User avatar
Graf Zahl
Lead GZDoom+Raze Developer
Lead GZDoom+Raze Developer
Posts: 48542
Joined: Sat Jul 19, 2003 10:19 am
Location: Germany

Re: ZScript global variables

Post by Graf Zahl »

Add shouldn't be static.
User avatar
Nash
 
 
Posts: 17346
Joined: Mon Oct 27, 2003 12:07 am
Location: Kuala Lumpur, Malaysia

Re: ZScript global variables

Post by Nash »

Code: Select all

class MyGlobalVariables : Thinker
{
    int testVar;

    MyGlobalVariables Init()
    {
        ChangeStatNum(STAT_INFO);
        return self;
    }

    MyGlobalVariables Add(int i)
    {
        testVar += i;
        return self;
    }

    static MyGlobalVariables Get()
    {
        ThinkerIterator it = ThinkerIterator.Create("MyGlobalVariables");
        let p = MyGlobalVariables(it.Next());
        if (p == null)
        {
            p = new("MyGlobalVariables").Init();
        }
        return p;
    }
}

class ZZ : ZombieMan replaces ZombieMan
{
    override void BeginPlay(void)
    {
        let g = MyGlobalVariables.Get();
        g.Add(1);
        Console.Printf(String.Format("I've seen %d zombiemen so far", g.testVar));

        Super.BeginPlay();
    }
}

 
Okay it compiles now, but the testVar doesn't seem to increment... it always stays as "1".

Really sorry, I know this is tedious... >_<
Last edited by Nash on Fri Feb 24, 2017 5:31 pm, edited 1 time in total.
User avatar
Major Cooke
Posts: 8109
Joined: Sun Jan 28, 2007 3:55 pm

Re: ZScript global variables

Post by Major Cooke »

A quick Console.Printf inside the "if (p == null)" area quickly revealed it's entirely null. Even after summoning more zz.

That thinker iterator is not finding them at all.
User avatar
Major Cooke
Posts: 8109
Joined: Sun Jan 28, 2007 3:55 pm

Re: ZScript global variables

Post by Major Cooke »

Fixed it.

Code: Select all

ThinkerIterator it = ThinkerIterator.Create("MyGlobalVariables",STAT_INFO);
The Create function needs STAT_INFO as the second parameter.
User avatar
Nash
 
 
Posts: 17346
Joined: Mon Oct 27, 2003 12:07 am
Location: Kuala Lumpur, Malaysia

Re: ZScript global variables

Post by Nash »

So close!!!

The variable is serialized now, but when you move to another map, the variable is back to 0! So it looks like each map is keeping its own instance of the variable.

Try jumping between the maps. Each map will save its own copy of the testVar.

What I wanted, however, was just ONE instance of it that persists globally, so if testVar was 16 when I left the level, when I enter the next level, it should also be 16!

In other words, like plain ol' ACS global variables.

Please help, we're this close. Once this is working, we can wrap this up into something neat that others can use and benefit from.

EDIT: file removed
Last edited by Nash on Sat Feb 25, 2017 10:28 am, edited 1 time in total.

Return to “Editing (Archive)”