Roger Firth's IF pages

Home

Just Enough Glulx

Email
Back up

You're a reasonably experienced Inform programmer; you can find your way around the Inform Designer's Manual without difficulty, and you've a fair idea what most of the Library functions are for. All in all, you're a happy bunny.

Except, that is, for this Glulx thing, where you can't help feeling a bit uneasy about your ignorance. You've glanced at the introductory material from Adam, from Doe, from Emily and from Zarf (especially his Game Author's Guide for Glulx Inform), and you can see there's a hell of a lot of potential. Trouble is, there's also a hell of a lot of new stuff to take on board. New stuff which you don't really need... right now.

And yet... maybe your game is a big one, sure to outgrow Version 8 capacity sooner or later; maybe you can see the scope for including sounds or images at some future date; maybe you simply like working at the cutting edge, trying out new stuff Just Because It's There. For any of those reasons, you fancy dipping a toe in the Glulx shallows, sampling the basics without a heavy learning curve. What you want is Just Enough Glulx.

The bi-platform Glulx compiler has two modes: Inform (without the -G switch) which compiles for the Z-machine, and Glulx (with the -G switch) which compiles for the Glulx Virtual Machine. In Inform mode, all of your valid Inform code should compile (or it's a bug and Zarf would like to hear from you) and run in a Z-code interpreter. In Glulx mode, most of your Inform code will compile without change and run in a Glulx interpreter, except where you have:

This page is all about helping you to overcome those problems. The solution on offer is pretty straightforward: a header file JustEnoughGlulx.h which you can download here and #Include at the head of your game, right after you #Include Parser.h. The header file defines some constants and routines which you use in your game in place of the problematic constructs. These routines mask the differences between Inform and Glulx; they work the same way -- the Z-machine way -- for both VMs.

Not that this will necessarily solve all your difficulties: if you've gone beyond the most elementary use of assembly language, for example by crafting a new DrawStatusLine() routine, or by inventing a menu system that knows all about windows, or using Version 6 capabilities, you're on your own. In cases like these, you'll need to learn a bit about the Glk I/O Library (and maybe the Glulx assembly language), and then write separate code for Inform and for Glulx. All that JustEnoughGlulx.h provides are simple standard solutions for the simple standard situations.

ZARF HEALTH WARNING. In making things simple, there's a danger of dumbing-down, of obscuring the power of Glulx behind JustEnoughGlulx's lightweight facade. All of this stuff assumes that your primary target is (currently) the Z-machine, with the ability to run on the Glulx VM as a bonus -- nice work if you can get it, as it were. If your target is Glulx from the outset, you're probably better off ignoring JustEnoughGlulx.h, and getting straight to grips with the full potential of Glulx.

OK? Right: once you've made the changes described below, you should be able to compile and run your game in both Z-machine and Glulx interpreters.

If you want to do this ...

And you'd normally write ...

Write this instead ...

Bring this good stuff into your game:

Include "Parser";

Include "Parser";
Include "JustEnoughGlulx";

Avoid the "two bytes to a word" assumption, most commonly found when using the .# property array size operator:

word_count = obj.#prop/2

word_count = obj.#prop/WORDSIZE

Output in embolded, underlined/italicised, or reversed text:

style bold;
  print ...
    style roman;

style underline;
  print ...
    style roman;

style reverse;
  print ...
    style roman;

bp_style(bp_style_Bold);
  print ...
    bp_style(bp_style_Roman);

bp_style(bp_style_Underline);
  print ...
    bp_style(bp_style_Roman);

bp_style(bp_style_Reverse);
  print ...
    bp_style(bp_style_Roman);

Write to the first word/byte of a table/string array -- the 'size' elements -- using assembly language (because table_array-->0=value; and string_array->0=value; cause compiler errors in Strict mode):

@storew table_array offset value;

@storeb string_array offset value;

bp_storew(table_array,offset,value);

bp_storeb(string_array,offset,value);

Switch the input stream to read from a file, typically because you're implementing your own REPLAY verb:

@input_stream 1;

bp_input_stream(1);

Switch the output stream to write to a file, typically because you're implementing your own SCRIPT ON|OFF and COMMANDS ON|OFF verbs:

@output_stream 2;    ! transcript
  ...
    @output_stream -2;

@output_stream 4;    ! commands
  ...
    @output_stream -4;

bp_output_stream(2);
  ...
    bp_output_stream(-2);

bp_output_stream(4);
  ...
    bp_output_stream(-4);

Switch the output stream to write to an array in memory, typically because you want to count characters or post-process the text. The number of characters written is returned in the word at array-->0, and the characters themselves are in the bytes starting at array->WORDSIZE; note that the array must be big enough to hold max+WORDSIZE bytes:

@output_stream 3 array;
  print ...
    @output_stream -3

bp_output_stream(3,array,max);
  print ...
    bp_output_stream(-3);

Select the upper (status) or lower (game text) window:

@set_window 1;    ! upper

@set_window 0;    ! lower

bp_set_window(1);

bp_set_window(0);

Position the cursor in the upper (status) window:

@set_cursor line column;

bp_set_cursor(line,column);

Clear the upper (status) or lower (game text) window, or the entire screen:

@erase_window 1;    ! upper

@erase_window 0;    ! lower

@erase_window -1;   ! screen

bp_erase_window(1);

bp_erase_window(0);

bp_erase_window(-1);

Emit a simple high- or low-pitched beep:

@sound_effect 1;    ! high

@sound_effect 2;    ! low

bp_sound_effect(1);

bp_sound_effect(2);

Wait for a key to be pressed and return its ZSCII value:

@read_char 1 -> key_code;

key_code = bp_read_char();

Fetch the screen width and height:

width = 0->$21;
height = 0->$20;

width = bp_window_get_width(1);    ! upper
height = bp_window_get_height(1);

width = bp_window_get_width(0);    ! lower
height = bp_window_get_height(0);

Do something more advanced, not covered by these routines:

code_for_Z-machine

#ifdef TARGET_ZCODE;
    code_for_Z-machine
#ifnot;    ! TARGET_GLULX;
    code_for_Glulx
#endif;    ! TARGET_

 
 

 
 

 
 

Finally, a few optional extras, provided just for convenience. Bear in mind that both bp_Graphic() and bp_Sound() trade off flexibility for simplicity -- you can be much cleverer than this if you master the underlying Glk functionality.

Here are three print rules producing output in embolded, underlined/italicised, or reversed text:

print ..., (bp_B) "string", ... ;

print ..., (bp_U) "string", ... ;

print ..., (bp_R) "string", ... ;

Display in the text window the image whose number is image. Optionally, offset it by number spaces from the left margin. If the operation fails or is unsupported, output a warning message (which can be suppressed by setting bp_GraphicSoundWarning = false).

bp_Graphic(image,number);

Play the sound whose number is sound. Play it number times (normally 1). If number is -1, play the sound continuously; if it is 0, stop playing the current sound. If the operation fails or is unsupported, output a warning message (which can be suppressed by setting bp_GraphicSoundWarning = false).

bp_Sound(sound,number);

Notes:

  1. JustEnoughGlulx.h automatically #Includes John Cater's infglk.h, so a copy of that is bundled in the zip file.
  2. In order to understand infglk.h, you really need to study the Glk Specification. When you do so, bear in mind that the NULL value it talks about is the C language NULL (0), not the Inform Library NULL (-1). infglk.h defines a constant GLK_NULL (equal to 0) which you can use where appropriate.
  3. Also in JustEnoughGlulx.zip you'll find a couple of sound files, used for the two sound effects in Glulx mode. You can replace these with other sounds of your own choosing, keeping the filenames unchanged.
  4. If you're writing a bi-platform Library package, you can #Include JustEnoughGlulx.h in that as well.
  5. Here's some additional information on character sets.
  6. And here's some more information on sound and graphic resources.

Finally, as a proof-of-concept, you can download a version of the DM4 example game "Ruins.inf" incorporating JustEnoughGlulx modifications which enable it to compile and run on both VMs.