Glulx Input Loops

version 1/101121 by Erik Temple

  • Home page
  • Beginning
  • Previous



  • Example: *** Under Doom - The primary intention of this example is to demonstrate the use of a secondary input loop (running within the main input loop). It also shows how to reconfigure the main input loop to use character (single-keystroke) input rather than the default line input, how to use the input loop setup rules, and how to create and use new input loops.

    The example completely alters the method by which commands are entered into the game. Instead of typing out our commands, we simply enter a single key for the verb: the entire verb word will appear on the command line as if we had typed it. If the command also requires a noun, we enter a secondary loop (we use the "character input" input-loop object for this purpose), where we can hit another keystroke to indicate the noun and complete the command. The available verbs are displayed in a commands window off to the right so that we know what keys to enter (this window switches to display the nouns when we enter the secondary loop).

    The commands are processed by Inform's parser as normal, so this example really only alters input--everything else about the "game" follows standard conventions. Of course, since we are limited to verb or verb + noun input, the resulting game is considerably less capable than Inform's parser. We could, though, relatively easily expand the input scheme to allow for more complex input.

    If you want to see exactly how the input loops interact, activate the input loop debugging use option (paste link at bottom of example; note that all of the preceding paste blocks need to be added to your code in order to compile the example.)

        "Under Doom" by Erik Temple
        
        [Use input loop debugging.]
        
        Section - Inclusions
        
        Include Flexible Windows by Jon Ingold.
        Include Basic Screen Effects by Emily Short.
        Include Glulx Input Loops by Erik Temple.
        
        Section - The commands window
        
        The commands-window is a text-buffer g-window spawned by the main-window. The position is g-placeright. The measurement is 25.

        Section - Introduction
        
        When play begins:
            try getting help;
            say "[line break]Press any key.";
            wait for any key;
            clear the screen;
            open up the commands-window.

    Here we reassign the focal event type of the main input loop object, so that it handles character input instead of line input. We also use the input loop setup rule as a convenient hook on which to hang the commands window refresh, since we know it will be called every time we're ready for input. (Another perfectly good hook would be in "before handling the input looping activity with main input" activity.)
        
        Section - Main input loop setup
        
        The focal event type of main input is char-event.
        
        An input loop setup rule for a char-event when the current input loop is main input:
            now key-verb is "Commands";
            display the Table of Keystroke Commands in the commands-window;
            say "[run paragraph on]".


    In this section, we actually handle all of the main input. After declaring a few global variables to hold the player's input and the verb word it translates to, we define the main input-handling rule for the main input loop (this is the "main char input handling rule"). This rule compares the character input to the Table of Keystroke Commands. If the player's (case-sensitive) keypress is found in the table, the player's command is changed to the corresponding verb word(s), which are also printed to the command line. If the "stage" entry in the table contains a 0, this indicates that the command is complete in itself and we stop input processing to parse the command.

    Otherwise, we need to get a noun from the player to complete the command. A table of nouns (the Table of Visible Objects) is constructed, including all objects in scope, and this table is then displayed in the commands window to prompt the player for a second input. We then invoke the "second phrase input" loop, which will run as a secondary loop and accept the keypress input for the noun part of the command. From the event-handling rule in this loop, we check the Table of Visible Objects (again, built dynamically) instead of the Table of Keystroke Commands, but the basic process is the same.

    One thing of note in this "secondary char input handling rule" is the test for a character code returned of -8; this code results from pressing the Escape (ESC) key. If the player presses ESC, we abort the command, setting a truth state variable ("secondary input escaped") that will serve to inform the main char input handling rule that input in the secondary input loop was aborted.

        Section - Handling core input
        
        The key-verb is an indexed text variable.
        
        Secondary input escaped is a truth state variable.
        
        First glulx input handling rule for a char-event:
            unless the number of characters in the player's command is 0:
                replace player input.
        
        An input loop event-handling rule for a char-event when the current input loop is main input (this is the main char input handling rule):
            change the text of the player's command to "";
            if there is a key of keystroke in the Table of Keystroke Commands:
                choose row with key of keystroke in the Table of Keystroke Commands;
                if stage entry is 0:
                    say "[input-style-for-glulx][command entry][roman type]";
                    change the text of the player's command to "[command entry]";
                    stop input loop processing;
                otherwise:
                    say "[input-style-for-glulx][command entry][roman type] [run paragraph on]";
                    now the key-verb is command entry;
                    create table of local objects;
                    display the Table of Visible Objects in commands-window;
                    process second phrase input loop;
                    if secondary input escaped is true:
                        now secondary input escaped is false;
                        continue input loop processing;
                    otherwise:
                        stop input loop processing;
            otherwise:
                continue input loop processing.

        Second phrase input is an input-loop. The focal event type is char-event.
        
        Input loop event-handling rule for a char-event when the current input loop is second phrase input (this is the secondary char input handling rule):
            now secondary input escaped is false;
            if keystroke-code is -8:
                cancel the command;
                stop input loop processing;
            if keystroke-code is the null char, continue input loop processing;
            repeat through Table of Visible Objects:
                if key entry is keystroke:
                    say "[input-style-for-glulx][command entry][roman type]";
                    change the text of the player's command to "[key-verb] [command entry]";
                    stop input loop processing;
            continue input loop processing.

        To cancel the command:
            say "[line break]--Action canceled.[paragraph break][command prompt][run paragraph on]";
            now secondary input escaped is true.


    The cancel secondary input on alternate input rule isn't really necessary for this example, but if our game had alternate sources of input or other events--such as hyperlinks or timed events--then we would need to define behavior for those events during the special secondary loop. This rule shows how to halt the noun input when an event other than a keypress is received. (Note that we do nothing for an arrange or redraw event, neither of which have any direct impact on gameplay.)

        First input loop event-handling when the current input loop is second phrase input and the current glk event is not char-event (this is the cancel secondary input on alternate input rule):
            unless the current glk event is arrange-event or current glk event is redraw-event:
                cancel the command;
                stop input loop processing;
        
        Section - Verb ("command") input
        
        Table of Keystroke Commands
      key (indexed text)  command (indexed text)  stage  
      "x"  "more about"  1  
      "l"  "look"  0  
      "t"  "take"  1  
      "D"  "drop"  1  
      "W"  "wear"  1  
      "n"  "go north"  0  
      "e"  "go east"  0  
      "w"  "go west"  0  
      "s"  "go south"  0  
      "u"  "go up"  0  
      "d"  "go down"  0  
      "i"  "take inventory"  0  
      "h"  "help"  0  
      "q"  "quit"  0  
        
        Section - Create list of objects for noun input
        
        To create table of local objects:
            blank out the whole of the Table of Visible Objects;
            let count be 1;
            repeat with item running through things:
                if the player can see the item:
                    choose a blank row in the Table of Visible Objects;
                    now the key entry is "[char-code (count + 47)]";
                    if item is yourself:
                        now the command entry is "myself";
                    otherwise:
                        now the command entry is "[the item]";
                    increase count by 1;
            choose a blank row in the Table of Visible Objects;
            now the key entry is "ESC";
            now the command entry is "Cancel".
        
        Table of Visible Objects
      key (indexed text)  command (indexed text)  
      --  --  
      with 40 blank rows  
        
        To display (T - a table name) in (win - a g-window):
            let max be the number of filled rows in T;
            let count be 1;
            move focus to commands-window, clearing the window;
            say "[bold type][key-verb]:[roman type][line break]";
            repeat through T:
                say "[key entry] - [command entry][line break]";
                increase count by 1;
            return to main screen.


    We implement the yes-no clarification for quitting the game using the "character input" input-loop. Rather than use the "wait for any key" phrase, however, we check the result of the input loop and take action only if the keypress is "y/Y" or "n/N". In a real game, we'd probably want to write the yes-no logic as reusable code, but this will do for the example.
        
        Section - Handling Quitters
        
        Carry out quitting the game:
            say "Are you sure you want to quit?";
            move focus to commands-window, clearing the window;
            say "[bold type]Quit?[roman type][line break]y - quit[line break]n - continue playing";
            return to main screen;
            now keystroke is "";
            while keystroke is not "y" and keystroke is not "Y" and keystroke is not "n" and keystroke is not "N":
                process the character input loop;
                if keystroke is "Y" or keystroke is "y":
                    say "[input-style-for-glulx][keystroke][roman type][paragraph break]Exiting...";
                    shut down the commands-window;
                    abide by the immediately quit rule;
                if keystroke is "N" or keystroke is "n":
                    say "[input-style-for-glulx][keystroke][roman type][line break]";
                    rule succeeds.
        
        Section - Commands
        
        Getting help is an action out of world applying to nothing. Understand "help" as getting help.
        
        Carry out getting help:
            say "This example uses the Glulx Input Loops extension to provide a keystroke interface rather than the standard text input. Type single characters to fill in words and phrases. The commands available at any given time, along with the keystrokes needed to invoke them, can be found in the window at the right."
        
        Understand "more about [something]" as examining.
        
        Section - "Scenario"
        
        Tunnel is a room. "The tunnel slopes down to the west, farther into the mountain. A reddish glow stains the bottom, and the air shimmers with the heat."
        
        Instead of going east in Tunnel:
            say "Turn back now? No."
        
        Instead of going down in the Tunnel:
            try going west.
        
        The ring is a wearable thing in the Tunnel. The description of the ring is "A simple gold ring."
        
        Instead of wearing the ring:
            say "No, you won't wear it; it drove him insane. All you need is to drop it into the flames at the heart of the mountain."
        
        At the Edge is west of the Tunnel. "The tunnel opens onto a wide ledge. Surrounding the ledge is a lake of fire, the heart of the volcano."
        
        Report dropping the ring in the Edge:
            say "You pitch the ring into the heaving pool of lava. A spark and a hiss, then an explosive concussion that shakes the very walls.[paragraph break]*** You have destroyed it ***";
            say "[paragraph break]Exiting...";
            shut down the commands-window;
            abide by the immediately quit rule;
        
        The description of yourself is "Tired, hungry, in need of a warm meal and a cold tankard."
        

    This last paste block is optional. Include it if you want to see a blow-by-blow of the input loop flow.
        
        Use input loop debugging.