If builders built buildings the way programmers write programs, the first woodpecker that came along would destroy civilisation.
— old computing adage
Infocom fixed 1,695 documented bugs in the course of getting ‘Sorcerer’ from rough draft to first released product. Alpha testing of ‘A Mind Forever Voyaging’ turned up one bug report every three minutes. Adventure games are exhausting programs to test and debug because of the number of states they can get into, many of them unanticipated. (For instance, if the player solves the “last” puzzle first, do the other puzzles still work properly? Are they still fair?) The main source of error is simply the designer not noticing that some states are possible. The Inform library can't help with this, but it does contain some useful features designed to help the tester. These are worth finding out about, because if you're going to code up a game, you'll be spending a lot of time testing one thing or another.
Inform has three main debugging features, each making
the story file larger and slower than it needs to be: each can be turned
on or off with compiler switches. One feature is “strict mode”
(switch -S), which checks that the story file isn't committing
sins such as over-running arrays or treating
nothing as if it were an
object: trying to calculate
child(nothing), for instance. Strict mode
is on by default, and automatically sets Debug mode whenever it is on.
To get rid of strict mode, compile with -~S
to turn switch S off.
Over and above this is the extensive “Infix” (switch -X), a far more potent set of debugging verbs, which significantly adds to the size of a story file (so that a really large story file might not be able to fit it in). Infix allows you to watch changes happening to objects and monitor routines of your choice, to send messages, call routines, set variables and so forth. Like Strict mode, Infix automatically switches Debug mode on.
Debug mode (switch -D) adds only a small suite of commands, the “debugging verbs”, to any game. For instance, typing “purloin mousetrap” allows you to take the mousetrap wherever it happens to be in the game. The debugging verbs do take up extra space, but very little, and note that even if Strict mode and Infix are both off, you can still have Debug on its own.
The Infix and Debug modes give the player of a story file what amount
to god-like powers, which is fine for testing but not for final release
versions. As a precaution against accidents, the end of a game's printed
banner indicates Infix
mode with a capital letter ‘X’,
Debug with ‘D’, and Strict with ‘S’.
Your source code can also detect which are set: in Strict mode the
STRICT_MODE is defined; in Debug mode the
DEBUG; with Infix the constant
The basic testing technique used by most designers is to keep a master-list of commands side by side with the growing game: a sequence which takes the player from the beginning, explores everywhere, thoroughly tests every blind alley, sudden death and textual response and finally wins the game.
“recording” or “recording on” or “recording off”
Records all the commands you type into a file on your machine (your interpreter will probably ask you for a filename). When a new region of game is written, you may want to turn recording on and play through it: you can then add the resulting file to the master-list which plays the entire game.
This immensely useful verb plays the game taking commands from a file on your machine, rather than from the keyboard. This means you can test every part of the entire game with minimal effort by replaying the master-list of commands through it.
If you're going to replay such recordings, you need the game to behave predictably: so that chance events always unfold in the same way. This means nobbling the random number generator, and the “random” verb does just that: i.e., after any two uses of “random”, the same stream of random numbers results. So you want the first command in your master-list to be “random” if your game has any chance events in it.
▲ If you have written a large and complicated game, you may well want to release >occasional updates to correct mistakes found by players. But tampering with the code always runs the risk that you may fix one thing only to upset another. A useful insurance policy is to keep not only the master list of commands, but also the transcript of the text it should produce. Then when you amend something, you can replay the master list again and compare the new transcript with the old, ideally with a program like the Unix utility “diff”. Any deviations mean a (possibly unintended) side effect of something you've done.
Every Inform game provides the “undo” verb, which exactly restores the position before the last turn took place. Though this is not advertised, “undo” can even be used after death or victory, typed in at the “Would you like to RESTART, RESTORE a saved game…” prompt. It can be useful to include fatal moves, followed by “undo”, in the master-list of commands, so testing death as well as life.
“showobj” is very informative about the current state of an object, revealing which attributes it presently has and the values of its properties. ‹anything› can be the name of any object anywhere in the game (not necessarily in sight), or even the number of an object, which you might need if the object doesn't have a name.
“tree” or “tree” ‹anything›
To see a listing of the objects in the game and how they contain each other, type “tree”, and to see the possessions of one of them alone, use “tree ‹that›”. So “tree me” is quite like “inventory”.
For instance, “showverb unlock”. This prints out what
the parser thinks is the grammar for the named verb, in the form of an
Inform Verb directive. This is useful if you're using the
directive to alter the library's grammar and want to check the result.
“scope” or “scope” ‹anything›
Prints a list of all the objects currently in scope, and can optionally be given the name of someone else you want a list of the scope for (“scope pirate”). Roughly speaking, something is in your scope if you can see it from where you are: see §32.
Tracing is the process of printing up informative text which describes changes as they happen. Each of the following verbs can be given on its own, which sets tracing on; or followed by the word “on”, which does the same; or followed by “off”, which turns it off again.
“actions” or “actions on” or “actions off”
Traces all the actions generated in the game. For instance, here's what happens if you unlock and then enter the steel grate in ‘Advent’:
[ Action Enter with noun 51 (steel grate) ]
[ Action Go with noun 51 (steel grate) (from < > statement) ]
Which reveals that the
Enter action has
handed over to
“messages” or “messages on” or “messages off”
Traces all messages sent between objects in the game. (Except for
messages, because this would look chaotic, especially when printing the
“timers” or “timers on” or “timers off”
Turning on “timers” shows the state of all active timers and daemons at the end of each turn. Typing this in the start of ‘Advent’ reveals that three daemons are at work: two controlling the threatening little dwarves and the pirate, and one which monitors the caves to see if every treasure has been found yet.
“changes” or “changes on” or “changes off”
Traces all movements of any object and all changes of attribute or property state.
>switch lamp on
[Giving brass lantern on]
[Giving brass lantern light]
You switch the brass lantern on.
[Setting brass lantern.power_remaining to 329]
In Debris Room
You are in a debris room filled with stuff washed in from the surface. A low wide passage with cobbles becomes plugged with mud and debris here, but an awkward canyon leads upward and west.
A note on the wall says, “Magic word XYZZY.”
A three foot black rod with a rusty star on one end lies nearby.
[Giving In Debris Room visited]
Warning: this verb has effect only if the story file was compiled with the -S switch set, which it is by default.
▲ Two things “changes” will not notice: (i) changes in the workflag attribute, because this flickers rapidly on and off with only temporary significance as the parser works, and (ii) changes to the entries in an array which is held in a property.
“trace” or “trace” ‹number› or “trace off”
There are times when it's hard to work out what the parser is up to and why (actually, most times are like this: but sometimes it matters). The parser is written in levels, the lower levels of which are murky indeed. Most of the interesting things happen in the middle levels, and these are the ones for which tracing is available. The levels which can be traced are:
|Level 1||Parsing a ‹grammar line›|
|Level 2||Individual tokens of a ‹grammar line›|
|Level 3||Parsing a ‹noun phrase›|
|Level 4||Resolving ambiguities and making choices of object(s)|
|Level 5||Comparing text against an individual object|
“trace" or “trace on" give only level 1 tracing. Be warned: “trace 5" can produce reams and reams of text. There is a level lower even than that, but it's too busy doing dull spade-work to waste time printing. There's also a level 0, but it consists mostly of making arrangements for level 1 and doesn't need much debugging attention.
You can “purloin” any item or items in your game at any time, wherever you are, even if they wouldn't normally be takeable. A typical use: “purloin all keys”. Purloining something automatically takes away the concealed attribute, if necessary.
“abstract” ‹anything› “to” ‹anything›
You can likewise “abstract" any item to any other item, meaning: move it to the other item. This is unlikely to make sense unless the other item is a container, supporter or animate object.
“goto” ‹room number›
Teleports you to the numbered room. Because rooms don't usually have names, referring to them by number (as printed in the “tree” output) is the best that can be done…
… unless you can instead name something which is in that room. So for instance “gonear trident” teleports to the room containing the trident.
Although Infix adds relatively few additional verbs to the stock, they are immeasurably stronger. All of them begin with a semicolon ; and the convention is that anything you type beginning with a semicolon is addressed to Infix.
This calculates the value of the expression and prints it out. At first sight, this is no more than a pocket calculator, and indeed you can use it that way:
; == 5040
But the ‹expression› can be almost any Inform expression, including
variables, constants, action, array, object and class names, routine
calls, message-sending and so on. It can be a condition, in which case
the answer is 0 for
false and 1 for
It can even be an assignment.
; == 36
>; score = 1000
; == 1000
[Your score has just gone up by nine hundred and sixty-four points.]
>; brass_lantern has light
>; lamp.power_remaining = 330
(brass lantern (39))
; == 330
>; child(wicker cage)
(wicker cage (55))
; == “nothing” (0)
; == 4
In the dialogue above, from ‘Advent’ compiled
with -X, the player called the same item both
the name it has in the source code, and “lamp”, the name
it normally has in the game. When Infix is unable to understand a term
like “lamp” as referring to the source code, it tries to
match it to an object somewhere in the game, and prints up any guess
it makes. This is why it printed “(brass lantern (39))”.
(39 happens to be the object number of the brass lantern.) Pronouns
like “me” and “it” can also be used to refer
; == 1
>; InformLibrary.begin_action(##Take, black_rod)
black rod with a rusty star on the end: Taken.
; == 0
StopDaemon will appear later in
§20: roughly speaking, “daemons”
control random interventions, and stopping them is useful to keep
(say) the bearded pirate from appearing and disrupting the replay of
a sequence of commands. The second example shows a message being sent,
though there is a simpler way to cause actions:
“;<” ‹action› ‹noun› ‹second›
which generates any action of your choice, whether or not the given ‹noun› and ‹second› (which are optional) are in your scope. Once generated, the action is subject to all the usual rules:
>;< Take black_rod
;<Take (the black rod with a rusty iron star on the end)
That isn't available.
Three Inform statements for changing objects are also available from Infix:
“;move” ‹expression› “to” ‹expression›
These do just what you'd expect. “;give” is especially
useful if, as often happens, you find that you can't test some complicated
new area of a game because you've forgotten to do something basic, such
as to make a door a door, or to set up an outdoor afternoon location
light. Using “;give” you can illuminate any
dark place you stumble into:
It is pitch dark, and you can't see a thing.
>;give real_location light
; give (the At “Y2”) light
You are in a large room, with a passage to the south, a passage to the west, and a wall of broken rock to the east. There is a large “Y2” on a rock in the room's center.
(The waiting was because Inform only checks light at the end of each turn, but “;give” and the other debugging verbs are set up to occupy no game time at all — which is often useful, even if it's a slight nuisance here.) Infix also extends the facilities for watching the changing state of the game:
or “;w” ‹named routine›
“;watch” or “;w” ‹named routine› “off”
“;watch” or “;w” ‹object›
“;watch” or “;w” ‹object› “off”
When a named routine is being watched, text is printed each time it is
called, giving its name and the values of the arguments it started up
with. For instance, “;watch StartTimer”
will ensure that you're told of any
call, and so of any timer that begins working. Watching an object,
say “;watch lamp”, will notify you when:
(1) any attribute of the lamp is given or taken away;
(2) any property of the lamp is set;
(3) any message is sent to a routine attached to the lamp;
(4) the lamp is moved;
(5) anything is moved to the lamp.
You can also watch things in general:
|“;watch objects”||watches every object|
|“;watch timers”||watches timers and daemons each turn|
|“;watch messages”||watches every message sent|
|“;watch actions”||watches all actions generated|
The final two Infix verbs extend the facilities for looking at things.
“;examine” or “;x” ‹something›
“;inventory” or “;i”
“;inventory” tells you the names known to Infix, which is a practical way to find out which classes, routines, objects and so on are inside the story file. “;examine” looks at the ‹something› and tells you whatever Infix knows about it: (a) numbers are translated to hexadecimal and to ZSCII values, where possible; (b) objects are “shown”; (c) classes are listed; (d) constants have their values given; (e) attributes produce a list of all objects currently having them; (f) properties produce a list of all objects currently providing them; (g) dictionary words are described; (h) verbs have their grammars listed; (i) arrays have their definitions shown and their contents listed; (j) global variables have their values given; (k) actions produce a list of all grammar known to the parser which can produce them. For instance:
; Dictionary word 'silver' (address 27118): noun
; Array buffer -> 120
; == 120 9 59 120 32 98 117 102 102 101 114 0 101 114 32 (then 105 zero entries)
You can watch routines even without Infix, and the Inform language provides
two features for this. Firstly, you can declare a routine with an
* immediately after the name, which marks it for watching. For
example, declaring a routine as follows
[ AnalyseObject * obj n m;
results in the game printing out lines like
[AnalyseObject, obj=26, n=0, m=0]
every time the routine is called. A more drastic measure is to compile the story file with the -g set. The ordinary setting -g or -g1 marks every routine in your own source code to be watched, but not routines in the library (more accurately, not to routines defined in any “system file”). The setting -g2 marks every routine from anywhere, but be warned, this produces an enormous melée of output.
If you do have Infix present, then you can always type “;watch…
off” to stop watching any routine marked with a
the source code. Without Infix, there's no stopping it.
▲▲ At present, there is no source-level debugger for Inform. However, for the benefit of any such tool which somebody might like to write, Inform has a switch -k which makes it produce a file of “debugging information” to go with the story file. This file mostly contains cross-references between positions in the game and lines of source code. The details of its format are left to the Technical Manual.
Several exercises in this book are about defining new debugging verbs to test one thing or another, and most games have invented a few of their own. Early versions of ‘Curses’, for instance, allowed various supernatural actions beginning with “x” once the player had typed the command “xallow 57” (the author was then living above a carpet shop at 57 High Street, Oxford). But Paul David Doherty eventually disassembled the story file and found the secret. Moral: place any new debugging verbs inside an
DEBUG; directive, unless you plan on leaving them in as
“Easter eggs” for people to find.
•A simple debugging verb called
“xdeterm” is defined in the DEBUG version
of ‘Advent’: it takes random events out of the game.
•Marnie Parker's library extension
"objlstr.h", which has contributions from Tony
Lewis, provides a useful debugging verb “list”, allowing
for instance “list has door lockable locked”, which lists
all objects having that combination of attributes.