Changing Glulx Status Line (Issues with Time)

Greetings all! I’m curious if there are any materials out there regarding using Inform 6 and changing the status line when your game is compiled to Glulx.

I might be missing it but I can’t even find an example of changing the status line to just show the time, as just one example. The exercises in §42 of the DM4 are great – but I realized they only apply if you are working with zcode, particularly the one about showing the exits and a sort of map.

I tried looking up games with source code on IFDB, but I need a game that (1) changes the status line, (2) is Inform 6 and (3) compiles to Glulx. I haven’t found much of that but my search-fu might be bad as well.

I found The Game Author’s Guide to Glulx Inform and in there it says: “If you write your own DrawStatusLine() procedure, using Z-code assembly, you will have to rewrite it using Glk calls. (See the bi-platform library for sample code.)” I wasn’t really sure where to go with that.

The best I’ve been able to come up with by futzing around is doing something like this:

[ DrawStatusLine;
   glk_set_window(gg_statuswin);
   glk_window_clear(gg_statuswin);
   glk_window_move_cursor(gg_statuswin, 0, 0);
   print "Testing";
   glk_set_window(gg_mainwin);
];

Is that the general idea?

Do you mean you want it to show only the time, i.e. not even the location name?

The “bi-platform library” means the version of the Inform 6 library that Zarf made when he created Glulx. All those changes have been long folded into the Inform 6 library proper. If you search the Inform 6 library you’ll find DrawStatusLine (in parserm.h) so you can see how the default one works, so the usual approach is to copy that and modify it to what you want. But yes, your simple version is the basic idea of it: set the current Glk window to the status window and print something.

2 Likes

Good question! I definitely want to show the time, but, yeah, ideally, keep the location name. I was then going to refine that to show exits as well. (That’s when I stumbled upon the material in the DM4, but I realized none of it would work in this context.)

To just show location name and time, I think you can do:

Statusline time;

Got it! Okay, I see the method with this signature:

[ DrawStatusLine width posa posb posc posd pose;

This is the one that targets Glulx. So it sounds like I do a Replace DrawStatusLine, copy that existing DrawStatusLine in my own source, but modify it. Specifically, that would mean, in one case, taking the solution to exercise 126 in the DM4 and replacing the opcodes with whatever Glulx needs. It might be, for example, that @set_cursor is now MoveCursor, if I’m reading it correctly.

I think I have my next path for experimentation. Much thanks!

(I would have honestly just stayed with zcode for this but the one element I absolutely need from Glulx is @protect, hence all this other experimenting.)

I did see that in the DM4 and I tried it, but when I do that my time always shows as this:

Time: 12:0-1 am 

And it never seems to increment. I thought it might be a Glulx thing so I tried going back to z5 and when I use that above statement in a z5 game, the same thing happens.

1 Like

Well that seems broken.

I just tried adding Statusline time; to one of my Glulx games and can confirm that the time in the status line is stuffed, as you reported, and the time doesn’t change.

Much weirdness. I thought it might be the library I was on so I tried with 6.12.6, 6.12.5 and 6.12.1. The problem happens with each. Then I thought it be the compiler version of Inform 6. So I went from 6.43 to 6.42 but I have the same issue.

I tried, in all cases, compiling with Glulx and compiling to z5. It actually happens with any use of time. For example, I replaced the DrawStatusLine with the following (it’s ugly; I was just doing the minimal to get my own time in place):

[ DrawStatusLine width posa posb posc posd pose;
    #Ifdef TARGET_GLULX;
    if (gg_statuswin == 0)
        return;
    #Endif;

    if (location == nothing || parent(player) == nothing)
        return;

    StatusLineHeight(gg_statuswin_size);
    MoveCursor(1, 1);

    width = ScreenWidth();
    posa = width-26;	! For standard move/score display.
    posb = width-13;
    posc = width-5;

    posd = width-19;	! For time display.
    pose = width-14;

    spaces width;

    MoveCursor(1, 2);
    if (location == thedark) {
        print (name) location;
    }
    else {
        FindVisibilityLevels();
        if (visibility_ceiling == location)
            print (name) location;
        else
            print (The) visibility_ceiling;
    }
    if (sys_statusline_flag) {
	if (width > 29) {
	    if (width > 39)
		MoveCursor(1, posd);
	    else
		MoveCursor(1, pose);
	    print (string) TIME__TX;
	    LanguageTimeOfDay(sline1, sline2);
	} else
	    jump DSLContinue;
    } else {
        if (width > 66) {
            #Ifndef NO_SCORE;
            MoveCursor(1, posa);
            ! print (string) SCORE__TX, sline1;
            ! print (PrintTime) the_time;
            #Endif;
            MoveCursor(1, posb);
            ! print (string) MOVES__TX, sline2;
            print (PrintTime) the_time;
        }
	if (width > 53 && width <= 66) {
	    MoveCursor(1, posb);
	    #Ifdef NO_SCORE;
	    ! print (string) MOVES__TX, sline2;
      ! print (PrintTime) the_time;
	    #Ifnot;
	    ! print sline1, "/", sline2;
      print (PrintTime) the_time;
	    #Endif;
	}
	if (width < 53) {
	   MoveCursor(1, posc);
	   #Ifdef NO_SCORE;
	   ! print (string) MOVES_S__TX, sline2;
     ! print (PrintTime) the_time;
	   #Ifnot;
	   ! print sline1, "/", sline2;
     print (PrintTime) the_time;
	   #Endif;
	}
    }
    .DSLContinue;
    MainWindow(); ! set_window
];

The PrintTime is a function I have defined that looks like this:

[PrintTime t;
    print (t/720), ":", ((t/12)%60)/10, (t/12)%10, ":", ((t%12)/2);
    if ((t%2) == 0)
       print "0";
    else
       print "5"; 

    if (t/(720*12) == 0)
        print " am";
    else
        print " pm";
];

When I run that, the time does show up differently (0:00:05 am) but similarly doesn’t increment at all. The same applies if I try this with a zcode version:

[ DrawStatusLine width pos;

 ! @split_window 0; 
 ! return; 
  
  @split_window 1;
  @set_window 1; 
  @set_cursor 1 1; 
  style reverse; 
  width = 0->33; 
  pos = width-20; 
  spaces (width); 

  @set_cursor 1 2; 
  PrintShortName(location);
   
  @set_cursor 1 pos; 
  print (PrintTime) the_time; 

  @set_cursor 1 1; 
  style roman; 
  @set_window 0; 
]; 

As the DM4 states on page 150:

It’s usual for a timed game to start off the clock by calling SetTime in its Initialise routine.

Given the way that the Standard Library code works (i.e. no default time setting), it should probably say “It’s required for a timed game…”

You just need to add:

SetTime(540, 1);	! 9:00A with 1 minute per turn

or similar to your Initialise() routine.

Got it! Good catch. That does help set the time, although I find it still doesn’t increment. Digging into DM4 a bit more in case I missed other details.

The SetTime() library feature is not much used. Its functionality might have gotten lost (out of the library, I mean) over the years.

Oops, the second parameter for SetTime() is also required. I’ve updated my answer above.

Got it. That indeed, does the trick. Okay, so at the end of this I think I do have something working. I’ve got a very minimal status line that just shows the time and increments appropriately.

Perfect!

My next experiment is going to be that answer to example 126 in the manual incorporated.

Thank you to everyone for your help!

1 Like

@DavidG:

It seems like there should probably be an adjustment to routine LanguageTimeOfDay() in english.h, which is currently:

[ LanguageTimeOfDay hours mins i;
	i = hours%12;
	if (i == 0) i = 12;
	if (i < 10) print " ";
	print i, ":", mins/10, mins%10;
	if ((hours/12) > 0) print " pm"; else print " am";
];

It’s not prepared for a situation where the arguments that it’s fed (in this case, 0 for hours and -1 for mins) are invalid.

Maybe

[ LanguageTimeOfDay hours mins i;
	if (mins < 0) { print "(unset)"; rfalse; }
	i = hours%12;
	if (i == 0) i = 12;
	if (i < 10) print " ";
	print i, ":", mins/10, mins%10;
	if ((hours/12) > 0) print " pm"; else print " am";
];

or similar?

1 Like

Cutthroats utilizes the fact that the time statusline code in Infocom’s Z-code interpreters doesn’t do bounds-checking for the time - if you take off your watch, the game sets the time to a special value which makes the statusline say 99:99.

Possibly, one wants the statusline in the Inform 6 library to mimic this.

1 Like

Anybody who wanted to do something like that would have to do some tinkering, anyway.

This routine is the one that produces the “12:0-1 am” output noted above when the Statusline time; directive is given without also using SetTime(). It’s not capable of producing “99:99” as an output, both because of the modulo 12 operation on the hours parameter and because of its automatic inclusion of am/pm.

The routine is used by DrawStatusLine():

[ DrawStatusLine width posa posb posc posd pose;
	...
	if (sys_statusline_flag) {
	    if (width > 29) {
	        if (width > 39)
	            MoveCursor(1, posd);
	        else
	            MoveCursor(1, pose);
	        print (string) TIME__TX;
	        LanguageTimeOfDay(sline1, sline2);	 ! <-- HERE
	    } ...
];

with the globals used as arguments previously having been set by a routine DisplayStatus() to the hours and minutes parts of the_time.

Since “12:0-1 am” is utterly opaque, it makes sense for the state causing it to be handled in a way that suggests the necessary action on the part of the author. There’s really no scenario in which a negative value for the mins argument will be handled well by the current routine.

2 Likes

Infocom’s Cutthroats uses 111:99 as a sentinel value for “you’re not carrying the watch”, which would display as 99:99 on the interpreters at the time (since they’d just subtract 12 from any hours number above 12 rather than doing a modulo operation). It seems reasonable to use the same sentinel value and/or same display for it in the Inform library, if we need to choose one.

This issue is not reflective of the PC not carrying a watch, i.e. not being able to tell the current time of day. It’s reflective of there being no time of day since the_time is still set to its initialization value of -1.