[Solved] ZScript global variables

Discuss all aspects of editing for ZDoom.
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.

[Solved] ZScript global variables

Postby Nash » Fri Feb 24, 2017 2:24 am

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
Nash
 
 
 
Joined: 27 Oct 2003
Location: Kuala Lumpur, Malaysia
Github ID: nashmuhandes

Re: ZScript global variables

Postby Matt » Fri Feb 24, 2017 2:34 am

According to the wiki BeginPlay is only an Actor function while PostBeginPlay is for Thinker (and thus Actor as well of course).
User avatar
Matt
Putting the XD into *xdeath since 2007
 
Joined: 04 Jan 2004
Location: Gotham City SAR, Wyld-Lands of the Lotus People, Dominionist PetroConfederacy of Saudi Canadia

Re: ZScript global variables

Postby Nash » Fri Feb 24, 2017 2:35 am

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]
User avatar
Nash
 
 
 
Joined: 27 Oct 2003
Location: Kuala Lumpur, Malaysia
Github ID: nashmuhandes

Re: ZScript global variables

Postby Gez » Fri Feb 24, 2017 7:01 am

Can you use console variables?
Gez
 
 
 
Joined: 06 Jul 2007

Re: ZScript global variables

Postby Graf Zahl » Fri Feb 24, 2017 8:23 am

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 allExpand view
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
Graf Zahl
Lead GZDoom+Raze Developer
Lead GZDoom+Raze Developer
 
Joined: 19 Jul 2003
Location: Germany

Re: ZScript global variables

Postby Xaser » Fri Feb 24, 2017 10:31 am

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 allExpand view
/* -- 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 allExpand view
/* -- 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
Xaser
anarchivist
 
 
 
Joined: 20 Jul 2003

Re: ZScript global variables

Postby Nash » Fri Feb 24, 2017 12:38 pm

Code: Select allExpand view
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 (
== null)
        {
            
= 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
 
 
 
Joined: 27 Oct 2003
Location: Kuala Lumpur, Malaysia
Github ID: nashmuhandes

Re: ZScript global variables

Postby Nash » Fri Feb 24, 2017 1:06 pm

Code: Select allExpand view

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 (== 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
Nash
 
 
 
Joined: 27 Oct 2003
Location: Kuala Lumpur, Malaysia
Github ID: nashmuhandes

Re: ZScript global variables

Postby Graf Zahl » Fri Feb 24, 2017 1:25 pm

That's because your code is wrong.

It should be
Code: Select allExpand view
        let g = MyGlobalVariables.Get();
        g.Add(1);
        Console.Printf(String.Format("I've seen %d zombiemen so far", g.testVar));
User avatar
Graf Zahl
Lead GZDoom+Raze Developer
Lead GZDoom+Raze Developer
 
Joined: 19 Jul 2003
Location: Germany

Re: ZScript global variables

Postby Nash » Fri Feb 24, 2017 1:31 pm

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 allExpand view
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 (
== null)
        {
            
= 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
Nash
 
 
 
Joined: 27 Oct 2003
Location: Kuala Lumpur, Malaysia
Github ID: nashmuhandes

Re: ZScript global variables

Postby Graf Zahl » Fri Feb 24, 2017 1:56 pm

Add shouldn't be static.
User avatar
Graf Zahl
Lead GZDoom+Raze Developer
Lead GZDoom+Raze Developer
 
Joined: 19 Jul 2003
Location: Germany

Re: ZScript global variables

Postby Nash » Fri Feb 24, 2017 2:45 pm

Code: Select allExpand view

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 (== 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
Nash
 
 
 
Joined: 27 Oct 2003
Location: Kuala Lumpur, Malaysia
Github ID: nashmuhandes

Re: ZScript global variables

Postby Major Cooke » Fri Feb 24, 2017 3:43 pm

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
QZDoom Maintenance Team
 
Joined: 28 Jan 2007

Re: ZScript global variables

Postby Major Cooke » Fri Feb 24, 2017 3:51 pm

Fixed it.

Code: Select allExpand view
ThinkerIterator it = ThinkerIterator.Create("MyGlobalVariables",STAT_INFO);


The Create function needs STAT_INFO as the second parameter.
User avatar
Major Cooke
QZDoom Maintenance Team
 
Joined: 28 Jan 2007

Re: ZScript global variables

Postby Nash » Fri Feb 24, 2017 5:31 pm

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.
User avatar
Nash
 
 
 
Joined: 27 Oct 2003
Location: Kuala Lumpur, Malaysia
Github ID: nashmuhandes

Next

Return to Editing (Archive)

Who is online

Users browsing this forum: No registered users and 2 guests