Jump to content
The Dark Mod Forums

GUI on a world object


Geep

Recommended Posts

I've been working on prepping some basic info about TDM-specific gui scripting, and there's an issue that has me stumped, having to do with a gui on a world object's surface... NOT an overlay. I'd like to influence what that gui does from a .script (either regular or script object, and by passing either values or using calls), but haven't been successful. I understand that TDM's version of idTech4 has reduced functionality for guis on world surfaces, but still.... If you want to take a wack, here's details. As always, could just be syntax problem.
 

Spoiler

As a test case, suppose you have a simple func_static, opaque except for an "Entity GUI" on one face. Give it a spawnarg override "gui_noninteractive 0" (though it doesn't seem to make a difference). Then give it a "gui" spawnarg to point to your gui file. Let's start with this simple gui, which work fine... it makes the active face flash bright green or invisible forever.
 

windowDef test
{
  rect 0, 0, 640, 480
  backcolor 0,1,0,1
  visible 1
  notime 0

  onTime 0
  {
    set "visible" "0";
  }

  onTime 1000
  {
    set "visible" "1";
  }

  onTime 2000
  {
    resetTime 0;
  }
}

Now, you want to alter it so the visibility change happens instead every time you frob the object (on one of its opaque sides). You might have a frob_action_script with code like:
 

void onFrob(entity me)
{

  // define at file scope: float vis = 0;
  sys.println("frobbed");

  if(vis == 0)
  {
    me.setKey("gui_parm1",1);
  }
  else
  {
    me.setKey("gui_parm1",0);
  }

  vis = me.getIntKey("gui_parm1"); // just to confirm it's really changing
  sys.println("vis = " + vis);
};

I can get this toggling code to respond (or a version that forwards the frob request to an equivalent script object function). The problem is that a gui like that shown next (my latest of many iterations here)...

windowDef test
{
  rect 0, 0, 640, 480
  backcolor 0,1,0,1
  visible 0
  notime 0
  float vis

  onTime 100
  {
    set "vis" "$gui::gui_parm1";
    if("vis" == 1)
    {
      set "cmd" "log 'visible 1 branch'";
      set "visible" "1";
    }
    else
    {
      set "cmd" "log 'visible 0 branch'";
      set "visible" "0";
    }
    resetTime 0;
  }
}

...with or without a "$" before the "gui::", never gets a changing value. Logging calls aren't working either, which doesn't help debugging. (BTW, calls like

  me.setGuiString(handle,"gui_parm1","0");

won't work, because they ignore handles that are not overlays.)

As an alternative, I've tried using this in the script

  sys.handleMissionEvent(self, EVENT_READABLE_OPENED,"");

to call this in the gui:

  onNamedEvent readableOpen {..}

but it doesn't appear to fire.

Thanks for any help

Link to comment
Share on other sites

 

If nobody else knows, speak to tels about this. Recently I created a patch pack for Dark Radiant 2.14.0, and in the internal shader material, I encountered tels describing the GUI shader as intended to be used with an entity property/spawnarg. ...so ask him to clarify why he wrote that.

Link to comment
Share on other sites

13 hours ago, Geep said:
void onFrob(entity me)
{

  // define at file scope: float vis = 0;
  sys.println("frobbed");

So I'm wondering if this is correct. It seems to me you created the variable vis but then you put // before that line, so that whole line is just a comment. I don't know, maybe that's intended?

Link to comment
Share on other sites

21 minutes ago, datiswous said:

So I'm wondering if this is correct. It seems to me you created the variable vis but then you put // before that line, so that whole line is just a comment. I don't know, maybe that's intended?

I don't know enough about this, but at first glance, setting it to 0 (in onFrob() ) would defeat the whole purpose of the script, but maybe the variable scope doesn't reach into this script, and so he needs to at least put "float vis;" in there, or maybe "float vis = me.getIntKey("gui_parm1");".

I don't know anything, but I've only seen "set" be used for spawnarg key-value pairs, and those seem different from variables.

Edited by Nort
Link to comment
Share on other sites

Sorry if I confused. What I meant was that this:

float vis = 0;

needs to be declared at the beginning of the .script file that contains the onFrob() [and maybe other functions in general] and outside the body of onFrob, so the value will persist between onFrob invocations, not just be temporary.  Like the scoping in C.

BTW, I believe tels is no longer active with TDM, so guidance must come from elsewhere.

Link to comment
Share on other sites

3 minutes ago, Geep said:

Sorry if I confused. What I meant was that this:

float vis = 0;

needs to be declared at the beginning of the .script file that contains the onFrob() [and maybe other functions in general] and outside the body of onFrob, so the value will persist between onFrob invocations, not just be temporary.  Like the scoping in C.

BTW, I believe tels is no longer active with TDM, so guidance must come from elsewhere.

Why I'm so confused, is that when I write functions that are supposed to take parameters, I write this:

Quote
void onFrob(entity me, float vis)
{
	// Code using the entity me and the float vis.
}

I don't just "declare vis outside". ...and then I output return values from a function, in the form of "return vis;", or put "float" instead of "void". It's been a while since I programmed C++, if this is even C++, but that's how I remember doing it. Are you sure you know the basics of how functions work?

Link to comment
Share on other sites

To use the frob_action_script call, you must supply a function with the signature "void myfrobfunc(entity)".

There a multiple ways to persist a value between function calls; I just used one that I like. If instead of a simple function, you were writing a script object, you'd typically make it a variable of the object (again, declared outside the body of any member function).

Link to comment
Share on other sites

14 minutes ago, Geep said:

To use the frob_action_script call, you must supply a function with the signature "void myfrobfunc(entity)".

There a multiple ways to persist a value between function calls; I just used one that I like. If instead of a simple function, you were writing a script object, you'd typically make it a variable of the object (again, declared outside the body of any member function).

You talking about "objects" sounds like object oriented programming, which I shun, so now I have an excuse to not understand what you're saying.
* slinks away.*

 

Edited by Nort
Link to comment
Share on other sites

On second thought, what is frob_action_script? Is it a function, like frob_action_script()? Is it a spawnarg? ...because if it's a spawnarg, then that's a weird restriction. Why would a spawnarg care how many parameters you put into your function? ...and if it's a function, in some languages you can overload functions, which is that you can just write another frob_action_script(), but which takes two parameters.
In any case, maybe your way works. I don't know how objects work.

 

Link to comment
Share on other sites

@greebo, here it is:

https://drive.google.com/file/d/19sAIHOtVZYkkNtfzwLOB-Fq8NCSsD8a6/view?usp=sharing

This is not full fledged, so needs to be started with "map testgui", not through main menus.

You'll see a green surface, with brown side walls. If you frob it repeatedly, nothing happens, but you can see in the console that the frob script is trying to toggle the visibility of the green surface.

Link to comment
Share on other sites

@Nort

Quote

Is it a spawnarg? ...because if it's a spawnarg, then that's a weird restriction. Why would a spawnarg care how many parameters you put into your function?

Yes, it's a spawnarg. In TDM, if you are calling a function from a spawnarg that's designed to do that, it will want a particular form of the function. If you don't give it what it wants, you often get a stack underflow because of a mismatch in parameters. User input parameters and output results are often passed in separate spawnargs, agreed upon by caller and callee.

Link to comment
Share on other sites

Ok, if I understood your use case correctly, this should do the trick:

Change the GUI to look like this:

windowDef test
{
  rect 0, 0, 640, 480
  backcolor 0,1,0,1
  visible "gui::is_visible"
  notime 0
}

The visible property is now bound to the is_visible GUI state variable. Which is "0" by default, so the green window starts out hidden.

Change your script to toggle the visibility by inverting the state flag:

void onFrob(entity me)
{
  sys.println("frobbed");

  // Invert the is_visible variable that is bound 
  // to the visible property of the test window
  me.setGuiInt(1, "is_visible", 1 - me.getGuiInt(1, "is_visible"));

  // Note: The first argument "1" refers to the first entity GUI
  // as defined by the "gui" "guis/test.gui" spawnarg
}

Does this help?

  • Like 1
  • Thanks 1
Link to comment
Share on other sites

30 minutes ago, Geep said:

@Nort

Yes, it's a spawnarg. In TDM, if you are calling a function from a spawnarg that's designed to do that, it will want a particular form of the function. If you don't give it what it wants, you often get a stack underflow because of a mismatch in parameters. User input parameters and output results are often passed in separate spawnargs, agreed upon by caller and callee.

Okay. Looking forward to dealing with that next month, when I start scripting. :)

Link to comment
Share on other sites

@greebo, confirmed that works. Wonderful! But now some questions, starting with the .script side.

I did play around with setGuiInt for a while, but then concluded that it (and other setGui... SDK calls) couldn't work, because inside the C++ code, it looks to confirm that the passed handle is in the m_overlays list. I kinda thought that a handle for a gui that was on a world object's surface would not have an overlay defined for it. So I'm confused again. Does overlay not refer to a 2D pane rendered in the same plane as the screen?

When I was working with setGuiInt, since I wasn't instantiating the world surface gui myself, but relying on autoload, I didn't have the handle number, so I would find it using:

string s;

  sys.println("handle hunt");
  for (i = 0; i < 10000; i++)
  {
      s = me.getGui(i);
      if(s != "") // could do a better job of string comparison here, but works for test map
      {
        handle = i;
        sys.println(s);
        break;
      }
  }
  sys.println("handle =" + i);

That was returning a value of 1. But what you seem to be saying is, the handle has to be 1 for the gui defined by "gui". True? And presumably that goes for "gui2" (handle = 2) and "gui3" (handle =3), but maybe not beyond that?

 

Link to comment
Share on other sites

Playing with my earlier version of the .gui file, to try to understand why it didn't work. Main problem turned out to be that a user variable (in spite of Doom 3 documentation suggesting otherwise) needs to be terminated by either a ";" or a "0". I'm adding that to one of my draft articles, working title "Syntax from Hell".🔥

This now works, approximately same behavior as greebo's version (if less elegant):
 

windowDef test
{
  rect 0, 0, 640, 480
  backcolor 0,1,0,1
  visible 0
  notime 0
  float vis; // must either end with ";" as here, or 0

  onTime 0
  {
    if("vis" != "$gui::is_visible")
    {
      set "visible" "$gui::is_visible";
      set "vis" "$visible";
      set "cmd" "log 'visible changed'";
    }
  }

  onTime 100
  {
    resetTime 0;
  }
}

@greebo, what is still a mystery is why the logging you see here is not working. Not showing up in either qconsole.log or DarkMod.log. Is there some .cfg value that must be set? Or a special log file I'm not aware of?

Link to comment
Share on other sites

6 hours ago, Geep said:

So I'm confused again. Does overlay not refer to a 2D pane rendered in the same plane as the screen?

I think the overlay system was designed to work with the player entity (HUD, effects, etc.), hence the name. It was implemented on the generic entity level, so it replaced the older system for all the entities. That's what I could figure out in the little time; it has been ages since I've touched that code and if I recall correctly, I didn't implement it myself, maybe it's been Ishtvan.

6 hours ago, Geep said:

That was returning a value of 1. But what you seem to be saying is, the handle has to be 1 for the gui defined by "gui". True? And presumably that goes for "gui2" (handle = 2) and "gui3" (handle =3), but maybe not beyond that?

I think, yes, since the "gui", "gui2", "gui3" spawnargs are processed before any script or game code has a chance to load any additional GUIs and reserve these [1..3] handles.

A workaround to not hardcoding the handle might be 1) use the script loop you wrote to find out what handle it has been assigned or 2) load the GUI by the script itself using me.setGui("guis/test.gui") and store the handle somewhere (either a script object field or the "me" func_static entity).

2 hours ago, Geep said:

Main problem turned out to be that a user variable (in spite of Doom 3 documentation suggesting otherwise) needs to be terminated by either a ";" or a "0". I'm adding that to one of my draft articles, working title "Syntax from Hell".🔥

I know how you feel, weird GUI syntax is weird. I remember having my own fill of figuring out the GUI quirks back when we didn't have any sources to check.

The GUI parser also chokes if no onTime block is present after the "float vis" declaration (without semicolon), claims about running into "unexpected end of file". It seems almost everybody hates working with GUIs, but after you've sunk in you'll find can do a lot and there are some really powerful features in there.

2 hours ago, Geep said:

what is still a mystery is why the logging you see here is not working. Not showing up in either qconsole.log or DarkMod.log.

The logging only works for the main menu GUI, which I assume is where you got that part from. The main menu GUI has special support in the C++ code, in idGameLocal::HandleMainMenuCommand or something like that. IIRC this method was the only place I could connect to the main menu GUI and implement things like the Mission Download GUI (in the days of closed source). set cmd "log" was one of the crucial things I needed for debugging stuff.

You can look at the main menu to learn, but some things cannot be applied to regular player or entity GUIs, especially the set "cmd" trickery.

  • Like 1
Link to comment
Share on other sites

On 6/16/2022 at 11:39 PM, greebo said:

The logging only works for the main menu GUI, which I assume is where you got that part from. The main menu GUI has special support in the C++ code, in idGameLocal::HandleMainMenuCommand or something like that. IIRC this method was the only place I could connect to the main menu GUI and implement things like the Mission Download GUI (in the days of closed source). set cmd "log" was one of the crucial things I needed for debugging stuff.

You can look at the main menu to learn, but some things cannot be applied to regular player or entity GUIs, especially the set "cmd" trickery.

Actually, set "cmd" log... was described in the Doom 3 docs, but I did earlier confirm the syntax as used in the main menu system. Those docs didn't indicate it couldn't be applied to player or entity GUIs.

What I'm trying to do now is develop TDM-specific documentation, so knowing what won't work is fine. Although I might put in a bugtracker feature request to get set "cmd" logging more generally available, for the obvious assistance it would give to mapper GUI debugging.

From what you say, I guess there's no point in testing set "cmd" runScript...  There is the other version (just "runScript...") I need to experiment with.

BTW, thanks for clarifying the handle & overlay situation.

EDIT: Just runScript, while quietly parsed, doesn't seem to me to try to execute the script function.

Edited by Geep
Link to comment
Share on other sites

Hi sorry for going off topic here a bit, but I noticed that on wiki page https://wiki.thedarkmod.com/index.php?title=GUI_Scripting:_Parsing_of_Set_'Cmd' in section TDM’s Specialized GUI Commands > Within GUIs of the Main Menu System , I think this info is still based on the 2.09 menu, while 2.10 got a big change. Some stuff like eraseSelectedModFromDisk is removed I think (I might be wrong). Although maybe these commands still work, but aren't used in the main menu's anymore.

Edited by datiswous
Link to comment
Share on other sites

A broader GUI issue: I'm struggling to adequately understand "gui::" variables. I've got a series of questions, but let me start with 2 basic ones, having to do with scoping. I’m going to use the general term “guiDef” to refer to “windowDef”, “choiceDef”, etc.

1. Internally, I think "gui::" variables are those stored in idDict structures. With respect to a given GUI, is there a single idDict for an entire GUI (i.e., top-level on down), or does each guiDef (top-level or nested) have its own?

2. Is there also (or instead) a “global” idDict, across all GUIs in an FM?

Looking mainly for TDM-specific answers from our gurus. Thanks.

Link to comment
Share on other sites

*crickets* Well, that question must of been too obscure. I'll come back to that, but first help me clear up GUI command "runscript", that could appear in an event handler code block.

I'm going to claim, despite some engine C++ code to parse it, that - on purpose - this command no longer works in TDM. In either form, "runscript ..." or "set 'cmd' runscript...".

If you know about this, please either agree with that claim, or provide a counter-example, such as a working test map or a pointer to an FM that successfully has a GUI file that uses runscript. Thanks!

Link to comment
Share on other sites

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.   Paste as plain text instead

  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.

  • Recent Status Updates

    • Ansome

      Turns out my 15th anniversary mission idea has already been done once or twice before! I've been beaten to the punch once again, but I suppose that's to be expected when there's over 170 FMs out there, eh? I'm not complaining though, I love learning new tricks and taking inspiration from past FMs. Best of luck on your own fan missions!
      · 4 replies
    • The Black Arrow

      I wanna play Doom 3, but fhDoom has much better features than dhewm3, yet fhDoom is old, outdated and probably not supported. Damn!
      Makes me think that TDM engine for Doom 3 itself would actually be perfect.
      · 6 replies
    • Petike the Taffer

      Maybe a bit of advice ? In the FM series I'm preparing, the two main characters have the given names Toby and Agnes (it's the protagonist and deuteragonist, respectively), I've been toying with the idea of giving them family names as well, since many of the FM series have named protagonists who have surnames. Toby's from a family who were usually farriers, though he eventually wound up working as a cobbler (this serves as a daylight "front" for his night time thieving). Would it make sense if the man's popularly accepted family name was Farrier ? It's an existing, though less common English surname, and it directly refers to the profession practiced by his relatives. Your suggestions ?
      · 9 replies
    • nbohr1more

      Looks like the "Reverse April Fools" releases were too well hidden. Darkfate still hasn't acknowledge all the new releases. Did you play any of the new April Fools missions?
      · 5 replies
    • The Black Arrow

      Hope everyone has the blessing of undying motivation for "The Dark Mod 15th Anniversary Contest". Can't wait to see the many magnificent missions you all may have planned. Good luck, with an Ace!
      · 0 replies
×
×
  • Create New...