Status lines

One of the most common uses of Z-assembly in Inform games is to create customized status lines. This won't work in Glulx Inform, since it doesn't recognize Z-assembly. Instead, you should use the Glk equivalents -- which are not raw opcodes but rather routines like any other.

The status line is such an IF tradition that it actually takes some effort to dispense with it. A standard Inform game will split off a portion of the screen to list the room the player character is in, the player's current score, and the number of moves made. To change this, the programmer must insert the line "Replace DrawStatusLine;" at the beginning of the program (putting it right after the list of constants works as well as anywhere.) Then the programmer must provide an alternate DrawStatusLine() routine. But here's where things diverge a bit.

In standard Inform, the command to create the status line window (@split_window) occurs within the library's DrawStatusLine() routine. If you want to replace it, you have to put in the @split_window command yourself. If you want to eliminate it, all you need to do is replace DrawStatusLine() with a dummy routine, like so:

   [ DrawStatusLine; ];

That's not enough in Glulx Inform. In the Glulx section of the bi-platform library, the status window is split off in GGInitialise(), not DrawStatusLine(). This means that if you just use a dummy DrawStatusLine(), the status line will be blank, but the window will still hang around, mocking you. So you also have to intercept the command to create the status window using the InitGlkWindow() entry point, like so:

[ InitGlkWindow winrock;
   switch (winrock) {
      GG_STATUSWIN_ROCK: rtrue;
   rfalse; ! leaving out this line will lead to a messy crash! 

If you do want to keep the status line around but want to provide your own instructions for it, there are some guidelines to follow. First off, if you want to allocate more than one line to the status window, say so in InitGlkWindow(), like so:

[ InitGlkWindow winrock;
   switch (winrock) {
         gg_statuswin_size = 2; ! or however many lines you want
   rfalse; ! leaving out this line will lead to a messy crash! 

Next, write a replacement DrawStatusLine() routine, beginning with the following code:

   ! If we have no status window, we must not try to redraw it.
   if (gg_statuswin == 0)

   ! If there is no player location, we shouldn't try either.
   if (location == nothing || parent(player) == nothing)

The first line after that should be "glk_set_window(gg_statuswin);", to set the window where you're going to be printing status line stuff, and the last line should be "glk_set_window(gg_mainwin);", to make sure that the program continues to put story text in the right place. In between, you can print whatever you'd like, though the process is slightly different from in a text buffer window.

Remember that a text grid window is sort of like a Scrabble board: though the borders between boxes aren't visible, the window consists of a grid of boxes, each of which can hold one character -- letters, numbers, or punctuation. Each box has a pair of coordinates associated with it, an X-coordinate and a Y-coordinate. The X-coordinate is how many boxes away the current box is from the left edge of the window; the X-coordinate of boxes on the left edge is 0. The Y-coordinate is how many boxes away the current box is from the top edge; the Y-coordinate of boxes on the top edge is 0. (This is different from regular Inform, where the top left corner is not (0,0), but (1,1).) To select a place to begin printing, use the command glk_window_move_cursor(), which takes three arguments: the name of the window to be printed to, the X-coordinate of the box to begin printing in, and the Y-coordinate of the box to begin printing in. As you print, the cursor will be moved along automatically -- no need to move it yourself just to print the next letter of a word. So the following code:

   glk_window_move_cursor(gg_statuswin, 3, 0);
   print "Time: ";

will place the letter "T" in location (3,0), "i" at (4,0), "m" at (5,0), "e" at (6,0), a colon at (7,0) and a space at (8,0), leaving the cursor at (9,0). Presumably next would come some code to print the current time.

One thing to take into account is that not everyone playing your game will have the same amount of screen space allocated to Glulxe: the status line window might be 120 characters long on one person's machine, and 40 on another. Or someone might resize their Glulxe window from 120 characters wide to 40 in the middle of playing the game. You can, however, put code in DrawStatusLine() to adjust for this (as, indeed, the default routine already does.) Simply stick variables named "width" and "height" in your DrawStatusLine() declaration, and insert the following snippet of code in the routine:

   glk_window_get_size(gg_statuswin, gg_arguments, gg_arguments+4);
   width = gg_arguments-->0;
   height = gg_arguments-->1;

Then you can make whatever adjustments you deem appropriate. Let's say you're working on a game called Crunch, Crumple and Stomp and you want to stick a hunger indicator in the status line beginning at column 40 that'd display either "FULL", "PECKISH", "FAMISHED" or "RAVENOUS". This could take you up to column 47. Some people will be playing with less than 48 columns, though, so you only want this to appear if they have enough space (since you certainly don't want the indicator to be cut off in mid-word.) Simply use code like the following:

   if (width > 48) { ! we'll mandate at least some clearance
      glk_window_move_cursor(gg_statuswin, 40, 0);
      switch (gojira.hunger) {
         0: print "FULL";     
         1: print "PECKISH";  
         2: print "FAMISHED"; 
         3: print "RAVENOUS"; 

Note that the possibilities above are of different lengths. If you try to overwrite "RAVENOUS" with "FULL", you'll end up with "FULLNOUS" unless you either pad each possibility out with spaces so they're all the same length, or stick a "glk_window_clear(gg_statuswin);" line right after your "glk_set_window(gg_statuswin);" call. The library uses the latter method.

Cleverer accommodations are possible than just not displaying items that don't fit -- we could have put in some elaborate code to abbreviate things as the status line gets smaller, for instance. The nice thing is that since DrawStatusLine() is called every turn, you don't need to fiddle with HandleGlkEvent() to deal with resizes, as you do for graphics. More about this in the next few sections.

Next section: Displaying PNG and JPEG images
Or return to the table of contents