Inform FAQ

By Gareth Rees, 1994-1995. Some of these questions and answers appeared in the second edition of the Designer's Manual, generally with slightly longer answers.

Questions

  1. How can you put a compass rose on the statusline, showing the available exits? Answer
  2. How can I make some verbs (e.g. lock) choose default objects in sensible cases (e.g. if the player is carrying exactly one key) but to ask for disambiguation in other cases? Answer
  3. How can I present the player with a Restore prompt before the start of the game? Answer
  4. How can the player follow something after it has gone somewhere else? Answer
  5. Can I overwrite a property that's a routine in the same way I would overwrite an ordinary property? Answer
  6. I'd like to have lots of descriptive scenery in my game, but I'm tired of typing in all those dummy scenery objects. Is there a better way to provide these descriptions? Answer
  7. How can I make a single object be both a supporter and a container? Answer
  8. How can I make a creature's possessions visible to the player? Answer
  9. How can I make other characters in my game move around the landscape, go through doors and so on? Answer
  10. How can I parse topics that are looked up in books or asked of characters? Answer
  11. Is it possible to save a character in one game and restore that character to play in another? Answer
  12. I have an object that appears in several places (using the found_in property), but which is absent to start with. My code executes give object ~absent, but the object fails to appear. Why? Answer
  13. How can I arrange that the command person, yes has the same effect as say yes to person (recall that yes is a verb)? Answer
  14. Two rooms have a glass window separating them. How can I implement this? Answer
  15. How can I read input from the keyboard without waiting for the return key to be pressed? How can I animate some display so that the timings will be the same on different computers? Answer
  16. What's the right way to have quotes in boxes appearing in the game? I know how to use the box directive, but when the prompt is printed, the quote scrolls off the top of the screen. Answer

Answers

  1. How can I put a compass rose on the statusline, showing the available exits?

    Joachim Baumann proposed a solution using an enlarged status line and an ASCII graphic compass rose. You can see this in action in the example game Compass Rose.

  2. How can I make some verbs (e.g. lock) choose default objects in sensible cases (e.g. if the player is carrying exactly one key) but to ask for disambiguation in other cases?

    The trick is to have an extra line of grammar that chooses a default object if possible, and to let the usual line of grammar do the disambiguation. Thus one could declare

         Extend "lock" first
             * noun = DefaultLockTest -> DefaultLock;
    
    where the usual grammar line for "lock" is
             * noun "with" held -> Lock
    
    The routine DefaultLockTest checks to see if a default object can be chosen (in this case, if the player is carrying exactly one key); if so, it returns success, and if not, it returns failure (whereupon the usual line of grammar will take effect, and ask What do you want to lock that with?). The routine DefaultLock actually chooses the default object and then executes a Lock action.

    You can see this in action in the example game Padlock and the library LockTest.

  3. How can I present the player with a Restore prompt before the start of the game?

    Teo Kwang Liak (July 1994) suggested the following:

    [ Initialise;
        location = Start_Room;
        print "Would you like to restore a game? >";
        if (YesOrNo()==1)
            <Restore>;
        print "^^^^Introductory text^^";
    ];
    
  4. How can the player follow something after it has gone somewhere else?

    This is what scope rules were designed for! We can declare a verb with a modified scope, as follows:

        Verb "follow" "chase" "pursue" "trail"
            * scope=FollowScope -> Follow;
    
    You need to declare a property that represents the room most recently visited by an object, and then the routine FollowScope puts into scope all those objects whose most recently visisted room is equal to the current location. (It also puts into scope all the usual objects, so that it can reply You can't follow that, it's right here with you! or some such).

    You can see this in action in the example games Follow my leader and The Thief, and packaged up as Andrew Clover's follower library.

  5. Can I overwrite a property that's a routine in the same way I would overwrite an ordinary property?

    Yes; a routine is just stored as a number (representing a Z-machine address), so you can change it to whatever you like. It is probably best to either set it to be the address of a routine:

         Troll.life = #r$SleepingTrollLife;
    
    or to get rid of it altogether by setting it to the special number NULL. The Carousel room from Zork II might have made use of this, if it had been written in Inform.

  6. I'd like to have lots of descriptive scenery in my game, but I'm tired of typing in all those dummy scenery objects. Is there a better way to provide these descriptions?

    Richard Barnett (richard@wg.icl.co.uk), January 1995, writes:

    Graham's Inform library provides for scenery non-objects - nouns which don't correspond to objects, but are recognized by the parser as referring to irrelevant and non-manipulatable objects. A room's name property holds the list of such nouns; attempts to manipulate or examine them produces the message:

    That's not something you need to refer to in the course of this game.
    You can also have objects which have the scenery attribute set. These are proper objects in every way - they can have before and after routines, cause actions and change game state.

    Now, you may just want to have scenery objects which have a name and a description, but don't otherwise interact with the game at all. You could of course just create simple scenery objects:

        Nearby  Walls "walls"
         with   name "walls" "wall",
                description "cold, slick and painted that depressing \
                    'institutional' green.",
         has    scenery;
    
    However, I'm lazy and I don't want to type all that. Instead, I've developed scenery descriptions: non-objects which have a description but nothing else.

    Here's a sample script:

    Near a cave mouth
    The ridge rises another ten metres or so above you, but there are no obvious footholds or handholds for the first five; you can't really get much higher. Nevertheless, the view is expansive if not very impressive: a dark spire pokes out of the swamp to the north; a wide river flows through the swamps and joins the sea to the east, and there are a few rocky islands to be seen in the ocean. The dark shape you saw earlier is, as has been evident for some time, a small cave mouth. The best routes back down are to the northwest and southwest.

    >x spire
    Tall and slender; at its tip is something which catches the sunlight.

    >x river
    Its waters are a bilious yellow.

    >get river
    That's just scenery.

    >x islands
    Wind and wave have carved them into uncanny configurations.

    >enter islands
    That's just scenery.

    Just like the nouns which give rise to the That's not something you need to refer to in this game message, they (unfortunately) don't interact with it or them.
    >enter them
    You can't see "them" (the swamp) at the moment.
    You can look at the source code for a sample game (uses version 5/7 of the library). I hope it's fairly self-explanatory; if not, then e-mail me. A simple modification would be for GetScDescAddr(loc, spWord) to search the sceneDesc properties of loc and any of its children which have the scenery attribute for a match with spWord. This is left as an exercise for the reader. Another modification would be to allow synonyms for the objects, to avoid duplicating strings; something like:
        sceneDesc 
            3 'rushes' 'reeds' 'plants' 
              "They're home to insects and swamp birds."
            2 'tree' 'trees' "Straight-trunked and inaccessible."
    
    I'd welcome any comments on this. I've not tested it in anger, and there may be better ways of doing things too. There may also be a better phrase than That's just scenery to report on an attempted manipulation.

  7. How can I make a single object be both a supporter and a container?

    From the Life and times of the Inform library:

    Several people have asked for easier ways to have several kinds of containment at once, all on the same object - on top, inside, under, behind, component parts of, etc. For these (and other) purposes a brand new property called `add_to_scope' has been added. Anything listed under this property is also in scope when the parent object is. (This also has consequences for light considerations.) See the modest example A Nasal Twinge for two applications of this."
    The example Padlock takes a slightly different approach.

  8. How can I make a creature's possessions visible to the player?

    There are two aspects to visibility. First, the creature's possessions need to be in context for the player, so set the transparent attribute (see the Designer's Manual, section 10). Second, the possessions should be described to the player when the creature is examined.

    One approach is for all creatures with visible possessions to be members of a class, whose before method generates the appropriate description. This implementation provides separate lists of objects the creature is carrying and clothing they are wearing.

    The example game The Thief shows how such a class can be defined and used.

  9. How can I make other characters in my game move around the landscape, go through doors and so on?

    You'll have to write code to handle all the movement rules, I'm afraid, including locked and closed doors. I don't think there's any easy way to use the library code to move NPCs. However, the thief exercise in the Designer's Manual is a basic plan for a thief who wanders round the map like the player, and the example game The Thief shows how this could be extended to deal with doors and movement routines. In any case, the definition of the GoSub function in verblib.h contains the full story, and can be plundered for code when you need it.

  10. How can I parse topics that are looked up in books or asked of characters?

    Chapter 16 of the Inform manual contains an implementation of a what is thing verb, and this is a good model. The idea is to use a scope definition that puts objects into scope, each object representing one topic, and then add lines of grammar that reference this scope definition. You can see a detailed implementation in the example game Encyclopedia Frobozzica. Also see the WhatIs library.

  11. Is it possible to save a character in one game and restore that character to play in another?

    You'll need to learn a bit of Z-code assembler to do this in Inform. The save opcode (in version 5) can be called with a pointer to an area of memory, a number of bytes to be saved, and a filename to save them to. For example:

        ! Create an array of bytes to hold the filename, with the number of
        ! characters in the string in the first byte.
        Array filename string "filename.dat";
    
        ! Create an array in which to encode the necessary data about the
        ! character (suppose it takes 100 bytes).
        Array save_data -> 100;
    
        ...
    
        ! Save the character data to a file
        [ SaveCharacter result;
            ! Encode the character into the 'save_data' array somehow.
            ...
    
            ! Save the data.
            @save save_data 100 filename result;
            if (result == 1) "Save succeeded.";
            "Save failed.";
        ];
    
        ! Restore the character from a file
        [ RestoreCharacter result;
            ! Restore the data.
            @restore save_data 100 filename result;
            if (result ~= 100) "Restore failed.";
    
            ! Decode the character from the `save_data' array somehow.
            ...
    
            "Restore succeeded.";
        ];
    
    With some more work you could prompt the user for a filename, but I'll leave that as an exercise.

    You need to do a bit of work to remember which objects the character had: perhaps give each object a unique number or name, and make sure that every object that could be carried in the old game is present in the new game. When decoding, just fetch each item corresponding to a name read in from the file and add it to the character's inventory.

  12. I have an object that appears in several places (using the found_in property), but which is absent to start with. My code executes give object ~absent, but the object fails to appear. Why?

    Objects that appear in multiple places get moved around by the MoveFloatingObjects routine in verblib.h, which in the normal course of events only gets called when the player enters a new room. So you should call MoveFloatingObjects right away.

    Note: it isn't always safe to use move object to location, because (i) location might be thedark; (ii) location might not be one of the object's permissible locations.

  13. How can I arrange that the command person, yes has the same effect as say yes to person (recall that yes is a verb)?

    Because yes is a verb, the command person, yes gets turned into an Order action (which doesn't go through the usual before routines, so you can't modify its behaviour there). I think something like this:

        Property doesnt_obey 0;
    
        Class   TalkableClass
         has    animate
         with   life [ b;
                 Order:
                    if (action == ##Yes) b = 'yes';
                    if (action == ##No) b = 'no';
                    if (b ~= 0) {
                        special_word = b; <<Ask self b>>;
                    }
                    if (self.doesnt_obey ~= 0) {
                        PrintOrRun(self,doesnt_obey); rtrue;
                    }
                ];
    
    The section of a creature's Life routine that processes the Order action should drop off the end if it fails to understand it; then the routine above takes over. The doesnt_obey property allows creatures to continue to have customised default responses to being ordered around.

  14. Two rooms have a glass window separating them. How would you implement this?

    Make the window found_in both locations. Give the window an add_to_scope routine that puts all the objects from the other location into scope. Give both rooms a before routine that traps any action other than `Examine' (and perhaps ThrowAt) when applied to an object that's behind the window.

  15. How can I read input from the keyboard without waiting for the return key to be pressed? How can I animate some display so that the timings will be the same on different computers?

    You need to learn a little Z-code assembler to do this (see the Specification of the Z-machine for details). The read_char opcode reads a single character from the keyboard; so for example here is a function that waits until the player presses y or n, return 1 if the former and 0 if the latter:

        [ YN k;
            .yn_start;
            @read_char 1 k;
            if (k == 'y' or 'Y') rtrue;
            if (k == 'n' or 'N') rfalse;
            jump yn_start;
        ];
    
    In order to animate something, it is possible to give the read_char opcode two optional arguments, called time and function. The function is called every time seconds while waiting for the keypress. So for example, here's the skeleton for an animation lasting 20 seconds.
        Global animation_step = 0;
        [ Animate k;
            do {
                @read_char 1 1 #r$DoAnimation k;
            } until (animation_step == 20);
        ];
    
        [ DoAnimation t;
            ...
            animation_step ++;
        ];
    
    If you want to animate things while the player is typing their input (as in Infocom's game Border Zone) then you should use the aread opcode, which can be used in a similar way. With both aread and read_char it isn't possible to have a time step of less than one second; Inform wasn't really intended for arcade games.

    Andrew Plotkin's demonstration game Free Fall uses the read_char opcode to good effect.

  16. What's the right way to have quotes in boxes appearing in the game? I know how to use the box directive, but when the prompt is printed, the quote scrolls off the top of the screen.

    The thing to do is to print the box only after you have printed the prompt! The way to do this is to use the LibraryMessages system to trap the printing of the prompt and to print your box afterwards. For example:

    Global quote = 0;
    Global quotes_on = 1;
    
    [ QuotesOnSub;  quotes_on = 1; "[Quotations are now on.]"; ];
    [ QuotesOffSub; quotes_on = 0; "[Quotations are now off.]"; ];
    
    Verb meta "quotes"
        * "on"                              -> QuotesOn
        * "off"                             -> QuotesOff;
    
    Object  LibraryMessages "lm"
     with   before [;
             Prompt:
                print "^>";
                if (quotes_on == 1 && quote ~= 0) DisplayQuote(quote);
                quote = 0;
                rtrue;
            ];
    

 
 
(Library extensions) NEXT
(Tutorial) PREV
(Codeface index)   UP
  TOP
----------------------------------------  
 

Andrew Clover