Contents Back Forward |
| ||||||||||
If builders built buildings the way programmers write programs, the first woodpecker that came along would destroy civilisation. Infocom claimed to have fixed nearly 2000 bugs in the course of writing 'Sorcerer', which is a relatively simple game today. Adventure games are exhausting programs to test and debug because of the huge number of states they can get into, many of which did not occur to the author. (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 features to help the tester to quickly reproduce states (by moving objects around freely, for instance) and to see what the current state actually is (by displaying the tree of objects, for instance). Inform provides a small suite of debugging verbs, which will be added to any game compiled with the -D switch. If you prefer, you can include them manually by writing Constant DEBUG;DEBUG somewhere in the program before the library files are included. (Just in case you forget having done this, the letter D appears in the game banner to stop you releasing such a version by accident.) You then get the following verbs, which can be used at any time in play: showobj <anything> purloin <anything> abstract <anything> to <anything> tree tree <anything> scope scope <anything> showverb <verb> goto <number> gonear <anything> actions actions on actions off routines routines on routines off messages messages on messages off timers timers on timers off trace trace on trace off trace <1 to 5> recording recording on recording off replay random"showobj'' is very informative about the current state of an object. You can "purloin" any item or items in your game at any time, wherever you are. This clears concealed for anything it takes, if necessary. You can likewise "abstract" any item to any other item (meaning: move it to the other item). To get a listing of the objects in the game and how they contain each other, use "tree", and to see the possessions of one of them alone, use "tree <that>". The command "scope'' 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 (e.g., "scope pirate''). "showverb'' will display the grammar being used when the given verb is parsed. Finally, you can go anywhere, but since rooms don't have names understood by the parser, you have to give either the object number, which you can find out from the "tree'' listing, or the name of some object in the room you want to go to (this is what "gonear'' does). Turning on "actions" gives a trace of all the actions which take place in the game (the parser's, the library's or yours); turning on "routines" traces every object routine (such as before or life) that is ever called, except for short_name (as this would look chaotic, especially on the status line). It also describes all messages sent in the game, which is why it can also be written as "messages''. Turning on "timers'' shows the state of all active timers and daemons each turn. The commands you type can be transcribed to a file with the "recording'' verb, and run back through with the "replay'' verb. (This may not work under some implementations of the ITF interpreter.) If you're going to use such recordings, you will need to fix the random number generator, and the "random'' verb should render this deterministic: i.e., after any two uses of "random'', the same stream of random numbers results. Random number generation is poor on some machines: you may want to Replace the random-number generator in software instead.
A source-level debugger for Inform, called Infix, has been planned for some years, and may possibly be coming to fruition soon.
| |||||||||||
For the benefit of such tools, Inform (if compiling with the -k option set) produces a file of "debugging information'' (cross-references of the game file with the source code), and anyone interested in writing an Inform utility program may want to know the format of this file: see the Technical Manual for details. | |||||||||||
On most interpreters, though, run-time crashes can be mysterious, since the interpreters were written on the assumption that they would only ever play Infocom game files (which are largely error-free). A Standard interpreter is better here and will usually tell you why and where the problem is; given a game file address you can work back to the problem point in the source either with Mark Howell's txd (disassembler) or by running Inform with the assembler trace option on. Here are all the ways I know to crash an interpreter at run-time (with high-level Inform code, that is; if you insist on using assembly language or the indirect function you're raising the stakes), arranged in decreasing order of likelihood: -- Writing to a property which an object hasn't got; -- Dividing by zero, possibly by calling random(0); -- Giving a string or numerical value for a property which can only legally hold a routine, such as before, after or life; -- Applying parent, child or children to the nothing object; -- Using print object on the nothing object, or for some object which doesn't exist (use print (name), print (the) etc., instead as these are safeguarded); -- Using print (string) or print (address) to print from an address outside the memory map of the game file, or an address at which no string is present (this will result in random text appearing, possibly including unprintable characters, which might crash the terminal); -- Running out of stack space in a recursive loop.
| |||||||||||
There are times when it's hard to work out what the parser is up to and why
(actually, most times are like this). 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:
{
| |||||||||||
| |||||||||||
Finally, though this is a drastic measure, you can always compile your game
-g ('debugging code') which gives a listing of every routine ever
called and their parameters. This produces an enormous melèe of output.
More usefully you can declare a routine with an asterisk * as its first
local variable, which produces such tracing only for that one routine.
For example,
[ ParseNoun * obj n m;results in the game printing out lines like [ParseName, obj=26, n=0, m=0]every time the routine is called. | |||||||||||
| |||||||||||
REFERENCES: A simple debugging verb called "xdeterm'' is defined in the DEBUG version of 'Advent', to make the game deterministic (i.e., not dependant on what the random number generator produces). | |||||||||||
|