
  +---------------------------------------------------------------------+
  |            Inform: A Compiler of Infocom-Format Games               |
  |                                                                     |
  |                        by Graham Nelson                             |
  |                                                                     |
  |                                                                     |
  |                           Fifth Edition                             |
  +---------------------------------------------------------------------+


            "I will build myself a copper tower
             With four ways out and no way in
             But mine the glory, mine the power..."

                 (Louis MacNeice, "Flight of the Heart")


  Hello, Informer!

  This manual contains four elements.  Firstly, it documents Inform, a
program to manufacture Infocom format "story files" (or Adventure games),
which can then be played on any of the interpreters now widely available:
this is probably the most portable form in which games can ever be written,
as no alteration whatever is required to move a game file from one model of
computer to another, and almost every model can run it.  The Inform language
is an Adventurous, object-oriented one, reminiscent of C.

  Secondly, it documents a suite of standard game routines provided with
Inform to allow designers to begin coding at once.  In effect, this means
that an Inform source file need not contain any of the parser code, or the
running of the "game universe" - the library consists roughly of a full
implementation of Zork without any actual puzzles.  It manages rooms,
objects, containers, things on top of other things, light, scoring,
switching things on and off, opening, closing and locking things, entering
things, travelling about in them and so forth: it implements about 80 verbs. 
The parser it uses (which can be entirely invisible to the designer, or can
be altered if necessary) is about as good as any 1980s parser.  (And its
source is very heavily commented, so the algorithm may be of interest even
to non-Informers.)

  Thirdly, it attempts to fully specify the "Z-machine", in all six
versions (including the final graphics version 6) and to discuss to what
extent publically-available interpreters actually implement it.  Some of
this information is already circulating in other files, but uncollated. 
Other information seems only available in as much as it is implicit in the
interpreter sources: and still more is newly issued here.  I hope that
Appendix A may serve as a fair definition of the Z-machine for interpreter
writers and maintainers.

  Fourthly, it contains a short book on the art and craft of devising
adventure games, which is quite general and makes no assumptions about the
language being used.  So in a way it does not belong in this manual: but I
think that game implementation bears about the same relation to design as
typing does to writing poetry, and I didn't want only to talk about typing.

  A short final appendix describes examples of Inform code.


  The best way to begin reading this manual is to look first at the second
chapter, the designer's manual.  The first chapter is a reference guide
rather than an introduction.



---------------------------------------------------------------------------
                             Contents
---------------------------------------------------------------------------

                Availability
                Prefaces to editions of this manual

      Reference Manual: The Inform Language and Compiler

           1.   Command lines, errors and memory allocation
           2.   Source file format
           3.   Compiler directives
           4.   Variables
           5.   Constants
           6.   Routines
           7.   Expressions and assignments
           8.   Commands
                (a)  Printing commands
                (b)  Object manipulation
                (c)  Control commands
                (d)  Causing actions
                (e)  Miscellaneous and rarely-used commands
           9.   Conditions
           10.  Built-in functions and random numbers
           11.  Objects, attributes and properties
           12.  Routines embedded in objects
           13.  Classes and inheritance
           14.  Verbs and grammar
           15.  Exactly what Inform does with words
           16.  Indirect function calls
           17.  Text spacing
           18.  Drastic alteration of objects
           19.  Abbreviations
           20.  Bells, whistles and gimmicks

      Designer's Manual: Using the Library

           D1.  Getting started
           D2.  Places, scenery and the map
           D3.  Causing actions and making new ones
           D4.  Containers, doors, switches and vehicles
           D5.  Living creatures
           D6.  Classes of objects
           D7.  Daemons and the passing of time
           D8.  Calls to and from the library
           D9.  Table of properties and attributes
           D10. Customising the parser

      The Z-machine

           A1.  The early Z-machine
           A2.  How text is encoded
           A3.  How Z-code is encoded
           A4.  The six versions of the Z-machine
           A5.  The late Z-machine
           A6.  Complete table of opcodes in versions 1 to 6
                (with Inform assembly language syntax)
           A7.  Dictionary of opcodes and specifications
           A8.  Table of header format through the ages
           A9.  A few statistics

      The Craft of the Adventure

           B1.  A Bill of Player's Rights
           B2.  A narrative...
           B3.  ...at war with a crossword
           B4.  Varnish and veneer
           B5.  Talking to parsers

      Example Inform programs

           C1.  Hello Cruel World
           C2.  "Toyshop": a small toy game
           C3.  "Adventure": a port of Colossal Cave
           C4.  A shell game to build on


---------------------------------------------------------------------------
Availability
---------------------------------------------------------------------------


  Material on Inform originates from the if-archive at the German anonymous
ftp site ftp.gmd.de, which is maintained by Volker Blasius, in the directory

  if-archive/infocom/compilers/inform.

Versions found at other sites (except those which mirror ftp.gmd.de) may
well be out of date.  So far, updated versions have been posted about once
a quarter.

  The Inform code is in portable ANSI C, and has been ported to and by:

  the Commodore Amiga under SAS/C              Christopher A. Wichura
  the Acorn Archimedes under Norcroft C        (the author)
  the Atari ST                                 Charles Briscoe-Smith
  Linux under gcc (essentially as per Unix)    Spedge, aka Dark Mage
  the Apple Macintosh                          Robert Pelak
  OS/2 32-bit mode under IBM's C Set++         John W. Kennedy
  386+ IBM PCs, eg. Microsoft Visual C/C++     Toby Nelson
  small IBM PCs under QuickC                   Bob Newell
  Unix under gcc (or big IBM PCs under djgpp)  Dilip Sequeira
  VAX mainframes under Digital's VAX C         (the author)

  (Recent ports have been quite painless.)  Executables for some of these
machines may be found ready-compiled in the archive.

  Inform is not public domain in the proper legal sense of the term.  The
copyright is retained by the author, Graham Nelson.  I am perfectly happy
for Inform to be used by anybody for any recreational purpose.  It may be
freely distributed provided no profit is involved, and provided the
copyright message is retained.  Please do not circulate heavily modified
versions, and please comment any private changes of your own at the top of
the source code.

  Story files produced by Inform belong to whoever wrote the source for
them; I think, however, it is fair to ask that game-writers put some message
into their credits saying that Inform was used, and giving the version
number used to compile it.


---------------------------------------------------------------------------
Prefaces to editions of this manual
---------------------------------------------------------------------------


  Historically, Inform was not a wonderfully well-written program: it must
be admitted that I treated it more as an easel than a painting.

  But it works, and it runs in only two passes.  (This may sound easy but is
not, because the story file format requires all manner of tricky operations
to be done: for example, the dictionary must be alphabetically sorted, and
the code must know absolute addresses of its entries... and the address of
the start of the dictionary depends on many other things not known during
pass 1... and so on.)

  It seems also, for what it's worth, to be more efficient than Infocom's
own compiler - perhaps because it compiles from a low C-like rather than
high LISP-like source.

                                                                 April 1993


Notes on the second release:

  Since the first release, much improvement has been made in Inform's memory
management which is now quite efficient: it allocates between 50 and 75K of
memory, as opposed to 800K in the first edition.

  The code has been annotated to some extent, and contains notes which
should be useful to anyone trying to port the code to a new machine.

  This documentation has changed only in the new "objectloop" construction,
and in Appendix C (sample output for the given programs).  The language
which Inform compiles has not changed (except that two defunct features,
which had not in any case been documented, have been withdrawn).  Details of
changes to the source code of Inform may be found in detailed comments at
its head.
                                                                  June 1993

And the third:

  The third edition of this manual contains a fair amount of new material.
Most of the changes in Inform are improvements which do not affect the
language (better error reporting, bug fixes, speed improvements, new
compile options, much greater portability across different C compilers).

  However, various new features have been added, mainly to provide for needs
which cropped up for the author:

  new command line switches;                             see (1)
  new directives "statusline", "release", "include",
    "default", "stub";                                   (2), (20)
  string indirection via the synonyms table;             (5), (18)
  multiple object names;                                 (11), (18)
  new constant forms #n$word and #r$routine;             (5)
  new object alteration commands "write" and "give";     (8)
  new command "string";                                  (8), (18)
  new command "font";                                    (8), (20)
  abbreviations, properly using the synonyms table.      (19)

  Making use of abbreviations slows compilation down, but (when switched on)
can make reasonable memory savings (about 8%).

  Inform also now correctly works out the checksum and length fields for the
story file header, which (a) makes a "verify" command easy to implement, and
(b) may make story files work on older interpreters.

  One change has been made which is incompatible with earlier editions:
the names of some of the more esoteric debugging directives have been
homogenised.

  The text has been revised and clarified in several other places.

                                                              November 1993

And the fourth:

  The fourth edition of Inform, and this manual, both contain much that is
new to cover: Advanced (version-5) story files, conditional compilation,
better array and object handling, better conditions, and miscellaneous other
additions.  The appendix specifying the Z-machine is greatly extended.

  In addition some of the text has been expanded upon, and explicit
warnings are made of ways in which game interpreters can be crashed by
accident.

  Most of the new features are "extras" rather than making old syntax
illegal.  However, "objectloop" is slightly different, and the much more
sophisticated loop constructs now available have a more C-like style than
their predecessors: see (8).

  The library routines - the game parser and the standard verbs - have
been rewritten in "new-style" Inform and are much more readable as a result.

  New features include:

  new directive "version" and switches -v3, -v5;         see (1), (3)
  more new switches, -z (memory map), -u (abbreviations
    optimiser), -r (record text) -g (run-time tracing);  (1), (19)
  conditional compilation;                               (3)
  a few new constant forms;                              (5)
  negative constants now allowed;                        (5)
  much better assignment forms for arrays and
    properties, and new operators unary minus,
    "++", "--", ".", ".#" and ".&";                      (7), (11)
  better loop constructs;                                (8)
  new commands "read", "save", "restore", "style";       (8)
  more powerful printing commands, and "spaces" command; (8)
  "&&" and "||" (logical and/or) for conditions;         (9)
  new functions for reading the object tree;             (10)
  property and attribute "alias"es;                      (11)
  new Version-5 special effects, including the "box"
    command;                                             (20), (8)
  and many new Version-5 opcodes.                        (A4)

  Many technical improvements have been made in the source code to Inform:
those which do not change the language are left to the modification history
in its header file.  There are also several new errors and warnings covering
rare and presumed accidents respectively.

  There are also a few new jokes, so it's not all good news.

                                                               January 1994

And the fifth:

  Once again, Inform has moved on.  The changes since Release 4 are largely
cosmetic but make an enormous difference to the elegance and legibility of
code.  (However, old code still compiles properly.)  The library routines
are much improved, and Inform code is now much more object-oriented than
in the past.

  The library documentation has been completely rewritten as a tutorial.
There are many new library features: for radically customising the parser,
easier alteration of container rules, objects which spread across many rooms
(such as rivers), "in" and "out" implemented as directions, easier
production of "you can't go west because..." messages.  (And there are a few
minor bug-fixes too, but these make no difference to the documentation.) 
Here Gareth Rees, Robin Watts and others have made several useful
contributions.

  The appendix on the Z-machine has been greatly expanded, and the project
of describing all six versions is finally complete: the material on
version-5 is much enlarged and version-6 is entirely new to this edition. 
Mark Howell and Paul David Doherty each took the trouble to read a draft of
this appendix and make detailed corrections and comments, for which I am
very grateful.  Responsibility for errors and style remains of course mine.

  A few of the opcodes have been slightly renamed and others are named
for the first time; Inform can now produce version 4 and 6 files (this is
not very useful); there are new tracing switches -j and -n.  The dictionary
is now capable of encoding words like "y2" and "fish-paste": i.e., it no
longer needs words to be purely alphabetic.

  Internally, memory management has been greatly reformed, and it is now
much easier to change the inbuilt size constraints: they can be altered at
the command line, without the need to recompile Inform itself.  This is
especially useful on small machines, and anyway hackers are bound to enjoy
using them.  See (1).

  In order to accommodate parser customisation, the grammar table now has
a slightly more interesting format: see (14).  Section (D10) describes how
to adapt the parser when using the library.

  The old appendix B on designing games has been expanded into a short,
possibly interesting book.

  Inform's source code now seems to be as portable as C ever is.  Several
people, but especially Bob Newell, have laboured to make it so: and each
time that Inform does not crash the machine it runs on, we owe them another
small debt.  Bob in particular describes himself as "more familiar with
Inform's code than I have been with my spouse lately": Inform, as an ugly
piece of code with poor prospects, can only be counted lucky to have such a
suitor.  In any case, I am grateful for Mrs Newell's tolerance.

                                                                        GAN
                                                                  June 1994


  The author's email address may be found at the bottom of this file. 
Comments and bug reports (by email) are welcomed with whatever degree of
enthusiasm he can muster.




---------------------------------------------------------------------------
            Reference Manual: The Inform Language and Compiler
---------------------------------------------------------------------------



---------------------------------------------------------------------------
1. Command lines, errors and memory allocation
---------------------------------------------------------------------------


       "I was promised a horse, but what I got instead
        was a tail, with a horse hung from it almost dead."

       (epigram by Palladas of Alexandria, translated by Tony Harrison)


Inform compiles the source code for an Adventure game to one of two kinds of
"story file": Standard (version 3, the default) or Advanced (version 5). 
Unless specialised version-5-only features are asked for, an Inform game can
be compiled to either format.  Because the Advanced format extends many of
the restrictions on the Standard one, it may be needed when a game becomes
sufficiently large.

If Inform is run without any parameters given, it prints out something like
the following information:

   Archimedes Inform 5 (v1259/at)
   Release 5 (June 11th 1994)
   (allocating memory for arrays) (temporary files) 
   
   This program is a compiler to Infocom format story files.
   It is copyright (C) Graham Nelson, 1993/4.
   
   Its syntax is "inform [-list] [$memcom ...] <file1> [<file2>]"
   
   <file1> is the name of the Inform source file; Inform translates this into
      "Zcode.<file1>"
   (unless <file1> contains a '.' or '/', in which case it is left alone).
   <file2> may optionally be given as the name of the story file to make.
   If it isn't given, Inform writes to
      "Zgames.<file1>"
   (for both version-3 and version-5 files)
   but if it is, then Inform takes <file2> as the full filename.
   
   -list is an optional list of switch letters following the initial hyphen:
     a   list assembly-level instructions compiled
     b   give statistics and/or line/object list in both passes
     c   more concise error messages
     d   contract double spaces after full stops in text
     e   economy mode (slower): make use of declared abbreviations
     f   frequencies mode: show how useful abbreviations are
     g   with debugging code: traces all function calls
     h   print this information
     i   ignore default switches set within the file
     j   list objects as constructed
     l   list all assembly lines
     m   say how much memory has been allocated
     n   print numbers of properties and attributes
     o   print offset addresses
     p   give percentage breakdown of story file
     r   record all the text to "Game_Text"
     s   give statistics
     t   trace Z-code assembly
     u   work out most useful abbreviations
     v3  force production of version-3 (Standard) story file
     v4  force production of version-4 (Plus) story file
     v5  force production of version-5 (Advanced) story file
     v6  force production of version-6 (graphical) story file
     w   disable warning messages
     x   print # for every 100 lines compiled (in both passes)
     z   print memory map of the Z-machine
   
   $memcom can be one or more memory allocation commands:
     $list             list current memory allocation settings
     $large            make the standard "large game" settings
     $small            make the standard "small game" settings (default)
     $?SETTING         explain briefly what SETTING is for
     $SETTING=number   change SETTING to given number

   For example: "inform -dex $large curses ram:curses".
   

(The file naming conventions and version numbers may differ slightly on your
copy.)

Roughly speaking, the switches are self-explanatory to the well-informed
and of little use to others.

Samples of -s and -p output can be found in Appendix C, and of -z in
Appendix A.  For -d, see section (17).  For -e and -f, see (19).  -x is
useful if running Inform on a slow machine, since it offers some signs of
life; as does -j.  -a, -n, -p and -l are largely useful to assembly-language
programmers and the unfortunate wretch who maintains Inform.

In -g mode, every function call at run time is traced (this is surprisingly
useful when debugging).

-i overrides any "SWITCHES" directive in the body of the code, so that the
only switches applying are those in the command line.

-m reveals how many bytes were malloc'ed.  The program can be compiled in
several different versions, with varying memory needs, and porters might
need to use this.

The filenames Inform uses for input and output will obviously depend on what
machine it runs on.  The Archimedes conventions are those above, but, for
example, the Unix version compiles files like "dejavu.inf" with headers like
"parser.h" to "dejavu.z3".

-v3 sets the Standard format (overriding any "Version" directive in the
file), and -v5 sets Advanced.  Standard is the default.  -v4 and -v6 are
now available but are not useful.

-r and -u both require much greater free memory (perhaps as much as
0.5-1 megabyte) to run than the rest of Inform.  -r makes a transcript file
of all of the text (excluding abbreviations and dictionary entries), which
can be useful for proof-reading - for instance, it could be run through a
spell-checker.  -u runs the abbreviations-optimiser, a computationally
expensive job not to be undertaken lightly: see (19).


As Inform runs, it may come up with warnings, errors or fatal errors.
Here is a typical sample:

  Archimedes Inform 5 (v1259/at)
  line 10: Error: Symbol name expected
  >   global
  line 12: Error: The "Main" routine is not allowed to have local variables
  >   [ Main i
  line 12: Warning: Local variable unused: "i"
  line 23: Warning: Local variable unused: "j"
  Compiled with 2 errors and 2 warnings (no output)

(Infocom interpreters can crash horribly when given incorrect files, so
Inform never writes a file which caused an error, though it will allow
files causing warnings only.)

-c (concise) mode doesn't quote from the source files; -w turns warnings
off.

The exchange rate is 100 errors to the fatal error: i.e., after 100 errors,
Inform gives up altogether.  An unlimited number of warnings may occur.


The memory management commands are provided for emergencies.  Previously,
to raise one of the compiler limits (say, MAX_OBJECTS) one had to recompile
Inform itself.  This was obviously at best a nuisance, at worst impossible.
In order to get round this, Inform always made enormously generous
estimates for what the player might want: but this meant that it allocated
more memory than strictly needed, which was a problem on small computers.

There are two main choices: $small and $large.  (Which one is the default
depends on the computer you use.)  Even $small is large enough to compile
all the example games, including "Advent".  $large is large enough to
compile almost anything (including the largest version of "Curses" which
ever existed, which was at one stage very close to 256K long).

A typical game, compiled with $large, will cause Inform to allocate about
336K of memory: and the same game about 100K less under $small.  (These
values will be rather lower if the computer Inform runs on has 16-bit
integers.)  In addition, Inform physically occupies about 170K (on my
computer).  Thus, the total memory consumption of the compiler at work
will be between 4 to 500K.

Running

    inform $list

will list the various settings which can be changed, and their current
values.  Thus one can compare small and large with:

    inform $small $list
    inform $large $list

If Inform runs out of allocation for something, it will generally print an
error message like:

   "Game", line 1320: Fatal error: The memory setting MAX_OBJECTS (which
   is 200 at present) has been exceeded.  Try running Inform again with
   $MAX_OBJECTS=<some-larger-number> on the command line.

and indeed

    inform $MAX_OBJECTS=250 game

(say) will tell Inform to try again, reserving more memory for objects this
time.  Note that settings are made from left to right, so that for instance

    inform $small $MAX_ACTIONS=200 ...

will work, but

    inform $MAX_ACTIONS=200 $small ...

will not because the $small changes MAX_ACTIONS again.

The setting names are in some cases rather peculiar, and changing some
settings has hardly any effect on memory usage, whereas others are expensive
to increase.  To find out about, say, MAX_VERBS, run

    inform $?MAX_VERBS

(note the question mark) which will print some very brief comments.


---------------------------------------------------------------------------
2. Source file format
---------------------------------------------------------------------------


       "The average reader knows hardly anything about textual
        criticism... and often shares the writer's prejudices.
        Stand on a barrel in the streets of Bagdad, and say in a
        loud voice, "Twice two is four, and ginger is hot in the
        mouth, therefore Mohammed is the prophet of God," and
        your logic will probably escape criticism; or, if anyone
        by chance should criticise it, you could easily silence
        him by calling him a Christian dog."

                (A. E. Housman, "The Application of Thought to
                 Textual Criticism")


Lines in an Inform file are terminated by semicolons.  An exclamation mark
! thus...
denotes that the rest of its physical line is a comment.  Backslashes "fold"
strings up, so that for example

initial "A hinged trapdoor in the floor stands open, and light streams in \
         from below."
         
is treated as if the "f" in "from below." follows directly from where the
backslash \ is; i.e., the carriage return and leading spaces are removed.

Tab characters are treated as spaces outside inverted commas, but should not
be used inside them.

Inform command names are not case sensitive, and nor are variable names.
However, reserved words after the initial command (such as the "to" in a
"for" construction) must be in lower case.

There are seven kinds of line:

                               Examples

  routines starting            [ NewRoutine i j;
  and stopping                 ];

  assignments                  fred = parent(lamp);
  and function calls           Verify();

  compiled commands            for (i=1:i<=100:i++) print i;

  directives                   #Release 4;

  assembly language            @prop_len_addr lamp lv;
  labels                       .Label;


In practice, you don't need to know the assembly language at all, but it's
there.


---------------------------------------------------------------------------
3. Compiler directives
---------------------------------------------------------------------------


        "...and yet the [European Community] directive on importation
         of caramel is over 20,000 words long."

               (An anti-European speaker at the 1993 Conservative
                Party Conference: sadly, though, the directive in
                question is apocryphal)


Directives are instructions to Inform which do not themselves make code,
though they change the way code is subsequently made.  They can be prefaced
by a # character, as in C, but need not be.

ABBREVIATE <string>                  Declare abbreviation (see (19))
ATTRIBUTE <name>                     Make new attribute flag

CLASS ...                            Declare an object class (see below)

CONSTANT <name> <value>              Declare a constant

END                                  End compilation here (this is optional)

ENDIF                                End of conditional compilation

GLOBAL <name> [ = <a> ]              Make a new global variable;
                                       [give it the initial value a]
              [ string <a> ]           [make it point to an (a+1)-byte array,
                                         which has <a> as first byte, and is
                                         otherwise zeros]
              [ data <a> ]             [make it point to an a-byte array,
                                         which is all zeros]
              [ initial <i1> ... ]     [make it point to an array, the bytes
                                         of which are as given]
              [ initstr "text" ]       [make it point to an array, the bytes
                                         of which are the ASCII values of the
                                         characters in the string]

IFDEF <name>                         Compile if constant name defined
IFNDEF <name>                        Compile if constant name undefined
IFNOT                                "Else" for conditional compilation
IFV3                                 Compile if version is set to 3
IFV5                                 Compile if version is set to 5

INCLUDE <filename>                   Include a file in the source

NEARBY ...                           Make an object near the last (see below)
OBJECT ...                           Make an object (see below)
PROPERTY ...                         Make a new property (see below)

REPLACE <routine-name>               Declare that this system file routine
                                     will be replaced in the game source

RELEASE <a>                          Set the release number to <a>

SERIAL <string>                      Set the serial number to <string>
                                        (it must be a six-digit number, and
                                         defaults to the date in the form
                                         YYMMDD if Inform has access to
                                         today's date, or to 940000 if it
                                         hasn't)

STATUSLINE score                     Make the status line show score/turns
           time                      ...show hours/minutes

SWITCHES <switches>                  Declare default switch settings
                                     (eg:  SWITCHES dexs
                                     causes "inform filename" to be read as
                                     "inform -dexs filename")

VERB ...                             Enter grammar for a new verb (see below)
EXTEND ...                           Extend the grammar for a verb

VERSION n                            Sets Inform to version 3 or 5

The following are mainly for debugging the compiler (should anyone ever
get around to doing this) but might sometimes be amusing or helpful:

LISTSYMBOLS                          List the symbol table
LISTDICT                             List the dictionary
LISTOBJECTS                          List the object tree
LISTVERBS                            List the verb table

(the names of which have changed since releases 1 and 2),

TRACE                                Trace assembler
LTRACE                               List the lines of input
ETRACE [full]                        Trace expression evaluator
                                     (rather lavishly if "full" is set)
BTRACE                               Trace assembler on both passes
NOTRACE, NOLTRACE, etc               Turn off appropriate tracing

And there are six more rather technical directives:

DEFAULT <cname> <value>              If the constant has not yet been
                                     defined, define it with this value
LOW_STRING <name> <string>           Puts a string in the "low strings" area,
                                     and creates a constant to hold its word
                                     address (see (18)).
STUB <rname> <n>                     If the routine has not yet been
                                     defined, define one which has n local
                                     variables and always returns false
DICTIONARY <name> <text>             Enter <text> in dictionary, and make
                                     a new constant for its address
                                     (this usage is obselete, since, e.g.
                                     #n$theword is much better)
FAKE_ACTION <name>                   Create a fake action: one which can be
                                     treated as an action but corresponds to
                                     no actual routine
SYSTEM_FILE                          Declares the present file to be a
                                     system file (from which routines can be
                                     REPLACEd)

Conditional compilation allows code for routines which need only exist in
some "versions" of your games.  For instance,

  print "Welcome to the ";
  #IFV3;
    print "Standard";
  #IFNOT;
    print "Advanced";
  #ENDIF;
  print " version of Zork LVI.";

Note the trailing semicolon: Inform is not C!  Such clauses may be nested up
to 32 deep, and may contain whole routines.  They may not, however,
conditionally give _part_ of a statement.  Thus, for instance,

  print 
  #IFV3;
    "Standard";
  #IFNOT;
    "Advanced";
  #ENDIF;

is _not_ legal.


---------------------------------------------------------------------------
4. Variables
---------------------------------------------------------------------------


       "I found it necessary to introduce the restriction that
       quantifiers may only be applied to formulae which actually
       involve the quantified variable...  I can well imagine that
       professional logicians will find this hard to swallow... but
       I would ask them to reflect, before they condemn me, on
       whether anyone _other_ than a logician would find this
       restriction at all odd."

              (P. T. Johnstone, "Notes on logic and set theory")

       "Variables don't; constants aren't."

              (old computing saying)


There are two kinds of variable, global and local (plus one special one).

Variables are all two-byte integers, which are treated as signed when it
makes sense to do so (eg. in asking whether one is positive or not) but
not when it isn't (eg. when it is used as an address).

There can be up to 240 global variables; as indicated in (3), these can be
initialised to point to dynamic workspace, so as to achieve the effect of
strings and arrays.  They have to be declared before use.  For instance:

  Global turns = 1;
  Global buffer string 120;   ! Buffer holding 120 characters
  Global task_scores initial 4 5 9 1 2 3 0;

In an array, the n-th byte is called

  array->n

and the n-th word (the n-th double-byte value, i.e.
256*array->(2*n)+ array->(2*n+1)) is called

  array-->n

In a string array, the bytes correspond to ASCII characters.  They are not
encrypted in the way that standard game text is.


In any routine, there can be up to 15 local variables.  These are declared
when the routine begins.  (There is one exception: the special Main routine
may not have local variables.)


WARNING: There is also a stack, but it should be tampered with only with
   *     care.  Never call a variable "sp", as this is the stack pointer,
  /!\    and be careful not to leave values on the stack: or the game may
 *---*   crash 1000 turns later, highly mysteriously.


[Inform in fact reserves the top three global variables to itself, for
temporary calculations.  The observant reader will have noticed that
240+15+1 = 256.  This is of course no coincidence.]


---------------------------------------------------------------------------
5. Constants
---------------------------------------------------------------------------


        "I cannot call this constant "Caratheodory" because it already
        has another name, namely 1/16."

               (E. Landau: Caratheodory's constant had only recently
                been evaluated)


Constants may be prefixed with a # character if desired.  This can be useful
if they are alphabetical and might otherwise be confused with something else.

A constant in "double quotes" assembles the given text at a suitable (even)
  address, and gives half this address as the integer value.  Inside this
  text the character ^ is replaced by a newline character, and the character
  ~ by a double-quote mark.  In practice you seldom need to worry where the
  text is stored, or how.

  Inside a string, @dd (an @ sign followed by two decimal digits) is
  compiled to the synonym of that number.  When the Z-machine finds this, it
  prints the string pointed to by that entry in the synonym table.  (This is
  useful in altering object short names - see section (18).)

A character in single quotes, such as 'e', means the ASCII value of that
  character.  (This is true even on machines not using ASCII, of course.)

A word (of longer than one character) in single quotes, such as 'herring',
  means the address of that word in the Dictionary (it is created if not
  already present).

A dollar $ indicates that a hexadecimal constant follows; $$ indicates that
  binary follows.  A minus sign indicates a negative number.  (Internally
  these are stored in the usual two-byte fashion, e.g. -1 = $ffff, -2 =
  $fffe and so on.)

A double # indicates an action (action numbers are sometimes explicitly
  needed as numbers).  So, for instance, ##Take.  (Fake actions also have
  numbers and can be referred to thus.)


Any constant declared in a directive can be quoted, and so can the various
special constants (set up by Inform) which are of purely technical utility:

  adjectives_table   (byte address)
  preactions_table   (byte address)
  actions_table      (byte address)
  code_offset        (packed address of code)
  strings_offset     (packed address of strings)
  version_number     (3 or 5 as appropriate)
  largest_object     (the number of the largest created object + 256)
  dict_par1          (see the description of the Dictionary)
  dict_par2
  dict_par3      

Old Inform syntax which is still allowed:

  A constant beginning a$, followed by the name of a routine which is an
  action routine, will have as value the number of the action.
  (For instance, #a$TakeSub.)

  A constant beginning w$, followed by a word of text, has as value the
  address of the given word in the dictionary (Inform will give an error at
  compile time if no such word is there).

  A constant beginning n$, followed by a word of text, has as value the
  address of the given word in the dictionary (Inform adds it to the
  dictionary as a new word if it is not already there).

  A constant beginning r$, followed by a routine name, gives the (packed)
  address of the given routine.  (This is needed for changing
  property values which are routine addresses.)

Thus, for instance, the following are legal constants:

  31415
  -1
  $ff
  $$1001001
  #adjectives_table
  'lantern'
  ##Look
  'X'
  "an emerald the size of a plover's egg"
  "~Hello,~ said Peter.^~Hello, Peter,~ said Jane.^"
  #r$FireRodRoutine
  


---------------------------------------------------------------------------
6. Routines
---------------------------------------------------------------------------


       "Habit!  That skillful but slow-moving arranger who begins
       by letting our minds suffer for weeks on end in temporary
       quarters, but... without it, reduced to their own devices,
       [our minds] would be powerless to make any room seem
       habitable."

             (Proust, Overture to "A La Recherche du Temps Perdu")


There are two kinds of routine: global ones, and ones embedded in the
definition of some object.  This section is about global routines.

The syntax to begin a routine is

  [ RoutineName <l1> ... <ln>;

and to end it, is

  ];

l1 to ln are the names of local variables, which are also the call
parameters.  For example, if you have a routine

  [ Look i j k;
    ...some code...
  ];

and it is called by

  Look(attic);

then i will initially have the value "attic" when this is executed.
Any local variables not specified (in this case, j and k) are initially
zero.  It should be emphasized that it is legal to call Look with 0, 1,
2 or 3 arguments.  (Three is the maximum number of arguments any routine
can have.)

Every routine returns a value to the caller; if no such value is
explicitly given, this value is the integer 1 ("true").  (Except in the
case of routines embedded in object definitions, when it is 0, or "false".)
In a line like

  Banner();

the return value is thrown away.

Inside a routine, labels may be declared with a line of their own:

  .labelname;

but note that whereas local variables have names which only mean anything
locally, labels have names which are global.  In other words, you can't
have a label called "loop" more than once in the file.  (It is legal to
jump from one routine to a label inside another one, but rather dangerous.)

There is one special routine, which you must define, called Main.  This is
where execution of the game will begin, and it _must_ be the first one
defined.  Also, uniquely and for peculiar reasons, Main is _not_ permitted
to have any local variables of its own.  This means it is usually only used
as an outer shell.

(Inform issues a warning if the earliest defined routine is not called
"Main".)


WARNING: Returning from Main will cause the interpreter to crash: you
   *     should explicitly use the "QUIT" instruction instead.
  /!\    
 *---*   



---------------------------------------------------------------------------
7. Expressions and assignments
---------------------------------------------------------------------------


        "His expression may often be called bald - but it is bald
        as the bare mountain tops are bald, with a baldness full of
        grandeur."

              (Matthew Arnold, of Wordsworth)


The usual arithmetic expressions are allowed, including the operators:

    + -           plus, minus
    * / % & |     times, divide, remainder, bitwise and, bitwise or
    -> -->        byte, word array entry
                  (eg: buffer->4 gives contents of the byte with address
                  buffer+4, while table-->3 gives the word at table+6)
    . .& .#       property, property address, property length (see (11))
    -             unary minus
    ++ --         as in C: frog++ gives the value of frog and then
                  increments it, whereas ++frog increments it and then
                  gives the value; -- decrements similarly
                  (these may only be applied to variables)

The order of precedence is as shown: i.e. those on each line are equally
potent, more potent than those above but less than those beneath.
                  
In addition one may call a function, either a built-in function or a
routine within the source code.

Expressions may not contain conditions, and assignments may not be made
within an expression, so, for instance,

  2+(i=3/j)

is not allowed.  In other words, = is not quite an operator.

There are four forms of assignment statement allowed:

  variable = value;

  byte_array->entry = value;
  word_array-->entry = value;

  object.property = value;


For example:

  4*(x+3/y)
  Fish(x)+Fowl(y)
  lamp.time
  buffer->5

  i=-15-j;
  i=j-->1;
  turns++;
  albatross.weight = albatross.weight + 1;
  (paintpot.&roomlist)-->i = location;

Although

  paintpot.#roomlist = 5;
  paintpot.&roomlist = array;

look logical, they are not allowed: one cannot change the size and location
of a property once the game is in play (see (11)).


WARNING: Interpreters can crash very mysteriously if a division by zero
   *     (or an attempt to find remainder-after-division by zero) takes
  /!\    place.
 *---*   


---------------------------------------------------------------------------
8. Commands
---------------------------------------------------------------------------


         "My name is OZYMANDIAS, king of kings:
         Look on my works, ye Mighty, and despair!"
         Nothing beside remains.  Round the decay
         of that colossal wreck, boundless and bare
         The lone and level sands stretch far away.

                  (Shelley)


(a) Printing commands
---------------------

         To begin the "high level" commands in Inform, we list the printing
         commands.  (The wrapping of lines is of course automatic.)


<a string on its own>

         A string on its own, such as

         "The world explodes in a puff of garlic.";

         is printed as if by PRINT_RET: i.e., it is printed, a carriage
         return is printed and the current routine is returned from with
         return vale "true", i.e., 1.


NEW_LINE                       Print a carriage return

PRINT ...list of things...
PRINT_RET ...list...

         PRINT and PRINT_RET are general printing commands, to be given
         a list of items separated by commas.  PRINT_RET differs from PRINT
         in that when it finishes, it prints a carriage return and returns
         from the current routine with return value true (or 1): this is
         a convenient shorthand.

         Items in the list must be

         <quoted text>         A string to print out
         <expression>          A number to print
         char <expression>     An ASCII code to print
         object <expression>   An object to print the short name of

         Within a text string, an up-arrow character ^ becomes a carriage
         return and ~ a double-quote.  (For fuller details of printing, see
         (5), (17) and (19).)

         So, for example,

             print_ret "Your score is ", score, " out^of ", max_score, ".";

         might produce the output

             Your score is 146 out
             of 10000.

SPACES <n>                     Print <n> spaces (if n<=0, print nothing)

PRINT_NUM <a>                  Print <a> as a (signed) decimal number
PRINT_CHAR <a>                 Print the character whose ASCII value is <a>
PRINT_OBJ <a>                  Print the short name of object <a>

         There are a few more technical printing commands also:

INVERSION                      Prints (in the game, not at compile time)
                               the version number of Inform used to
                               compile the story file
PRINT_ADDR <a>                 Print the string whose address is a
PRINT_PADDR <a>                Print the string whose address is
                                  2*a (in version-3)
                               or 4*a (in version-5)
STRING <n> <text>              Set the nth indirect string to text (see (18))
FONT on                        Turn proportional fonts on/off (see (20))
     off

STYLE roman                    (Version 5 games only)  Set the text style
      reverse                  (see (20))
      bold
      underline

BOX <text1> ... <text2>        (Version 5 only)  Highlight a text window
                               (see (20))


(b) Object manipulation (see (11))
----------------------------------


REMOVE <a>                     Remove object a from the tree of objects
                               (it may certainly be later put back)
MOVE <a> TO <b>                Add object a to the things possessed by b

WRITE <object> <p1> <v1> [<p2> <v2>...]        Change properties
GIVE <object> <a1> [<a2>...]                   Change attributes
         
         These set several properties or attributes of the given object
         at once.  (Attributes may be preceded by a tilde ~, in which case
         they are removed rather than added.)  For example,

             give lamp light ~open container scored;
             write lamp timeleft 50 brightness "flickering";


(c) Control commands
--------------------


         We begin the control commands, perversely perhaps, with the
         remaining ways to return from the present routine (apart from
         PRINT_RET and an <<action>>):

RETURN                         Return (actually, return true, i.e. 1)
RETURN <a>                     Return the value a
RTRUE                          Return true, i.e. the value 1
RFALSE                         Return false, i.e. the value 0
                               (These used to, and still can, be called
                               "ret#true" and "ret#false".)

         The next few constructions involve conditions and blocks of code.
         See (9) for proper definition of conditions.  A block of code may be
         a single instruction or a series of several, in which case it must be
         enclosed in braces '{' and '}'.  Thus, for instance, in

             if (i==1) print "The water rises!";
             if (i==2) { print "The water rises further...";
                         water++;
                       }

         the if statements contain a block of code each.  Blocks can be nested
         inside each other up to 32 deep.  An if statement (for example) is a
         single statement even when it contains a great deal of code in its
         block: so, for example,

             if (i>1)
                 if (water<10)
                      print "The water is beginning to worry you.";

         is perfectly legal.  (One small exception: an if followed by an else
         counts as two expressions, so in

             if (i>1)
                 if (water<10) print "Glug...";
                               else print "Arrghh...");

         the else belongs to the _outer_ if.  So it's wise to brace
         if...else... expressions as one block.)

         [In previous editions of Inform, much less sophisticated
         constructions were allowed: conditions were much simpler, and were
         not bracketed, as in:

             if i==1 { print "The water rises!"; }

         This syntax is still permitted.  But unless the condition is
         bracketed, the braces are compulsory in accordance with old-style
         syntax.]

         As the reader has probably surmised, we have "if" and other
         standard loops:

IF <condition>                 Execute if the condition holds
  { ... code ... }
[ ELSE
  { ... other ... } ]          [or execute this if not]

WHILE <condition>              Execute while the condition holds
  { ... code ... }

DO                             Execute until the condition fails
  { ... code ... }
UNTIL <condition>

         and also a "for" loop which is quite powerful.  Inform used to
         implement only a BASIC-style FOR loop, but is now able to code a
         C-style one.  The old, simpler style looks like:

FOR <var> <init> TO <final>    Execute the code iteratively, starting with
  { ... code ... }             <var> set to <init> and incrementing it each
                               time until it is bigger than <final>: if the
                               final value is actually less than the initial
                               one, then don't execute the code at all

         (again, braces are compulsory for such a usage) but the new style is

FOR ( <initial assignment> : <condition> : <end assignment> )
  { ... code ... }  

         which carries out the initial assignment, then executes the code
         for as long as the condition holds, executing the end assignment
         after each pass through the code.  For instance,

             for i 1 to 10 { print i, " "; }

             for (i=1:i<=10:i++) print i, " ";

         are old- and new-style ways to write the same loop.  But the new
         style is capable of much more.  For one thing, several different
         assignments are legal at once, if separated by commas.  So, for
         example,

             for (i=0,j=10:i<10:i++,j--) print i, " + ", j, " = ", i+j, "^";

         All three clauses are optional: if the assignments are missed out,
         nothing is done at the appropriate moment; if the condition is
         missed out, it is always true.  So, for instance,

             for (::) print "Ha!^";

         laughs maniacally forever.


         A useful loop construction in Adventure games is:

OBJECTLOOP ( <var> from <obj> )  { ... code ... }
                   near <obj>
                   in   <obj>

         which loops the variable through the object tree: either

           from the given object through all its siblings, or
           through all objects with the same parent as the given object, or
           through all children of the given object.

         So for instance

             objectloop (x in lamp) { print_obj x; new_line; }

         is equivalent to

             for (x=child(lamp): x~=0: x=sibling(x))
             { print_obj x; new_line; }

         but the shorthand is convenient.

WARNING: When looping through the object tree, be careful if you are altering
   *     it at the same time.  For instance,
  /!\      objectloop (x in rucksack) remove x;
 *---*   is likely to go horribly wrong - it's safer not to cut down a tree
         while actually climbing it.

         It is legal to jump in and out of loops in the obvious way, but this
         makes for somewhat unattractive code.  (And that would never do.)
         A compromise measure is:

BREAK                          Break out of the current loop (not block)

         However, no language would be complete without:

JUMP <label>                   Jump to the label (warning: it is unsafe to
                               jump out of one routine into another)

         As a demonstration of the loop constructs, here is an inefficient
         routine to try: Primes(100) should print out prime factorisations of
         the numbers from 2 to 100.

             [ Primes i j k l;
               for (j=2:j<=i:j++)
               {   print j, " : ";
                   l=j;
                   while (l > 1)
                       for (k=2:k<=l:k++)
                           if (l%k == 0)
                           {   l=l/k;
                               print k, " ";
                               break;
                           }
                   new_line;
               }
             ];

         (A program of historical value only - slightly more clumsily
         expressed, this was the first non-trivial program Inform compiled.)


(d) Causing Actions
-------------------

         A special form of command causes an action to happen as if the
         player had typed it at the keyboard, according to the normal game
         rules.  This takes either the form

< Action [first-object [second-object]] >

         or

<< Action [first-object [second-object]] >>

         The latter returns "true" from the current routine after carrying
         out the action.  The former does not return.

         (Inform does very little to achieve this: it simply generates a
         function call, which the library is expected to provide.)



(e) Miscellaneous and rarely needed commands
--------------------------------------------


INC <var>                      Increment variable
DEC <var>                      Decrement 

PUT <addr> BYTE <index> <v>    Write byte value v into index byte after addr
PUT <addr> WORD <index> <v>    ...and similarly for words

         (these are now superceded by the new assignment forms
             addr->index=v;
             addr-->index=v;
         but the commands are retained for compatibility)

SHOW_SCORE                     (Version 3 only)  Redisplay the score bar
                               immediately, without waiting for the next
                               keyboard input: avoid use of this if possible


         The remaining commands need not be used if the library is being
         included:

QUIT                           Quit the game (at once, with no confirmatory
                               question to the user): all games must end this
                               way, since it is illegal to return from Main()
RESTART                        Restart the game from its initial state
SAVE <label>                   Try to save the game (asking the user for a file
                               to put it in): if successful, jump to the label,
                               otherwise carry on
RESTORE <label>                Ditto, but restore the game
VERIFY <label>                 Ditto, but verify that the game is intact

READ <a> <b> [<routine>]

         Read keyboard into buffer a and decompose it to the buffer b:

         on entry a[0] = size of text buffer, b[0] size of parse buffer

         on exit  a[0] and b[0] are preserved

                  a[1] = no characters typed
                  a[2] to a[a[1]+1] are the characters (unterminated)

                  b[1] = number of words typed (note that the special
                         separating characters such as ',' are words in their
                         own right)
                  and then from byte 2, b contains 4-byte chunks, one for

                  each word of input:

                  0,1  address of dictionary entry if recognised,
                         0000 otherwise
                  2    number of letters in word
                  3    first char of word in a

         If compiling in version 3, this command automatically redisplays
         the status (score) line.  Any routine given is ignored.
         In version 5, if no routine name is given, Inform compiles code
         emulating what a version 3 game would have done; if a routine name
         is given, the routine is called to print a status line instead.


If a command matches none of these, or if it began with an @ character, the
line is sent to the assembler instead.  Some of the assembler opcodes are
fairly usable (see Appendix A), but the essential features of the Z-machine
can be got at with just the high-level commands and functions.


---------------------------------------------------------------------------
9. Conditions
---------------------------------------------------------------------------


        "So I told him:  "Money.  As much money as you could give
        us.  And with as few conditions as you could possibly make."
        And that's where we stand."

                (C. P. Snow, "The Masters")


A simple condition is

  <a>  <relation>  <b>

where the relation is one of

  ==            a equals b
  ~=            a does not equal b
  <  >  >=  <=  comparisons
  has           object a has attribute b at the moment
  hasnt         ...has not...
  in            object a is currently held by object b
  notin         ...is not...
  near          objects a and b have the same parent
  far           ...have not...


With == (and ~=) only, one may also write the useful construction

  <something> == <v1> [or <v2> [or <v3>]]

which is true if the first something is any of the values given.


Conditions can be combined by the && and || operators:

  <condition1> && <condition2>

which is true if both are true, and 

  <condition1> || <condition2>

true if either is true.  These can be bracketed together.


Compound expressions are always tested left to right until the outcome
is known.  So, for instance,

  i==1 || Explode(2)==2

does not call Explode if i is 2.


For example:

  i==1 or 2 or 3
  door has open || (door has locked && parent(key)==player)


Conditions do not have to bracketed (as they would have to be in C).
However, they can be, and for control constructs like

    if (i==1) { ... }
    while (j==2) { ... }
    do { ... } until (k==3);

this is advisable though not insisted upon by Inform (for the sake of
compatibility with earlier releases).  Even so, individual simple
expressions don't need bracketing, so

    if (i==1 && j==2) { ... }

is perfectly legal.


---------------------------------------------------------------------------
10. Built-in functions and random numbers
---------------------------------------------------------------------------


       "ROS: [throwing a coin]  Heads.

        ROS: [again]  Heads.

        ROS: [again]  Heads.

        ROS: [again]  Heads.

        ROS: [again]  Heads.

        GUIL:  [flipping a coin]  There is an art to the building
               up of suspense."

        (Opening lines of "Rosencrantz and Guildenstern are Dead",
         Tom Stoppard)


The built in functions are

  PARENT(obj)      parent object

  SIBLING(obj)     sibling object
  CHILD(obj)       child object

  CHILDREN(obj)    number of children

  ELDEST(obj)      eldest (added longest ago) child object
  YOUNGEST(obj)    youngest (most recently added) child object
  ELDER(obj)       next oldest child object
  YOUNGER(obj)     next youngest child object

for reading the object tree (see (11) below), together with

  RANDOM(x)        give a uniformly random number between 1 and x

  INDIRECT(addr)   call the routine whose address is in addr
                   and take its return value (see (19))

and

  PROP_LEN(addr)   property length
  PROP_ADDR(o,p)   property address
  PROP(o,p)        property value

which are now obselescent: see (11) below.


Warning: some interpreters set up their random number generator with poor
choices of seed value, which means that the first few random numbers may be
rather peculiarly distributed.  ("ROS: Heads.")   After a time, it settles
down.  ("ROS: Heads.")  To get around this, "Curses" (for example) takes
and throws away 100 random numbers when it begins.  ("ROS: Seventy-six love.")

In Version 5 and on benign interpreters only, RANDOM(-x) makes the generator
produce predictable values for a while: see the dictionary of opcodes
under "random".


WARNING: Trying to execute RANDOM(0) at run time can crash the interpreter
   *     because of trying to find a remainder after division by zero.
  /!\    
 *---*   


---------------------------------------------------------------------------
11. Objects, attributes and properties
---------------------------------------------------------------------------


     "...making philosophical sense of change runs up against what
     seem to be impossible philosophical difficulties.  Aristotle...
     focuses on the central case of an object coming to have a
     property that it formerly lacked."

          (Julia Annas, "Classical Greek Philosophy")


The object hierarchy is a tree of "objects", which you might use for many
different game elements: rooms, compass points, scenery, things which can be
picked up, and so on.


They are numbered upward from 1, and the number 0 by convention means
"nothing".


WARNING: Attempting to print_obj object 0 will produce a string full of
   *     peculiar letters or (if you are very unlucky indeed) even random
  /!\    ASCII values followed by an interpreter crash.
 *---*   It is also unwise to apply SIBLING, PARENT or CHILD to 0.


In the tree, each object has a parent, a sibling, and a child.  Thus, for
instance, a portion may resemble

            Meadow
               |
            Mailbox -> Player
               |          |
             Note      Sceptre -> Cucumber -> Torch -> Magic Rod
                                                |
                                              Battery

in which -> shows siblings, and | parents and children.  In this case, the
Meadow has nothing as its parent.  Anything with no possessions, such as the
note, has nothing as its child, and so on.

When an object is moved, its possessions move with it.

The PARENT, SIBLING and CHILD functions read this tree in the obvious way.
It is sometimes convenient to know how many direct possessions an object
has and CHILDREN(object) returns the number.  Thus, for instance,

        PARENT ( Mailbox ) = Meadow
        CHILDREN ( Player ) = 4
        CHILD ( Sceptre ) = 0
        SIBLING ( Torch ) = Magic Rod

CHILDREN(0)=0, but it is undefined what CHILD, SIBLING and PARENT do to the
"nothing" object: so don't apply them to it.

When an object is added to the possessions held by another, it appears at
the end of the list.  Thus, the eldest child is first in the list and the
youngest is last.  Inform also provides functions

        YOUNGEST     end of list of possessions
        ELDEST       same as CHILD
        YOUNGER      same as SIBLING
        ELDER        reverse of SIBLING


In practice an object needs rather more data than just a position in a tree. 
It also has a collection of variables attached to it.

Firstly, there are flags, called "attributes", which can be either set or
clear.  These might be such conditions as "giving light", "currently worn"
or "is one of the featureless white cubes".  All these are free for the
programmer to use (though the Library routines, if in use, consume many of
them).  They must be declared before use, by directives like

  ATTRIBUTE locked;

which will allocate a new attribute and make a constant "locked" to have the
value of its number.  You never then need to know about these numbers,
because you can use commands like

  IF (obj has locked) "But it's locked!";

  GIVE obj locked;

The limit on the number of attributes can quite easily be hit.  The author
has found it useful to declare one as "general", to be used for different
things for different objects.  (And this is done for you in the library.)

It sometimes happens that an attribute is only meaningful for a particular
kind of object: for instance, "spell has been read" might only be meaningful
for a "scroll".  With care, therefore, one may re-use the same attribute to
have different meanings for different kinds of object.  The syntax to
declare that an attribute is being reused is

  ATTRIBUTE <new> alias <old>;

Thereafter Inform will treat the new and old attribute names as referring
to the same attribute: it's up to the programmer to make sure this does not
lead to inconsistencies.


Secondly, there are "properties".  These are far more elaborate.  For one
thing, not every object has every property.  The following all declare new
properties:

  PROPERTY door_to;
  PROPERTY article "a";
  PROPERTY blorpleroutine $ffff;

The value given, in the case of article and blorpleroutine, is the default
value: that is, the value of the property which an object will have if it
doesn't explicitly have some other value.  If you don't define a default
value, it will by default be 0.

So, for instance,

  frog.door_to

will be 0 if "frog" has no door_to entry.

The data for a given property can be a single number, or an array of
values.  In Standard (version 3) files this consists of up to four numbers
in a row, or up to eight bytes of data; in Advanced (version 5) files it
can amount to 32 numbers or 64 bytes.

But the vast majority of properties are single numbers.  The simplest way to
get at the current value is something like

  i = location.door_to;

which will get the first number in the property door_to of object location.
Similarly, it can be written to with

  location.door_to = hall_of_mists;

or (if preferred)

  WRITE location door_to hall_of_mists;


WARNING: The Z-machine crashes if you attempt to write to a property field
   *     which an object hasn't got.  So although you can read an undeclared
  /!\    property (you just get the default value), you can't write to one.
 *---*   (Also, you can't extend a property beyond its length.)


A subtle point is that numbers smaller than 256 are stored differently from
larger ones.  In order to decide whether the property is one byte's worth or
two, the Z-machine looks at the number of bytes which the property has in
all, and sees whether it is odd or even; if even, it presumes the number is
a 2-byte word; if odd, it presumes it is just one byte.

This is seldom something you need to know about, but occasionally you will
want a property which will, later in the game, need to hold a value of, say,
1000, but which initially will be zero.  This is particularly the case with
timing mechanisms, for instance.  The command

  PROPERTY LONG timeleft;

declares the property "timeleft" and requires Inform to make sure that all
"timeleft" fields are 2 bytes wide, even if they have small initial values.

(In Version 5 only, all properties are defaulted to LONG because property
values are very often object numbers, which are usually but not always less
than 256; this makes code more portable and wastes few bytes.)

Properties can also be aliased, by

  PROPERTY <new> alias <old>;

but "PROPERTY LONG <new> alias <old>" is meaningless: the property has
whatever length it was originally set up as having.


More elaborate manipulation has to be done by hand.

  k = o.&weird;

sets k to the address of the "weird" data of object o.  To find out how many
bytes there are, try:

  l = o.#weird;
    
Once you have the address you can read and write to it directly.  Be careful
not to overrun the length, which may not be changed.


The functions

  PROP(object,property)
  PROP_ADDR(object,property);
  PROP_LEN(PROP_ADDR(object,property));

duplicate the effect of

  object.property
  object.&property
  object.#property

but are now superceded by them.


An object is declared by something like:


Object trapdoor "hinged trapdoor" attic
  with name "hinged" "trap" "door" "trapdoor",
       when_open "A hinged trapdoor in the floor stands open, and light \
                  streams in from below.",
       when_closed "There is a closed trapdoor in the middle of the floor.",
       door_to house,
       door_dir d_to
  has  door static open light openable;

trapdoor is a constant which is set to its object number; "hinged trapdoor"
is its attached short name; attic is the object which initially possesses
it.  If it was to be initially unowned, this could be "nothing" instead of
"attic".  Or one can simply omit it altogether:

Object trapdoor "hinged trapdoor"
  with ...

would initially be outside the game (and could be brought in later).


Objects can also be declared, in an identical way, by the NEARBY command.
The only difference is that no object can be given to initially possess it;
it initially belongs to the last declared OBJECT.  E.g., in

Object hillside "Panoramic Hillside"
  with ...

Nearby scenery "scenery"
  with ...

the hillside is to be a room, and the scenery will belong to it.


The full syntax of the header is:

     Object <obj-name-1> <obj-name-2> ... <obj-name-n>
            "short name" [<parent-obj>]

or   Nearby <obj-name-1> <obj-name-2> ... <obj-name-n> "short name"

or   Class  <class-name>

and of an object is

     <Header> [,]
     "class" <class-1> <class-2> ... <class-n>[,]
     "with"  <property-name-1> <value-1> ... <value-n>,
             <property-name-2> <value-1> ... <value-n>,
             ...
             <property-name-n> <value-1> ... <value-n> [,]
     "has"   <att-1> <att-2> ... <att-n>[,]

Although it's conventional to write "class", "with" and "has" in this order,
actually they can be in any order and any or all can be omitted altogether:
and the commas in square brackets [,] are optional in between these fields.

[Notice that you may give an object more than one internal name, thus:

  OBJECT frog tree brick "frog" attic
    with ...;

after which the same object can be called frog, tree or brick within the
source code: in other words, several constants are created with the same
value.  Why on earth should you want this?  - See section (18).]


"With"
------

Warning: an excellent source of mysterious errors is missing off the commas
between the properties, since property names are themselves legal constants.
Inform warns you if a property name is used as a constant after the first
entry of a property, which although legal is probably this mistake.

There is one special property, called "name".  Its data must be (up to four
at most in version-3, or up to thirty-two in version-5) words, as above, and
these are entered into the dictionary as nouns (if they aren't already):
the property data actually stored is the dictionary addresses.

Note that the dictionary itself does _not_ know that "door" refers to this
object: there might be any number of objects which could be called "door".


If you give a property more than eight bytes of data in a version-3 game,
Inform warns you and takes only the first eight, but does not cause an
error: this is so that, say,

  OBJECT ...
    with name "radio" "wireless" "transistor" "portable" "stereo" "tranny",
         ...

will compile on either version-3 or version-5 (but the last two synonyms
for "radio" will not enter the dictionary if it's being compiled as
version-3 since a name takes two bytes).


"Has"
-----

After "has" is a list of attributes which the object initially has.
These attributes may also be taken away.  For example:

  ...
  has  light ~scored;

declares that the object definitely doesn't have the "scored" attribute.
This is needed for over-riding inheritances.


In Version 3 games (the default) there are up to 255 objects, each with 32
"attribute" flags and up to 30 "properties" (collections of data).  In
Version 5 there is no limit as such on the number of objects, and the other
limits are increased to 48 and 62 respectively.


---------------------------------------------------------------------------
12. Routines embedded in objects
---------------------------------------------------------------------------


Some properties of objects should be routines.  For instance, in the
standard Inform library, an object can have a "describe" property which is a
routine to print out a description of it.

These can either be declared as any other property would be, by giving
the name of the routine as the property value, or can be actually included
in the definition.  For instance, in the classic Adventure object


Nearby tasty_food "tasty food"
      with description "Sure looks yummy!",
               initial "There is tasty food here.",
           name "food" "ration" "rations" "tripe"
                "yummy" "tasty" "delicious" "scrumptious",
           after
           [; Eat: "Delicious!"; ],
           article "some"
      has  edible;


the "after" property does not name a routine but instead defines it.  No
name is needed for the routine.  However, the semicolon after the [ is
needed: a list of local variables follows the [ (but in this example there
are none).

The routine must end with either "]," or "];".  If "]," the object definition
can resume where it left off, with further properties.  (If it ends with
"];", then the object definition ends where the routine finishes.)


The rules for embedded routines are slightly different.  By default,
they return "false", or 0 (instead of "true", which other routines return
by default).  They also allow a handy shorthand:

    Action [, Action2 ...] : ...some code...

executes the code only if the action being considered is the one named.

(Inform actually does this by seeing if the "switch variable" sw__var,
which it expects to have been suitably set up by the library, has the
given action values.)


---------------------------------------------------------------------------
13. Classes and inheritance
---------------------------------------------------------------------------


As well as objects one can define classes in almost exactly the same way.
The only differences are that a class has no short name or initial location 
(since it does not correspond to a real item).  For example,

    Class Treasure
     with depositpoints 10,
          after
          [; Take: if (location==Inside_Building)
                        score=score-self.depositedpoints;
                   score=score+5;
                   "Taken!";
             Drop: score=score-5;
                   if (location==Inside_Building)
                   {   score=score+self.depositedpoints;
                       "Safely deposited.";
                   }               
          ],
     has  valuable;

defines a class.  An object of this class inherits the properties
and attributes it defines: in this case, an object of class Treasure
picks up the given score and rules automatically.

To declare an object as being of a given class, one writes, say

    Nearby bars_of_silver "bars of silver"
     class Treasure
      with description "They're probably worth a fortune!",
           initial "There are bars of silver here!",
           name "silver" "bars";

The "class" field of an object can contain a list of classes,

     class C1 ... Cn

in which case the object inherits first from C1, then from C2
and so on.  These classes may well disagree with each other,
so the order matters.  If C1 says "depositedpoints" is 5,
C3 says it is 10 but the object definition itself says 15 then
the answer is 15.

Some properties, however, do not have a single value but a list
of values.  These can be declared as "additive", e.g. by

     Property additive before $ffff;

If so, each class adds values to the list in order.

Classes can themselves inherit from other classes.  Thus a class for
"like Treasure but with only 8 depositedpoints" is easily written.


---------------------------------------------------------------------------
14. Verbs and grammar
---------------------------------------------------------------------------


     "The book ends with a chapter on grammar...  The foolish and the
     wicked who lack respect for the language will not take the
     slightest notice of it."

          (Kingsley Amis reviewing the Oxford Guide to English Usage)


Whereas objects should be declared at the start of the file, the grammar
to be allowed by the game should be declared at the end.  This is done with
the VERB command.  VERB does something quite complicated, but probably not
what you think.  A typical VERB command would be:

VERB "take" "get" "pick" "lift"  * "out"                    -> Exit
                                 * multi                    -> Take
                                 * multiinside "from" noun  -> Remove
                                 * "in" noun                -> Enter
                                 * "off" held               -> Disrobe;

This declares a verb, for which "take", "get" etc are synonyms, and which
can take five different courses.  In the first, it must be followed by the
word "out".  In the last, it must be followed by "off" and then an item
which is currently held by the player.  In the second, it can be followed by
one object, or a list, perhaps specified as "everything", for instance.
There can be no grammar at all, for example

VERB "invent" "i"                *                          -> Inv;

After the "->" is the name of a routine which is to be called when this is
matched.

If a verb is declared as a meta-verb, e.g. via

   VERB meta "score"
                *                                -> Score;

then the parser will treat it as outside the game - taking no time up, and
possible at any moment.



For traditional reasons unclear to the author, previous Infocom hackers have
called words such as "out" and "off" adjectives.  They are of course
(mainly) prepositions.  We shall wearily follow convention.

Remember that the Z-machine does _not_ contain the bulk of a game parser,
only the computationally expensive and low-level part which works out what
the words are.  So this command only sets up a table with some numbers in. 
If you want a parser, you have to write code to deal with the table again.
If you're using the library routines, the parser is all done for you and
the possible tokens are:

   Token               What the library parser uses it for
   =====               ===================================
   noun                any visible object
   held                object held
   multi               one or more visible objects
   multiheld           one or more held objects
   multiexcept         one or more objects, except the other object 
   multiinside         one or more objects, inside the other object
   creature            an animate creature
   special             any single word or number
   number              a number only

   <attribute>         any visible object with the given attribute
   <Routine>           the routine is called: if it returns -1,
                         no match is made: otherwise a match is made,
                         with the value returned
   noun = <Routine>    any visible object which passes the following test:
                         the variable noun is set to the object in
                         question, and Routine is called.  If it returns
                         true, the object is accepted; otherwise not.

Look through the library's grammar table for examples.


One can also extend a previous verb definition by

   EXTEND "verb" [optional-keyword]
       ...one or more lines of grammar as above...;

This is useful for adding to the standard library's grammar table.
The optional keyword can be:

   replace      completely replace the old grammar with this one
   first        insert the new grammar at the top of the old one
   last         insert the new grammar at the bottom of the old one

The default is "last".


---------------------------------------------------------------------------
15. Exactly what Inform does with words
---------------------------------------------------------------------------


     Bulldust, coolamon, dashiki, fizgig, grungy, jirble, pachinko,
     poodle-faker, sharny, taghairm

          (some of the more readily catachrestic words from the
           265000 in Chambers English Dictionary)


This is a very technical section about exactly how Inform deals with the
grammar table and the dictionary.  It can safely be ignored by anyone
using the library routines supplied, and in fact since the remaining
sections of the manual proper are quite specialised, the next part to
read is probably Appendix C.



By convention, adjectives are numbered downwards from $ff.  Thus, if
the above were the opening lines of grammar, "from" would be $fe, and so on. 
As they are created, they are entered into the dictionary, and also into the
adjective table, which has four-byte entries

  <dictionary address of word>  00  <adjective number>
  ----2 bytes-----------------  ----2 bytes----------- 

In order to make life more interesting, these entries are stored in reverse
order (i.e., lowest adjective number first).  The address of this table is
rather difficult to deduce from the file header information, so the constant
#adjectives_table is set up by Inform to refer to it.  In any event, the
table isn't very useful and is created only for the sake of conforming to
Infocom internal conventions.

The important tables are the grammar and action tables.

The grammar table address is stored in word 7 (ie bytes 14 and 15) of the
header.  The table consists of a list of two-byte addresses to the entries
for each word.  This list is immediately followed by these entries, one
after another.

An entry consists of one byte giving the number of lines (eg, 5 for the
"take" definition above) and then that many 8-byte lines.  These lines
have the form

  <objects>  <sequence of words>  <action number>
  --1 byte-  ----6 bytes--------  --1 byte-------

<objects> is the number of objects which need to be supplied: eg, 0 for
"inventory", 1 for "take frog", 2 for "tie rope to dog".  The sequence
of words gives up to 6 blocks of syntax to follow the verb, which must
be matched in order.  Large numbers such as $ff mean that the appropriate
adjective must appear; small numbers are inserted by special words such as 
"held" or "noun" in the VERB command.  Tokens are set according to:

   Word            Byte
   ====            ====
   noun             0  
   held             1  
   multi            2  
   multiheld        3  
   multiexcept      4  
   multiinside      5  
   creature         6  
   special          7  
   number           8

   (noun=Routine)   16+parsing-routine-number
   (Routine)        64+parsing-routine-number
   (attribute)      128+attribute number

   (adjective)      255-adjective number

Parsing routines have addresses which are too large to store in a single
byte.  Instead they are numbered from 0, and their (packed) addresses are
stored in the preactions table of the story file (which is called
"preactions" because of what it was used for by the original Infocom parser).

The sequence is padded out to 6 bytes with zeros.

The action numbers begin at 0.  The first routine mentioned as an action (in
the above example, Exit) is assigned action number 0; the next (Take)
is given 1, and so on.  The appropriate number is stored in the last byte of
the line.

Thus, a little later on in the grammar, the line

VERB "exit" "leave"              *                          -> Exit;

might well appear, and Exit will mean "action 0" as before.

So this table does not store the address of the action routine, as one might
expect.  Instead the addresses corresponding to the action numbers are
stored in the actions table.  Once again, Inform puts this table in its
conventional place, but this address being difficult to work out, the
constant #actions_table is set up to hold it.  The actions table is simply
a list of 2-byte entries giving the routine addresses (divided by 2).

There is also a preactions table, with another constant #preactions_table,
created only to conform to Infocom conventions; it is set up containing 0000
for each action.  ("Curses", for instance, makes no use of this.)

In the mean time, what has happened to the actual words, "take", "get",
"pick" and "lift"?  Note that these do not appear in the grammar table at
all.  Instead they are entered into the dictionary, along with the verb
number.  As a final baroque twist, these numbers also count down from $ff.
Any number of words can be given, all referring to the same verb number;
"Curses" has 11 synonyms for "attack", for instance.

Of course, Inform does not know or care what is done with any of these
tables.   For instance, the "take" verb has the entry

005
000 255 000 000 000 000 000 000
001 002 000 000 000 000 000 001
002 005 254 000 000 000 000 002
001 253 000 000 000 000 000 003
001 252 001 000 000 000 000 004

but it is up to the code you write to deal with this.  (The LISTVERBS command
will print out the full verb table in a similar format.)



Now for what Inform does with the dictionary.  Again, if you use the parser
supplied, you needn't know this.

The fourth word of the file header (bytes 8 and 9) contain the dictionary
table's address.

The table begins with a 7-byte header:

  03 '.' ',' '"'

meaning there are three characters used to separate words in typed input,
full stops, commas and quotation marks.  (The Z-machine will allow any list
to be given here but Inform decides on this for you.)

  n   <number_of_entries>
      ----2 bytes--------

meaning there are that many entries in the dictionary, all n bytes long. 

It is usual (not compulsory in the Z-machine format, though Inform always
makes it so) for n to be the number of bytes consumed by the word itself,
plus 3.  In version 3 this makes it 7, which means that words are cut down
to their first six letters only.  In Version 5 it is 9, making the
dictionary accurate to nine letters, which is much more satisfactory. 
Provided dictionary words are always given in full in source code, Inform
will truncate them itself to whichever is appropriate.

The entries are in alphabetical order, and look like:

  <the text of the word>  <flags>  <verb number>  <adjective number>
  ----4 or 6 bytes------  --1 b--  ----1 byte---  ----1 byte--------

The text is stored in the usual text format, thus allowing up to 6 or 9
characters.

When using entries like this, it's convenient to write code which works
equally well under versions 3 or 5.  To do so one needs to access the three
data bytes without knowing whether they are 4 or 6 bytes from the start of
the dictionary entry address.  Inform provides three constants for this:

                 In Version 3     In Version 5
  #dict_par1          4                6
  #dict_par2          5                7
  #dict_par3          6                8

Thus, for example, address->#dict_par1 gives the flags byte.

The flags (chosen once again to conform loosely to Infocom conventions, not
for any sensible reason) have the eight bits

  7      6  5  4  3     2      1      0
  <noun> .. .. .. <adj> <spec> <meta> <verb>

<verb>, <noun> and <adj> mean the word can be a verb, noun or adjective; the
<spec> bit means the word was inserted by a DICTIONARY command in the
program, except that <verb> words also have the <spec> bit set (ours not to
wonder why).

Verbs declared as "meta" have the <meta> bit set.  (These are such
out-of-world experiences as SAVE and SCORE.)

Note that a word can be any combination of these at once.  It can even be
simultaneously a verb, adjective and noun.

A standard game typically needs at least 600 dictionary entries - about ten
times the number of portable objects.  Even so it only consumes about 4K, or
1/64th of the available memory.  It's never worth economising on dictionary
entries; nothing else a designer can do with 4K will be as goodto the user.
(By means of containing a heroic number of synonyms, some of the larger
Infocom games have as many as 2000 words in their dictionaries.)


---------------------------------------------------------------------------
16. Indirect function calls
---------------------------------------------------------------------------


         "By indirections find directions out"

                  (Shakespeare, "Hamlet")


Occasionally one needs to call a function whose address is in a variable:
for example, if the routine address has been looked up from a table, or an
object's property list.

For this, the function "indirect" is provided:

  a=indirect(b);

sets a to the return value of calling the function whose address is in b.


WARNING: To pass arguments as well, you must use the assembler-level
   *     @icall, but do so with care.
  /!\    Be careful not to leave values on the stack: or the game may
 *---*   crash 1000 turns later, highly mysteriously.


---------------------------------------------------------------------------
17.  Text spacing
---------------------------------------------------------------------------


        "The thundering text, the snivelling commentary!"

                (Robert Graves)


Typewritten English, like this file, normally puts a double space after a
full stop.  This is much easier to read.  Unfortunately Infocom-standard
interpreters do not usually understand that.  When they fold text across
lines, they can easily turn

  ...and a pomegranate.  After all, you always hated fruit.

into something like

   |You decline the offer of a banana, an apple and a pomegranate.   |
   | After all, you always hated fruit.                              |
   |                                                                 |
   |>                                                                |

which looks awful.  It would be easy to fix the interpreter not to do this;
but nobody does.  In case (like the author's) your typing is habitually
double-spaced, Inform provides a command line option -d to change it back
again.  It does this only by replacing the string ".  " by ". " in text
conversion.


---------------------------------------------------------------------------
18.  Drastic object alteration
---------------------------------------------------------------------------


       "Everything changes.  We plant
        trees for those born later
        but what's happened has happened
        and poisons poured into the sea
        cannot be drained out again."

               (Cicely Herbert, after Brecht)


In earlier versions of Inform, there were some aspects of an object
difficult to change, once set.  Firstly, the "short name".  If you
declared an object as, say,

  OBJECT frog "little green frog" attic
    WITH ...

then the game would always refer to it as "little green frog": this would
be impossible to alter if, for instance, it should in some magical way
become an enormous green frog.

A sneaky way around this is to use string indirection.  Declare it as

  OBJECT frog "@00" attic
    WITH ...

so that, when the Z-machine does a print_obj on it, it prints out the
string entered 0th in the synonyms table.  In your initialisation code,
write your own string here, by:

  LOW_STRING L_Frog "little green frog";
  LOW_STRING E_Frog "enormous, slavering green frog";

  STRING 0 #L_Frog;

(compiling simply to

  (0-->12)-->0=#L_Frog;

which looks up the synonyms table address; setting word n changes the
string printed in place of @n).


WARNING:  Note that any string you intend to use in this way must be
   *      declared by LOW_STRING as above.  (LOW_STRING is like CONSTANT,
  /!\     but makes strings in a slightly different way.)
 *---*    The more friendly-looking usage

             STRING 0 "illegal frog";

          will work in a Version 3 game but may unpredictably fail in a
          Version 5 one which exceeds 128K in length.  (This is a
          consequence of the design of the Z-machine; see Appendix A.)


Then at any time you can amend the name by

  STRING 0 #E_Frog;

@00 to @31 are available.  (Counting in decimal, not hex.)

(This system also provides an elegant way of dealing with bottles and
containers of water in general, say: "full beer bottle" can become
"half-empty beer bottle" and then "empty beer bottle".  (But if so,
remember also to change its indefinite article from "a" to "an".))


Secondly, properties which pointed to game routines were tricky to
set for a complicated reason to do with how constants are translated.
Suffice to say that one can now do this by, e.g.

  frog.preroutine = #r$EnormousFrogPre;

or

  frog.preroutine = #r$LittleFrogPre;


Thirdly, it was difficult to change the dictionary entries recognised
as referring to an object.  Well, it still is, but here's how it's done:

Create your object with the name field containing dummy entries, e.g.

  OBJECT frog "@00" attic
    WITH name "zzzzzz" "zzzzzz" "zzzzzz",
         ...;  

and then initially set these by

  x = frog.&name;

  x-->0 = #n$little;
  x-->1 = #n$green;
  x-->2 = #n$frog;

then alter them by

  x = frog.&name;

  x-->0 = #n$enormous;

(Warning: if there are only three entries in the name property list, as
here, then the Z-machine will crash if you try to write to the fourth: so
make sure there are enough dummy entries when you create the object.)


It is thus possible to change absolutely every aspect of an object.  One
virtue of this is that, as Richard Tucker pointed out to the author, the
version-3 limit of 256 objects ceases to be a limitation if you can recycle
them. It takes careful coding, but these methods allow that recycling to
take place.

This is why multiple internal names are now allowed for an object:

  OBJECT frog brick herring "@00" attic
    WITH name "zzzzzz" "zzzzzz" "zzzzzz",
         ...;

will allow the same object number to be called frog, brick or herring by
different routines which deal with different incarnations of the same
object.

In a version-5 game it seems best not to use this device.


---------------------------------------------------------------------------
19.  Abbreviations
---------------------------------------------------------------------------


     "Obviously, to get maximum gain one must make sensible choices.
     A reasonable selection is..."

          (unintended irony from the third edition of this manual)


When the game becomes full, 8 to 10% of its length can be saved by making
use of text abbreviations: a method under which up to 64 commonly occurring
phrases can be abbreviated whenever they occur.

This makes no difference to the text as seen by the player.

Because checking for these causes a speed overhead (again, of about 10%),
and isn't worthwhile until the game is about 90% full, Inform does not do
so except in economy mode (compiling with the switch -e on).

An abbreviation must be declared explicitly, before any other text appears,
by a directive such as:

  ABBREVIATE "the ";

Only 64 may be declared (note for experts: the remaining 32 slots in the
synonyms table are allocated for variable strings, see (18)).

(This causes "the " to be stored internally as only 2 text chunks, rather
than 4, whenever it occurs: which is very often.)

To see how good your current choice of abbreviations is, try compiling with
the -f (frequencies) option set, which will count the number of times each
abbreviation is used, and work out how many bytes it saved.  For instance,
" the " occurs some 2445 times in the latest version of "Curses".
Experimenting with words soon reveals that parts of speech and words like
"there" make big savings, but that almost any proper noun makes hardly any
difference.

Infocom's own compiler does not seem to have chosen abbreviations very
rigorously, since Infocom story files contain just such a naive list.  (This
may have been wise from the point of view of printing speed in the days of
much slower computers.)

In any case, the -u option of Inform (if your computer is large enough and
fast enough to make this feasible) will try to work out a nearly-optimal set
of abbreviations.

The algorithm for doing so is too complex to give here: see the source code.
Briefly, it runs in two phases: building a table of cross-references, and
then running a number of passes looking for good substrings and choosing
good antichains from the partially ordered set resulting.  The result is not
guaranteed to be optimal but seems pretty good.  The output it finally
produces is a list of legal Inform "Abbreviate" commands which can be pasted
into source code.

Since there are something like

     300000
    2

possible choices for a game the size of "Curses", this is bound to be a
tricky and computationally expensive job.  The 128K version of "Curses" takes
about 45 seconds to compile on my machine, and slightly under two hours to
optimise.  There are three passes, of which the first is by far the longest.

Reasonable guesswork and experiment (resulting in the words suggested in
earlier editions of this manual) actually doesn't perform too badly, but
"Curses" was 1200 bytes shorter than that when optimised: sample -f output
(again, for the 128K version of "Curses") follows:

    How frequently abbreviations were used, and roughly how many
    bytes they saved:  ('_' denotes spaces)
       you   668/  444         with   144/  190        which    92/  182   
       urs    58/   38         tion   142/  188          ter   274/  182   
       t_w   134/   88          t_s   117/   77          t_o   164/  108   
       t_i   167/  110          ing   960/  639         ight   187/  248   
       her   283/  188          e_w   146/   96          e_s   160/  106   
       e_o   227/  150          e_i   245/  162          e_a   254/  168   
       der    87/   57          d_s    61/   40          d_o   122/   80   
       d_i    82/   54          d_a   122/   80          and   560/  372   
       all   289/  192          You   297/  394         This    47/   92   
       The   384/  510      Meldrew    28/  108        It_is    40/  104   
 Aunt_Jemima  15/  102           ._   680/  452           ,_  1444/  962   
      's_~    42/  109        's_no    41/  106          _un   105/   69   
       _to   708/  471        _the_  1328/ 2654          _th   578/  384   
       _ro   110/   72          _pr    95/   62          _po    78/   51   
       _no   246/  163          _ma   165/  109          _lo   119/   78   
       _ho    87/   57          _hi    99/   65          _ha   309/  205   
       _gr    67/   44          _ga    60/   39        _from    94/  186   
      _for   185/  245          _fi   130/   86          _fa    97/   64   
       _ex    89/   58          _ea    61/   40        _door    46/   90   
       _di   110/   72         _con    88/  116         _com    72/   94   
       _cl    81/   53         _can   164/  217          _ba   120/   79   
       _a_   587/  390   

(On the most recent (256K) version of "Curses", using abbreviations saved
about 23000 bytes and added 9 seconds to a 91-second compilation time.)

Most of these abbreviations, it seems fair to say, would not be guessed at,
and it's interesting how few words in common the naive and optimised lists
have.  Only two proper nouns survived, and they provide the only longish
words.  "is " as such turned out not to be worthwhile.  " the " was perhaps
obvious in retrospect, but I didn't think of it.  The best strategy for
abbreviating seems, surprisingly, to be to choose three-character strings
which make a fractional saving each (only one Z-character each time, for the
most part) but which occur very often indeed.  (This may be undesirable from
the point of view of printing speed, of course.)

Note also that another 32 abbreviations (which could be accommodated, if the
string-changing mechanism were dropped) would not make all that much
difference.  The least worthwhile of these already saves only 38 bytes or
so.


---------------------------------------------------------------------------
20.  Bells, whistles and gimmicks
---------------------------------------------------------------------------


    "He has written poems resembling the kind of pictures typists
    make with their machines in the coffee break..."

         (Philip Larkin on the modern artist, from the
          introduction to "All What Jazz")


a.  Version 3
-------------


Version 3 story files are pleasingly austere.  Almost their only special
effects are the status line, and occasional character graphic maps or
drawings.

The status line is perhaps the most distinctive feature of Infocom games in
play.  This is the (usually highlighted) bar across the top of the screen. 
The game automatically prints the current game location, and either the time
or the score and number of turns taken.

The status line is redisplayed at least (a) on a SHOW_SCORE command and
(b) each time the game asks the player to type something.  It may be
displayed even more often, at the whim of the interpreter.

The place name is the short name of the object whose number is held in
global 0 - the earliest global declared in the file.  If ever this global
holds the value 0, the name displayed will become corrupted and the game
may crash.

The next two globals are also used.

By default, these show the score and number of turns taken so far, usually
in the form "4/87".  (Interpreters vary in how they print these.)

However, if the file contains the directive

  Statusline time;

then they are treated as the time in hours and minutes.  For instance,
1 and 32 would come out as "1:32 am".

It is up to the program to adjust these variables as time passes, score
is gathered, location changes, etc.  (Though as usual, the library will
take care of some of this work.)


About character graphic drawings: on some machines, text will by default be
displayed in a proportional font (i.e. one in which the width of a letter
depends on what it is, so for example an i will be narrower than an m).  If
you want to display a diagram made up of letters, you will have to turn this
off, for which the "font" command is provided:

   font off;
   print "   +---+^   | A |^   +---+^";
   font on;

for example.  Remember to turn the font back on afterwards.

On a machine not using proportional fonts, these have no effect.  But
the commands need to be inserted for the sake of machines which do.

WARNING: Some interpreters only display a line once it has scrolled.
   *     Consequently it is wisest only to change the font after a
  /!\    new-line has been printed.
 *---*   


b.  Version 5
-------------


Various gimmicks and special effects are provided for Version 5 story files. 
These should be used as sparingly as possible, in the interests of public
decency as much as of portability.

Assembly language to code such effects is detailed in (A4).

The main difference is that the status line is not automatically displayed
and that SHOW_SCORE is no longer legal.  However, the READ command is able
to emulate the old status line by, for instance,

  read buffer parse;

if you only want a standard one.  If you want something more exotic, you
will need something like:

  read buffer parse Pretty;

where the Pretty() routine is, say:

  [ Pretty i j;
    i = 0->33; if (i==0) i=80;          !  Find width of screen

    split_window 2;                     !  Create 2-line top window
    buffer_mode 0;                      !  Switch off line-splitting
    set_window 1;                       !  Move to it
    style reverse;                      !  Reverse-video mode on

    set_cursor 1 1;                     !  Blank out line 1...
    spaces i;
    set_cursor 2 1;                     !  and line 2... with spaces
    spaces i;

    set_cursor 1 2;                     !  Print the top line
    print_obj location;
    set_cursor 1 53;
    print "Amulets: "; print_num score;
    set_cursor 1 66;
    print "Days: "; print_num turns;

    set_cursor 2 2;                     !  And the second line
    PrintRank();

    style roman;                        !  Back to standard text
    buffer_mode 1;                      !  Switch on line-splitting
    set_window 0;                       !  in the standard window
  ];

By stretching the status bar to many lines wide, you can make it show a
character-graphics map, a Scott Adams-style list of viable directions, an
election slogan for your favourite politician - the possibilities are, alas,
endless.

You can also BEEP the user and read the keyboard "live", with a clock
running; see appendix (A4) for fuller details.


Something several later Infocom games did was to display messages
- quotations, writings on signs, etc. - in reverse video in a centred text
window at the top of the screen.  This is easy but tedious to code
correctly, so Inform provides a command to do it, viz. "BOX".  For
instance,

     BOX "Beware of the Dog";

or

     BOX "I might repeat to myself, slowly and soothingly,"
         "a list of quotations beautiful from minds profound;"
         "if I can remember any of the damn things."
         ""
         "-- Dorothy Parker";

Note that a string of lines is given (without intervening commas) and
that a blank line is given by a null string.  Remember that the text
cannot be too wide or it will look awful on a small screen.

The author takes the view that this device is amusing for irrelevant
quotations but irritating when it conveys vital information (such as,
"Beware of the Dog", for instance).


Version-5 also allows an "undo" feature to be programmed.  See (A4)
for details.  It does not properly work on all interpreters, but is
worthwhile enough to be coded anyway.


---------------------------------------------------------------------------
Designer's Manual: Using the Library
---------------------------------------------------------------------------


     "And what was one to make of the arrangement of covered walk,
     library and communal refectory which seemed to form an almost
     independent entity within the plan of the mausoleum?  The
     expectant visitor would have been disappointed on entering this
     part of the monument..."

          (Luciano Canfora, "The Vanished Library")


---------------------------------------------------------------------------
D1.  Getting started
---------------------------------------------------------------------------


The first thing to try is to compile the "Hello Cruel World" game, a very
short test file given in Appendix C.  If that compiles and runs properly
(producing a short page of text, then finishing), try the following:


    Constant Story "SHELL";
    Constant Headline "^An Interactive Skeleton^\
                 Copyright (c) 1994 by (your name here).^";

    #include "Parser";
    #include "VerbLib";

    Object Blank_Room "Blank Room"
      with description "An empty room."
      has  light;

    [ Initialise;
      location=room;
      "^^^^^Welcome to the shell...^^";
    ];
    
    #include "Grammar";
    end;


If this compiles, Inform is almost certainly set up and working properly.
It takes a short while to compile, because it "includes" three large standard
files, containing a large amount of code.  These are:

    Parser        The core of the game, and a proper game parser
    VerbLib       A library of routines for game verbs like "take"
    Grammar       A grammar table to decode the player's input from
  
Together, they make up the "library".  They can certainly be modified by
programmers, but have been designed in such a way as to minimise the need for
this.  (The "#include"s are written that way to imitate C, but they could
just be written "Include".)

Apart from that, the code contains:

  strings giving the name of the game, and a copyright message, to be
printed out at the appropriate moments;

  a routine, called "Initialise", which is run when the game begins, and
simply sets where the player starts (in the obvious place!) and prints a
welcoming message;

  an object, to be the only room of the game.

The "shell" game is very boring: there is nothing for the player to do but
wait and quit.


In Inform, everything is an object: rooms, compass directions, things to be
picked up, scenery and even intangible things like mist.  Let us add
something, underneath the room's definition:

     Nearby cone "green cone"
       with name "green" "cone";

("Nearby" just means it's an object inside the last thing declared as an
"Object", in this case the Blank Room.)

A green cone now appears in the Blank Room.  The player can call it either
"green cone", "cone" or even "green".  It can be taken, dropped, looked at,
looked under and so on.

This is still rather plain.  Examining the cone sees "nothing special about
the green cone", for instance.  So we might extend the definition by:

     Nearby cone "green cone"
       with name "green" "cone" "emerald",
            initial "Nearby is an emerald green cone, one foot high.";

The "initial" message now appears when we arrive in the Empty Room.  Taking
things a little further...

     Nearby cone "green cone"
       with name "green" "cone" "emerald" "marzipan",
            initial "Nearby is an emerald green cone, one foot high.",
            description "The cone seems to be made of emerald-coloured \
                         marzipan."
       has  edible;

(Note that the description is split across two lines: the \ makes the message
come out as one sentence without a huge space.)  Now if we examine the
cone, we get its surprising "description".  Also, the cone not only has
"properties" (the values of "name", "description" and "initial") but now
also an "attribute" (which can only be held or not held).  And the player
can now eat the cone.

There still isn't any actual code connected with the cone.  We could go
further without doing any honest programming, but instead:

     Nearby cone "green cone"
       with name "green" "cone" "emerald" "marzipan",
            initial "Nearby is an emerald green cone, one foot high.",
            description "The cone seems to be made of emerald-coloured \
                         marzipan.",
            after
            [; Take: "Taken.  (Your hands are smeared with marzipan.)";
               Drop: "The cone drops to the floor and sags a little.";
            ],
       has  edible;

The property "after" doesn't just have a string for a value: it has a
routine of its own.  (This is much like the "Initialise" routine, except
that it doesn't have a name: it doesn't need one.)  Now what happens is
that when an action happens to the cone, the "after" routine is called
to apply any special rules about the cone.  In this case, Take and Drop
are the only actions tampered with: and the only effect is that the
usual messages ("Taken." "Dropped.") are replaced.

Still, the cone doesn't actually do anything!  So here it is with a
(completely unfair) puzzle added:

     Nearby cone "green cone"
       with name "green" "cone" "emerald" "marzipan",
            initial "Nearby is an emerald green cone, one foot high.",
            description "The cone seems to be made of emerald-coloured \
                         marzipan.",
            before
            [; Eat: if (random(100) <= 30)
                    {   deadflag = 1;
                        "Unfortunately, you seem to be allergic to almonds.";
                    }
                    "You nibble at a corner of the cone.";
            ],
            after
            [; Take: "Taken.  (Your hands are smeared with marzipan.)";
               Drop: "The cone drops to the floor and sags a little.";
            ],
       has  edible;

The "before" routine is called before the player's intended action takes
place.  So when the player tries typing, say, "eat the cone", what happens
is: in 30% of cases, she dies of almond poisoning; and in the other 70%,
she simply nibbles a corner of the cone (without actually consuming it
completely).

"deadflag" is a global variable, whose value does not belong to any particular
object (or routine).  It is defined somewhere in the depths of the library:
it's usually 0; setting it to 1 causes the game to be lost.

In either case, the usual rule for the Eat action is never applied.  This is
because, although it isn't obvious from the code, the routine actually
returns a value, true or false.  And the command

    "Unfortunately, you seem to be allergic to almonds.";

not only prints the message (together with a carriage return), but also
returns true from the "before" routine.  Since the routine normally returns
false, the library knows that something has happened to interrupt the usual
rules of the game.


One more extension:

     Nearby cone "green cone"
       with name "green" "cone" "emerald" "marzipan",
            describe
            [; if (cone has moved)
                   "A misshapen cone of green marzipan sits here.";
               "Nearby is an emerald green cone, one foot high.";
            ],
            description "The cone seems to be made of emerald-coloured \
                         marzipan.",
            before
            [; Eat: if (random(100) <= 30)
                    {   deadflag = 1;
                        "Unfortunately, you seem to be allergic to almonds.";
                    }
                    "You nibble at a corner of the cone.";
            ],
            after
            [; Take: "Taken.  (Your hands are smeared with marzipan.)";
               Drop: cone.description = "The cone is a vague green mess.";
                     "The cone drops to the floor and sags a little.";
            ],
       has  edible;

Now the old "initial" message has gone.  Instead, we have provided a
"describe" routine.  Whenever the game has to describe the cone in the
description of a place, it will call this routine.  The "moved" attribute
is held only by an object which has at some time in the past been taken.  So
the cone is now perfect and untouched until taken and dropped, whereupon
it becomes misshapen.  Also, the act of dropping the cone now changes the
description which appears when a player examines it.


---------------------------------------------------------------------------
D2.  Places, scenery and the map
---------------------------------------------------------------------------


Now for a room: throw away the old "blank room" and replace it by...

     Object Square_Room "Square Room"
       with description
                "A broad, square room, ten yards on a side, floored \
                 with black and white chequered tiles."
       has  light;

(We also have to change the Initialise routine to make this the place
where the player begins, since the Blank Room no longer exists.)

Like the blank room, this one has "light".  (If it didn't, the player
would never see it, since it would be dark, and the player hasn't yet
been given a lamp or torch of some kind.)  So where is the light coming
from?

     Nearby chandelier "crystal chandelier"
       with name "crystal" "chandelier",
            initial "A crystal chandelier hangs from far above, casting \
                     light in little rainbows across the floor.",
            description "The crystal is beautiful cut-glass."
        has static;

This is a piece of scenery, hence the "static" attribute (which means it
can't be taken or moved).  But what about the rainbows?

     Nearby rainbows "rainbows"
       with name "rainbow" "rainbows",
            description "Caused by diffraction, or something like that - \
                you were never very good at physics."
        has scenery;

Being "scenery" makes the object not only static but also not described
by the game unless actually examined by the player.  A true perfectionist
might alter it to:

     Nearby rainbows "rainbows"
       with name "rainbow" "rainbows",
            description "Caused by diffraction, or something like that - \
                you were never very good at physics.",
            before
            [; Take, Push, Pull, Turn: "But the rainbows are made of light.";
            ],
        has scenery;


Let us now add a second room:

     Object Corridor "Sloping Corridor"
       with description
                "This corridor slopes upward and out of the square room.",
            d_to Square_Room, s_to Square_Room,
            u_to "The slope becomes impossibly steep, and you retreat.",
            cant_go "The corridor runs up and down."
       has  light;

and extend the Square Room to:

     Object Square_Room "Square Room"
       with description
                "A broad, square room, ten yards on a side, floored \
                 with black and white chequered tiles.  A doorway in the \
                 centre of the north side opens onto a rising corridor.",
            u_to Corridor,
            n_to Corridor
       has  light;

The player can now go from one to the other.  The properties "u_to", "d_to",
"n_to" (and so on) declare what lies in the directions "up", "down", "north"
(and so on).  If they aren't declared, one cannot go that way.  Notice that
they can be either a room or a message which is printed if the player tries
to go in the given direction.

In the Square Room, if the player tries to go, say, east, she gets a message
along the lines of "You can't go that way.", which is not very helpful.  In
the Corridor, the "cant_go" message is printed instead.

Notice that the map connections are all one-way: they just happen to be
defined in such a way that they appear two-way.


Rooms also have rules of their own.  We might write:

     Object Corridor "Sloping Corridor"
       with description
                "This corridor slopes upward and out of the square room:  \
                 the floor underfoot is a little sticky.",
            d_to Square_Room, s_to Square_Room,
            u_to "The slope becomes impossibly steep, and you retreat.",
            cant_go "The corridor runs up and down.",
            before
            [; Take: if (noun == cone)
                         "The cone seems to be stuck to the floor here.";
            ],
       has  light;

and now the cone (if dropped there) cannot be taken from the floor of
the Sloping Corridor.  The variables "noun" and "second" hold the first
and second nouns supplied with an action.  Rooms have before and after
routines just as objects do.

Remember, when writing rules for rooms, that the room may be a different
one after the action has taken place.  The Go action, for instance, is
offered to the "before" routine of the room which is being left, and the
"after" routine of the room being arrived in.  For example:

            after
            [; Go: if (noun==in_obj)
                   print "How grateful you are to get out of the rain...^";
            ]

will print the message when the room is entered via the "in" direction.
(Note that the message is printed with the "print" command.  This means
that it does not automatically return true: in fact, it returns false,
so the game knows that the usual rules still apply.  Also, no new-line
is printed automatically: the ^ symbol means "print a new-line".)

Directions (such as "north") are objects called n_obj, s_obj and so on:
in this case, in_obj.  (They are not to be confused with the property names
"n_to" and so on.)


---------------------------------------------------------------------------
D3.  Causing actions and making new ones
---------------------------------------------------------------------------


Quite often you want to simulate the effect of a player typing something.
For instance, in the Pepper Room the air is full of pepper and every turn
you sneeze and drop something at random.  If the code to do this simply
removes an object and puts it on the floor, then it might accidentally
provide a solution to a problem like "the toffee apple sticks to your hands
so you can't drop it".

This can at least be coded like this:

  You sneeze convulsively, and lose your grip on the toffee apple...
  The toffee apple sticks to your hand!

which (although not ideal) is much better.  As an example, here is another
piece of scenery to clutter up the tiny map so far:


     Object low_mist "low mist"
       with name "low" "swirling" "mist", article "the",
            initial "A low mist swirls about your feet.",
            description "It carries the unmistakable odour of cinnamon.",
            found_in  Square_Room  Corridor,
            before
            [; Smell: <<Examine self>>;
            ],
       has  static;

This mist is found in both the Square Room and the Corridor: note that the
"found_in" property has a list of places as its value.

(Note also the "article".  Usually the indefinite article for an object
is "a".  Changing it gives a little variety:

  a platinum bar
  an orange balloon
  your Aunt Jemima
  some bundles of reeds
  far too many marbles

for example.)

 
The player will find that smelling the mist produces the same message as
looking at it.  The command

     <<Examine self>>;

causes the game to behave exactly as if the player had typed "examine the
mist" at the keyboard: that is, the Examine action happens, applied to
the low_mist object.  ("self" always means the object whose routine this
is.  In this case, it's really a bit pointless since

     <<Examine low_mist>>;

does just the same thing.)  After going through the business of examining
the mist, the routine then returns "true" (in this case, so that the normal
rules for smelling something are stopped in their tracks).

If instead

     <Examine self>;

had been used, the same would have happened, but the routine would not have
returned "true".  So the mist would be examined; and then the library would
have carried on and said something like "You smell nothing unusual.".

Other actions can of course also be written this way:

     <Look>;  <<ThrowAt cone chandelier>>;

will, for instance, look around, then behave as if the player had asked
to throw the cone at the chandelier, then return true.


Requests like "Look", "ThrowAt", "Take" and so on are called actions. 
Internally, they are stored as numbers, and the number associated with an
action can be got at by

     x = ##Take;

for instance.  The variable "action" holds the current action number.
Sometimes it's convenient to use this directly.  For instance, imagine
a mirror hung very far above the player.  Given:

            before
            [; if (action==##Examine) rfalse;
               "The mirror is too high up, out of reach.";
            ]

the player will only be able to examine the mirror, and nothing else.
This prevents the library from ever saying something like "You push the
mirror but nothing happens.", which would be misleading.


An action corresponds to a routine somewhere which actually carries out
the looking, throwing at, taking and so forth.  (Well, in fact there are
also some special actions called "fake actions" which don't correspond to
such routines, as we shall come to later.)  These have the same name as the
action with "Sub" (short for "subroutine") on the end: so, "TakeSub" for
instance.


The actions implemented by the library are in three groups:

 1. Quit, Restart, Restore, Verify, Save, ScriptOn, ScriptOff,
    Brief, Normal, Verbose;
  
 2. Inv, Take, Drop, Remove, PutOn, Insert, Transfer, Empty,
    Enter, Exit, Go, Look, Examine, Give,
    Unlock, Lock, SwitchOn, SwitchOff, Open, Close, Disrobe, Wear, Eat;

 3. Yes, No, Burn, Pray, Wake, WakeOther [person],
    Kiss, Think, Smell, Listen, Taste, Touch, TouchThing, Dig,
    Cut, Jump [jump on the spot], JumpOver, Tie, Drink,
    Fill, Sorry, Strong [swear word], Mild [swear word], Attack, Swim,
    Swing [something], Blow, Rub, Set, WaveHands [ie, just "wave"],
    Wave [something], Pull, Push, PushDir [push something in a direction],
    Turn, Squeeze, LookUnder [look underneath something], Search,
    ThrowAt, Answer, Buy, Ask, Sing, Climb, Wait, Sleep

Note that the player can type all manner of things to get these.  For
instance, "take off shirt" and "remove the shirt" both cause the Disrobe
action.  Your code can ignore this complication.

Group 1 actions are called "meta" - they are outside the game proper, and
your code is unable to interfere with them.  (If you want a room where the
game can't be saved, as for instance "Spellbreaker" cunningly does, you'll
have to tamper with SaveSub directly, say with a Replacement routine: see
later.)

Group 2 actions, by default, actually do something; group 3 actions,
by default, do nothing but reply with a generally negative message.


Although all actions call the "before" routines, not all of them bother to
check "after" routines.  For instance, since the built-in SmellSub routine
just says "You smell nothing out of the ordinary", there would be no point
calling "after" routines - nothing, after all, has been done.  (These are
the group 3 actions above.)

The ones which actually do something, and call "after", are:

  Inv, Take, Drop, Remove, PutOn, Insert, Exit, Go, Look, Examine, Unlock,
  Lock, SwitchOn, SwitchOff, Open, Close, Disrobe, Wear, Eat, Search.

(Some other group 2 actions use these "after" routines indirectly - if the
player empties a sack out onto the floor, this is deemed to be dropping the
objects within, for instance, and if a sack is emptied into a packing case
this is considered a multiple insertion.)


The library's actions are easily added to.  For instance, add the routine:

     [ BlorpleSub;
         "You speak the magic word ~Blorple~.  Nothing happens.";
     ];

(somewhere after the Initialise routine, say, to be tidy).  There is now
an action "Blorple" (though it doesn't do anything very interesting).  One
can use the command <Blorple>; to make it happen, and could change the
"before" routine of, say, the Corridor, to make Blorple do something
exciting in that one place.  In other words, Blorple is now an action just
like any other.

But the player can't yet type "blorple" and get this response, because
although the action exists, it hasn't been written into the grammar of
the game.  The grammar is a large table (mostly written out in the "Grammar"
library file).  It can easily be added to, and in this case we simply add
the lines

     Verb "blorple"
                *                                -> Blorple;

immediately after the inclusion of the "Grammar" file.  This is about as
simple as grammar lines come, and means that only the word "blorple" can
be used as a verb, and it can't apply to any noun or nouns.

Grammar is more fully described in (14), but looking at the grammar table
in the "Grammar" file will give a fair idea of what it can do.


It is time to be more precise about the exact sequence of events.  Suppose
the player is in the Bedquilt Room, and types "drop oyster".  Once it has
checked that this is a reasonable command, the parser does the following:

   1.  Call GamePreRoutine (if there is one).
       If this returns true, stop here.

   2.  Call the "before" of Bedquilt Room.
       If this returns true, stop here.

   3.  Then the "before" of the oyster.
       If this returns true, stop here.

   4.  Actually drop the object.

   5.  Call the "after" of Bedquilt.
       If this returns true, stop here.

   6.  Then the "after" of the oyster.
       If this returns true, stop here.

   7.  Call GamePostRoutine (if there is one).
       If this returns true, stop here.

   8.  Print "Dropped."

(GamePreRoutine and GamePostRoutine are routines you can optionally
provide to make global rule changes: their use is to be avoided if
possible, as it usually is, for reasons of speed and tidiness.)


---------------------------------------------------------------------------
D4.  Containers, doors, switches and vehicles
---------------------------------------------------------------------------


Objects can be inside or on top of one another.  An object which has
"container" can contain things, like a box: one which has "supporter"
can hold them up, like a table.  (An object can't have both at once.)
It can hold up to 100 items, by default: this is set by the "capacity"
property.

However, one can only put things inside something which has "open".
If it has "openable", the player can open and close it at will.  (Unless
it also has "locked".)

To complicate matters, some containers are "transparent" (so that the
player can see inside them even when they are closed) and some are not.


Containers (and supporters) are able to react to things being put inside
them, or removed from them: for example,

     Object bag "toothed bag" room
       with name "toothed" "bag",
            description "A capacious bag with a toothed mouth.",
            before
            [; LetGo: "The bag defiantly bites itself \
                       shut on your hand until you desist.";
               Close: "The bag resists all attempts to close it.";
            ],
            after
            [; Receive:
                   print "The bag wriggles hideously as it swallows ";
                   DefArt(inp1); ".";
            ],
       has  container open;

makes a rather acquisitive bag:

    >put fish in bag
    The bag wriggles hideously as it swallows the fish.

    >get fish
    The bag defiantly bites itself shut on your hand until you desist.

(LetGo and Receive are actually two of the "fake" actions: they are
the actions Insert and Remove looked at from the other container's point
of view.  It's quite straightforward to define fake actions.  See the
way these are defined in "Verblib" to get the idea.)


Objects which have "locked" cannot be opened, be they doors or containers
(or both).  But objects which have "lockable" can be locked or unlocked
with the appropriate key, which is declared in the "with_key" property.
(If it is undeclared, then no key will fit.)

As a final example of a container, this is a fairly typical locked
cupboard:

       Nearby cupboard "bolted cupboard"
         with name "bolted" "cupboard",
              describe
              [; if (self hasnt open)
                     "^A shut cupboard is bolted to one wall.";
                 "^Bolted up on one wall is an open cupboard.";
              ],
              with_key key
         has  locked container openable lockable static;



A useful kind of object is a "door".  This need not literally be a door:
it might be a rope-bridge or a ladder, for instance.  To set up a door:

    (a)  give the object the "door" attribute;

    (b)  set the "door_to" property to the destination;

    (c)  set the "door_dir" property to the direction which that would be,
         such as "n_to";

    (d)  make the room's map connection in that direction point to the
         door itself.

For example, here is a closed and locked door:

     Object In_Immense_N_S_Passage "Immense N/S Passage"
       with description "One end of an immense north/south passage.",
            s_to In_Giant_Room,
            n_to RustyDoor;

     Nearby RustyDoor "rusty door"
       with description "It's just a big iron door.",
            name "door" "hinge" "hinges" "massive" "rusty" "iron",
            when_closed
                "The way north is barred by a massive, rusty, iron door.",
            when_open
                "The way north leads through a massive, rusty, iron door.",
            door_to In_Cavern_With_Waterfall,
            door_dir n_to,
            with_key set_of_keys
       has  static door openable lockable locked;

(Note that the door is "static" - otherwise the player could pick it up and
walk away with it!)  The properties "when_closed" and "when_open" give
descriptions appropriate for the door in these two states.

Doors are rather one-way: they are only really present on one side.  If
a door needs to be accessible (openable and lockable from either side),
a neat trick is to make it present in both locations and to fix the
door_to and door_dir to the right way round for whichever side the player
is on.  Here, then, is a two-way door:

     Object Grate "steel grate"
       with name "grate" "lock" "gate" "grille" "metal"
                 "strong" "steel" "grating",
            description "It just looks like an ordinary grate \
                mounted in concrete.",
            with_key set_of_keys,
            door_dir
            [; if (location==Below_The_Grate) return u_to; return d_to;
            ],
            door_to
            [; if (location==Below_The_Grate) return Outside_Grate;
               return Below_The_Grate;
            ],
            describe
            [; if (self has open) "^The grate stands open.";
               if (self hasnt locked) "^The grate is unlocked but shut.";
               rtrue;
            ],
            found_in  Below_The_Grate  Outside_Grate
       has  static door openable lockable locked;

where Below_The_Grate has u_to set to Grate, and Outside_Grate has d_to
set to Grate.  The grate can now be opened, closed, entered and locked
from above or below.


At first sight, it isn't obvious why doors have the "door_dir" property.
Why does a door need to know which way it faces?  The idea is that if
there's an open door in the south wall, a player can go through it either
by typing "south" or "enter door".  So what the Enter action does (if
the door is actually open) is to cause the Go action with the given
direction.

This has one practical consequence: if you put "before" and "after" routines
on the Enter action for the Grate, they only apply to a player typing
"enter grate" and not to one just typing "down".  The way to trap both at
once is to write a routine for the d_to property of Outside_Grate.



Objects can also be "switchable".  This means they can be turned off or
on, as if they had some kind of switch on them.  The object has the
attribute "on" if it's on.  For example:

     Object searchlight "Gotham City searchlight" skyscraper
       with name "search" "light" "template", article "the",
            description "It has some kind of template on it.",
            when_on "The old city searchlight shines out a bat against \
                     the feather-clouds of the darkening sky.",
            when_off "The old city searchlight, neglected but still \
                      functional, sits here."
       has  switchable static;

Here is a lamp whose batteries will some day run down:

     Nearby brass_lantern "brass lantern"
       with name "lamp" "lantern" "shiny" "brass",
            when_off  "There is a shiny brass lamp nearby.",
            when_on   "Your lamp is here, gleaming brightly.",
            time_left 330,
            before
            [; Examine: print "It is a shiny brass lamp";
                     if (brass_lantern hasnt on)
                         ".  It is not currently lit.";
                     if (brass_lantern.time_left < 30)
                         ", glowing dimly.";
                     ", glowing brightly.";
               Burn: <<SwitchOn brass_lantern>>;
               Rub:  "Rubbing the electric lamp is not particularly \
                      rewarding.  Anyway, nothing exciting happens.";
               SwitchOn: if (brass_lantern.time_left <= 0)
                     "Unfortunately, the batteries seem to be dead.";
            ],
            after
            [; SwitchOn: give brass_lantern light;
               SwitchOff: give brass_lantern ~light;
            ],
       has  switchable;


An object which has "enterable" can be got inside.  (The idea of "inside"
here is that the player is only half-in, as with a car or a psychiatrist's
couch.  If it's more like a prison cell, then it should be a separate
place.)

     Object car "little red car" cave
       with name "little" "red" "car",
            longdesc "Large enough to sit inside.  Among the controls is a \
                      prominent on/off switch.  The numberplate is KAR 1.",
            initpos "The red car sits here, its engine still running.",
            closedpos "A little red car is parked here.",
            before
            [; Go: if (car has on) "Brmm!  Brmm!";
                   print "(The ignition is off at the moment.)^";
            ],
       has  switchable enterable static container open;

This demonstrates a special rule.  If a player is inside an enterable object
and tries to move, say "north", the before routine for the object is called
with the action Go, and n_obj as the noun.  If it returns false, the game
disallows the attempt to move (as usual).  If it returns true, then the
vehicle and player move together via the game's usual map.


---------------------------------------------------------------------------
D5.  Living creatures
---------------------------------------------------------------------------


Animate objects (such as sea monsters, mad aunts or nasty little dwarves)
have a property called "life", containing their rules.  This behaves just
like a "before" or "after" routine, but only the following actions apply:

   Order         The player has asked the creature to do something,
                 e.g., by "troll, go south".  action, noun and second are
                 set up as usual: e.g. action=##Go and noun=s_obj.

   Attack        Player tried to attack creature

   Kiss          Tried to kiss

   Answer        The player tried either "answer <word> to troll", or else
                 "troll, <something not understood>".  In either case
                 special_word is set to the dictionary entry of the first
                 word, or 0 if it isn't in the dictionary, and
                 special_number is set to an attempt to read it as a
                 number.  (For instance, "computer, 143" will cause
                 special_number to be set to 143.)

   Ask           "ask troll about ..." - similarly special_word and
                 special_number are set up

   Give          noun holds the object number of what the player has tried
                 to give (or feed) the creature.  (Unless code is written
                 the creature will "seem uninterested" and nothing will
                 happen.)

   ThrowAt       noun holds whatever the player tried to throw.

If the routine doesn't exist, or returns false, events will take their
usual course.  Here is a full example:

     Object snake "sullen snake" mists
       with name "sullen" "snake",
            description "Perhaps a boa constrictor.  Perhaps not.",
            life
            [; Order: if (action==##Go)
                        "The snake wasn't born yesterday.";
               Attack:  "Lazily, the snake dodges your attack.";
               Kiss:    "What a repulsive idea.";
               ThrowAt: print "Effortlessly, the snake dodges ";
                        DefArt(inp1); ".";
               Answer:  "The snake disdains to comment.";
               Ask:     if (noun == 'mists')
                            "~Healthy and good for the skin, mists.~";
                        "~I'm only the obligatory monster.~";
               Give:    if (noun has edible)
                        {   remove noun;
                            "~Mmm!  Thanks!  I still hate you, though.~";
                        }
                        "~Bleurghh!  Are you trying to poison me?~";
            ],
       has  animate;

Of course an "animate" still has "before" and "after" routines like any
other.  (The library understands that, for example, an animate creature
cannot be taken.)


A footnote about Order: Order is another "fake action".  The "before"
and "after" routines of a room can't detect the player having given a
request to another character.  Also, if you want the snake to obey when
the player tells it to take something, you have to write the code to do
the actual taking yourself.  This isn't any problem in practice.  (Try
looking at the code for "Christopher" in the "Toyshop" example game.)


---------------------------------------------------------------------------
D6.  Classes of objects
---------------------------------------------------------------------------


An example of a class is:

      Class Treasure
       with depositpoints 10,
            after
            [; Take: if (location==Inside_Building)
                          score=score-self.depositpoints;
                     score=score+5;
                     "Taken!";
               Drop: score=score-5;
                     if (location==Inside_Building)
                     {   score=score+self.depositpoints;
                         "Safely deposited.";
                     }               
            ],
       has  valuable;

Any object declared as being of this class, such as:

     Nearby bars_of_silver "bars of silver"
      class Treasure
       with description "They're probably worth a fortune!",
            initial "There are bars of silver here!",
            article "some",
            name "silver" "bars";

inherits the "depositpoints" value of 10 and the rules about taking
and dropping.  If the silver bars had themselves set "depositpoints"
to 15, say, then the value would be 15: i.e., the class would be
over-ridden.

We could also, for instance, have:

     Nearby cake "valuable cake"
      class Treasure
       with description "Exquisite!",
            initial "There's a valuable cake here!",
            after
            [; Eat: "Your most expensive meal in ages, but worth it.";
            ],
            name "valuable" "cake"
       has  edible;

Now the cake has two "after" rules.  Both apply, but the rule in the cake
itself takes precedence, i.e., happens first.


An object can inherit from several classes at once (in sequence, left to
right).  A class can itself inherit from other classes.  The full rules
are in (13).


---------------------------------------------------------------------------
D7.  Daemons and the passing of time
---------------------------------------------------------------------------


By tradition, a "daemon" is an event which happens each turn while it is
active.  The classic example is of a dwarf which appears in the cave: it
has a daemon routine attached to move it about, make it throw knives at
the player and other pleasantries.

Each object can have its own daemon.  It is set going by calling the
routine

     StartDaemon(the-object);

and can be turned off again with

     StopDaemon(the-object);

Once it's active, its "daemon" property is called as a routine each turn.
(Be warned: this continues to happen even if the daemon is associated with
a room or item which has been left behind by the player.)


A "timer" (these are traditionally called "fuses" but the author can stand
only so much tradition) can alternatively be attached to an object.
(An object can't have both a timer and a daemon active at the same time.)
A timer is started with

     StartTimer(the-object, time);

in which case it will "go off" (alarm clock-style) in the given number of
turns.  This means that its "time_out" routine will be called, once and
once only, at this time.

It can be deactivated (so that it will never go off) by calling

     StopTimer(the-object);


Timers and daemons are _required_ to provide a "time_left" property.  In
the case of a daemon, this is set to -1 when the daemon is active.  In the
case of a timer, it's the number of turns left before the timer goes off.
This can be manipulated and looked at by the program.  Warning: if you
forget to provide "time_left", the game may crash!


If you're writing a game with time instead of score/turns on the status
line, you can set the time by

   SetTime( hours*60+minutes, rate);

where rate=0 means the time is left alone, and if rate>0 that many
minutes pass every action, whereas if rate<0 that many actions pass
for every minute.

The current time is held in a variable, "the_time".  It's a 24-hour
clock.

Calling SetTime also tells the library that the game is a "time" rather than
"score" game.  Remember to call it in Initialise().


Exactly what happens at the end of each turn is:

  1.  The turns counter is incremented.

  2.  The time moves on.

  3.  Daemons and timers are run (in no particular order).

  4.  The "each_turn" routine of the current room is run.

  5.  The game's global TimePasses() routine is called.

  6.  Light is re-considered (it may have gone dark as a result
        of what has happened).

This sequence is abandoned if at any stage the player dies.


---------------------------------------------------------------------------
D8.  Calls to and from the library
---------------------------------------------------------------------------


A game using the library _must_ provide one routine:

  Initialise() is called before the banner is printed up, and one thing it
  _must_ do is to set "location" to the initial game location.

It must also define two string constants, Story and Headline, e.g.:

     Constant Story "ZORK II";
     Constant Headline "^An Interactive Plagiarism^\
                 Copyright (c) 1993 by Ivan O. Ideas.^";


In addition, it may (but need not) provide the following routines:

  TimePasses() is called after every turn (but not, for instance, after a
    command like "score" or "save").  It's much more elegant to use timers
    and daemons, or "each_turn" routines for individual rooms - using this
    is a last resort.

  PrintRank() completes the printing of the score.  (You might want to change
    this, so as to make the ranks something like "junior astronaut" or
    "master catburglar" or whatever suits your game.)

  DarkToDark() is called when a player goes from one dark room into another
    one.  If you want, you can take the opportunity to kill the player off
    for doing this.

  DeathMessage() is to print up "You have died" style messages.  To kill a
    player, set "deadflag" to 1.  To make a player win, set "deadflag" to 2.
    If you set "deadflag" to any other value (3, 4, ...) this routine is
    called to say what happened, e.g. "You have changed".

  LookRoutine() is called at the end of every location description.

  NewRoom() is called when the room changes, before any description of it
    is printed.  (This happens no matter how the change of room occurred.)

  PrintTaskName() prints the name of a game task (such as "driving the
    car").

  Amusing() is called to print some amusing afterword when the game is won
    (for instance, it might advertise some features which a successful
    player might never have noticed).  (But only if you have defined the
    constant AMUSING_PROVIDED in your own code.)

  GamePreRoutine() and GamePostRoutine() - see below.

  ParseNumber - allows numbers in unusual formats to be parsed.  Sometimes
    it's useful for the parser to be able to understand numbers in
    strange formats: Roman numerals, letter codes, long telephone numbers,
    etc.  Accordingly you can provide

     [ ParseNumber buffer length;
       ...returning 0 if no match is made, or the number otherwise...
     ];

    to examine the "number" held in ASCII characters at the given byte
    address, of given length.  If this is present, then when special_number
    is set, it will be set using this routine if possible first (and then
    lapse into its usual parsing if it makes no match).

  AfterLife - called when death takes place, but before any
    *** You have died *** message appears.  If it resets deadflag back to 0,
    the player effectively gets resurrected.


Apart from these, the only routines of yours which are ever called are those
attached to your objects.


The library contains several useful routines which can be called from time
to time.  Among these are:

  DefArt(obj): a useful little routine which prints the name of the
      object, with its definite article attached.  This causes, for example,

          the platinum bar
          Aunt Jemima
          Elbereth

      (an object with "proper" - meaning, the name is a proper noun - does
      not have "the" printed in front).

  CDefArt(obj): the same but with a capital letter at the front.

  IndefArt(obj): similar, but with the indefinite article:

          a platinum bar
          an orange balloon
          your Aunt Jemima
          some bundles of reeds
          far too many marbles

      (the indefinite article is "a" unless set by the "article" property).

  DescribeObj(obj): produces a more complete description:

          an electric torch (providing light)
          a rucksack (which is open and contains a scarlet fish)

  Achieved(task): declares a certain task as completed (see below)

  PlayerTo(place): moves the player to a new place (see below)

  SetTime(now, step): sets the 24-hour clock (see above)

  YesOrNo(): asks the player a yes-no question, returning true if the
      reply was yes.  (It doesn't print the question.)


Occasionally you need to rewrite one of the library routines.  But
the danger of doing so is that it is then necessary to keep a copy
of the library for every game, which is clearly unsatisfactory.  So:
the directive

    REPLACE BurnSub;

(if placed before the library files are included) tells Inform to
ignore the definition of "BurnSub" in the library files.  (You then
have to define a routine called BurnSub yourself.)



The library won't allow the player to carry an indefinite number of
objects: the limit allowed is the constant MAX_CARRIED, which you
may define if you wish.  (If you don't define it, it's 100, which
roughly removes the rule.)

If you define SACK_OBJECT to be some container, then the player will
automatically put old, least-used objects away in it as the game
progresses.  (If not, nothing happens.)


Another constant is AMUSING_PROVIDED.  If you define this, the library
knows to put an "amusing" option on the menu after the game is won.
It will then call Amusing() from your code when needed.


In debugging, it's sometimes tricky to work out exactly what is
happening and in what order.  If a game is compiled with the constant
DEBUG defined, then it will print out details of every object routine
ever called, which makes it much easier to follow what's going on.


The other constants you are allowed to define help the score routines
along.  These are:

   MAX_SCORE     The maximum game score (default 0)
   NUMBER_TASKS  Number of individual "tasks" to perform (1)
   OBJECT_SCORE  Bonus for first picking up a "scored" object (4)
   ROOM_SCORE    Bonus for first entering a "scored" room (5)

and then the individual tasks have scores, as follows:

   Global task_scores initial t1 t2 ... tn;

Within your code, when a player achieves something, call Achieved(task)
to mark that the task has been completed.  It will only award points if
this task has not been completed before.

There do not have to be any "tasks": there's no need to use the scoring
system provided.  Tasks (and the verb "full" for full score) will only
work at all if you define the constant TASKS_PROVIDED.


The library maintains light by itself.  It will cope, for instance, with
what happens if a dwarf picks up the light source and walks away, or if
the light source is shut up in an opaque box.  The program can give
or take away the light attribute to anything, or move anything anywhere,
without having to think about whether or not this makes the room dark.


To move the player about (for teleportation of some kind), two things
must be done: to move the player object, by

   move player to newroom;

and also to change the "location" variable, which says which room to
display on the status line:

   location = newroom;

In general location can be different from parent(player) in two ways: it
can be "Darkness", or it can be the actual room while parent(player) is
something the player sits inside, like (say) a jeep.

The cleanest way to move the player is call PlayerTo(place); which also
sorts out things like only printing the new room's description if there's
enough light there to see by.  (Calling PlayerTo(place, 1); will move the
player without printing anything, and in particular without printing any
room description.)


Finally, you might want the parser to know about plural nouns.  Many
games involve collecting a number of similar items, say a set of nine
crowns in different colours.  Then you'd want the parser to recognise
things like

   > drop all of the crowns except green

for instance.  It can do this, provided it's told that "crowns" is the
plural of crown, and provided it's told how to recognise a crown when
it sees one.

You need not declare any, but are allowed up to three such plurals, declared
in your Initialise() routine by lines like:

    plural_word1 = 'crowns'; plural_filter1 = is_crown;

(and so on, for 2 and 3 as needed).  You must already have declared is_crown
as an Attribute, and flagged all the crowns with this attribute.  ('crowns'
is a construction which puts the word "crowns" into the dictionary.)


---------------------------------------------------------------------------
D9.  Table of properties and attributes
---------------------------------------------------------------------------


The following are the attributes defined by the library, as they apply
to objects:


      light            gives off light
      concealed        invisible, but touchable
      worn             currently worn clothing
      clothing         can be clothing
      animate          is a living creature of some kind
      female           gender female (otherwise male) - used for eg "her"
      proper           short name is proper noun
      moved            has been picked up at some time
      door             is a doorway of some kind
      container        can contain things (eg, a bottle)
      supporter        can support things (eg, a table)
      transparent      interior of container can be seen when closed
      open             container or doorway which is open
      openable         container or doorway open/closeable to player
      workflag         (flag used by parser)
      enterable        can be entered (eg, car or fireplace)
      scenery          not described by Look, nor moveable (eg, rock face)
      static           immovably fixed in place (eg, Y2 rock)
      direction        (is one of the compass directions)
      lockable         can be locked or unlocked (with suitable key)
      locked           is presently locked
      switchable       can be switched on and off
      on               is presently switched on
      edible           can be eaten
      autosearch       examining this object causes it also to be searched
                         (in particular, looked inside if it's a container)
      scored           award points for first taking
      talkable         is not an animate creature, but can nevertheless
                         be talked to (eg, a microphone)
      absent           a removed object normally found in several places
      general          general-purpose flag

"general" is free for the user (as are the remaining spare attributes) and
conventionally means "the puzzle associated with this object has been
solved".

An object cannot be both a container and a supporter.

Most of the above attributes make no sense for locations.  The attributes
applying to them are:

      light            there's ambient light
      visited          place has been visited at some time
      scored           award points for first visit

(If you simply never want to have darkness, a sneaky way of doing it is to
put the line

    give player light;

in Initialise().  The game works as if the player herself was glowing
enough to provide light to see by.  In every situation, then, it's light.)


Here are the properties defined and used by the library:

                  Default value    Use
                    if not 0
      name (*)                     for an object:
                                       dictionary words referring to it
                                   for a room:
                                       dictionary words which refer to
                                       "irrelevant" things in a room

      description                  for an object:
                                       examine description of an object,
                                       or routine to print one
                                   for a room:
                                       long description of a room,
                                       or routine to print one

      article       "a"            indefinite article (objects only)

      initial                      for an object:
                                       initial description of an object
                                       not yet picked up
                                   for a room:
                                       routine called when the room is
                                       entered, before its description is
                                       printed

      describe                     for an object:
                                       routine to describe it during Look
                                       (this over-rides its "initial")
                                   for a room:
                                       routine to print a long description
                                       (this over-rides its "description"
                                       and is provided for consistency)
                                   (note: "describe" can only be a routine)

      before        $ffff          routine for altering rules before actions
      after         $ffff          and after actions
      life          $ffff          and rules for "animate" creatures


      n_to   s_to  (**)            for a room:
      e_to   w_to                      map connections to other rooms,
      ne_to  se_to                     or strings to print if can't go,
      nw_to  sw_to                     or routines to call to determine this 
      u_to   d_to
      in_to  out_to

      cant_go        "You can't go that way."
                                   for a room:
                                       printed when player tries to go an
                                       impossible way from a location

      door_to                      place that a "door" connects to
                                       or routine returning this
      door_dir                     direction which goes through it
                                       or routine returning this

      when_closed                  description of a door which is closed
      when_open                    description of a door which is open

      when_on                      description of a switchable which is on
      when_off                     description of a switchable which is off

      with_key                     key to unlock a lockable object

      capacity      100            maximum number of things a container
                                   or supporter can contain or support

      found_in                     for an object:
                                       list of rooms in which it is found

      time_left (***)              turns left until timer goes off
      time_out                     routine to run when it does

      daemon                       daemon routine (called each turn while
                                   active)

      each_turn                    for a room:
                                       called each turn the player is in
                                       the room

      number                       this is provided as a general-purpose
                                   integer variable (to save on globals):
                                   the library never does anything to or
                                   with it

(*) "name" is a property actually defined in the syntax of Inform itself.
But this is the use to which it is put by the library routines.

(**) warning: do not confuse these with the direction objects n_obj,
s_obj... which are what noun, second etc would be set to in a command
mentioning a direction (such as "push the car north").
 
(***) warning: this _must_ be declared for any object which is going to
be used as a timer or a daemon, or the Z-machine may crash at run-time.


---------------------------------------------------------------------------
D10.  Customising the parser
---------------------------------------------------------------------------


Inform 5 has a variety of new features to make customising the parser
possible: for instance, numbers can be specified directly in grammar
tables, like so:

     Verb "type"
                     * number                         -> TypeNum
                     * special                        -> TypeWord;

so that the TypeNum action will happen if the player types

     > type 504

but TypeWord will happen if the player types any other text.  The routine
which parses numbers can itself be rewritten to allow, say, Roman numerals.


We can also sort out objects according to attributes that they have:

     Verb "use" "employ" "utilise"
                     * edible                         -> Eat
                     * clothing                       -> Wear
     ...and so on...
                     * enterable                      -> Enter;

In fact, you can supply a routine to make almost any parsing decision.
For instance:

     [ French w n; w=NextWord();
         if (w=='un' or 'une') n=1;
         if (w=='deux')        n=2;
         if (w=='trois')       n=3;
         if (w=='quatre')      n=4;
         if (w=='cinq')        n=5;
         if (n==0) return -1;
         parsed_number = n; return 1;
     ];

will detect French numbers, and can be used by something like:

     Verb "type"
                     * French                         -> TypeFrenchNum
                     * number                         -> TypeNum;

The specification for a routine like this is as follows: it is to use
NextWord (possibly several times) to look at the appropriate words which
the user has typed.  The variable wn (current word number) may also be
helpful.  The routine must return:

     -1      if the user's input isn't understood,
      1      if there is a numerical value resulting
                 (and the value should be put in the variable parsed_number)
      n      if object n is understood.

On an unsuccessful match (returning -1) it doesn't matter what the final
value of wn is.  On a successful one it should be left pointing to the next
thing after what the routine understood.


Another possibility is as follows.  Suppose we want a verb, "free", but only
to release animals from a cage:

     [ CagedCreature;
         if (noun in wicker_cage) rtrue;
         rfalse;
     ];

     Verb "free" "release"
                     * noun=CagedCreature             -> FreeAnimal;

So that only nouns which pass the CagedCreature test are allowed.


The above examples are slightly contrived because they create wholly
new and unlikely verbs.  More often, one would want, say, a big array of
labelled buttons, any of which could be pushed.  So the verb for "push"
ought to be extended by:

     Extend "push"
                     * Button                         -> PushButton;   

and a routine called Button could be written to accept things like

    "button j16", "d11", "a5 button".

The point of Extend is that it is against the spirit of the library to
alter the standard library files - including the grammar table - unless
absolutely necessary.

Normally, extra lines of grammar are added at the bottom of those already
there.  This may not be what you want.  For instance, "take" has a grammar
line

                     * multi                          -> Take

quite early on.  So if you want to add a grammar line which diverts
"take something-edible" to a different action, like so:

                     * edible                         -> Eat

then it's no good adding this at the bottom of the Take grammar, because
the earlier line will always be matched first.  Thus, you really want
to insert your line at the top, not the bottom, in this case.  The right
command is

     Extend "take" first
                     * edible                         -> Eat;
  

You might want to actually replace the old grammar completely, not just
add a line or two.  For this, use

     Extend "push" replace
                     * Button                         -> PushButton;

and now "push" can be used only in this way.


As an example (suggested by a frustrated Inform 4 user), suppose we have
a spaceship which has a control panel with five sliding controls, each of
which can be set to a numerical value.  Now we could implement these with
five separate objects, essentially duplicates of each other.  (And by
using a class definition, this wouldn't look too bad.)  But if there were
500 slides this would be less reasonable.  So:


     [ ASlide w n;
        if (location~=Machine_Room)            !  Slides only make sense in
            return -1;                         !  the Machine Room
        w=NextWord();
        if (w=='slide') w=NextWord();
        n=0;
        if (w=='first' or 'one')   n=1;
        if (w=='second' or 'two')  n=2;
        if (w=='third' or 'three') n=3;
        if (w=='fourth' or 'four') n=4;
        if (w=='fifth' or 'five')  n=5;
        if (n==0) return -1;                   !  Failure!
        w=NextWord();
        if (w~='slide') wn--;                  !  Move word counter back to
                                               !  first misunderstood word
        parsed_number=n;
        return 1;                              !  Success!
     ];
     
     Global slide_settings data 10;            !  Ten bytes of data to hold
                                               !  five words for the settings
                                               !  (all initially zero)
     
     !  An interesting point here is that "noun" and "second" contain the
     !  appropriate numbers, and not objects: this all happens automatically

     [ SetSlideSub;
        slide_settings-->(noun-1) = second;
        print_ret "You set slide number ", noun,
                  " to the value ", second, ".";
     ];
     
     [ XSlideSub;
        print_ret "Slide number ", noun, " currently stands at ",
            slide_settings-->(noun-1), ".";
     ];
     
     Extend "set" first
                * ASlide "to" number                  -> SetSlide;
     Extend "push" first
                * ASlide "to" number                  -> SetSlide;
     Extend "examine" first
                * ASlide                              -> XSlide;

This results in something like:

     >look

     Machine Room
     There is a control panel here, with five slides, each of which can be
     set to a numerical value.

     >push slide one to 5
     You set slide number 1 to the value 5.

     >examine the first slide
     Slide number 1 currently stands at 5.

     >set four to 6
     You set slide number 4 to the value 6.



---------------------------------------------------------------------------
Appendix A:  The Z-machine
---------------------------------------------------------------------------


     "The legend that every cipher is breakable is of course absurd,
     though still quite widespread among people who should know better."

          (J. E. Littlewood, "A Mathematician's Miscellany")

     "There is an obvious resemblance between an unreadable script
     and a secret code; similar methods can be employed to break
     both.  But the differences must not be overlooked.  The code is
     deliberately designed to baffle the investigator; the script
     is only puzzling by accident."

          (John Chadwick, "The Decipherment of Linear B")


The Z-machine, an imaginary computer originally devised by Joel Berez and
Marc Blank in 1979, is well-adapted to its task.  Its behaviour is exactly
specified and it has been implemented on virtually every small computer.
It maintains a hierarchy of objects and possessions, and does the
computationally-intensive part of parsing input itself.

The purpose of this appendix is to fully document the Z-machine, discuss
to what extent it is presently implemented and detail how to use Inform
as an assembler.

Only a few of the pieces in this jigsaw were placed by myself, and the
credit belongs to many people.  Old hands at the decipherment game will
no doubt find the opcode table tiresomely familiar: but, as with a chemist
finding Mendeleyev's periodic table on a laboratory wall, so will the hacker
be reassured by the sight.

I gratefully acknowledge the help of Paul David Doherty and Mark Howell, who
each read a draft of this appendix and sent back detailed corrections. 
Mistakes and misunderstandings remain my own.


To begin, three general points.  The fascination with the letter Z began
with "Zork": apparently "zork" was a nonsense word used at MIT for the
current uninstalled program in progress, and stuck.  The Z-machine runs what
we shall call Z-code.  Just as we shall use the term "Z-machine" for both
the machine and its loaded program, so ZIP (Zork Implementation Program) was
used to mean either the interpreter or the object code it interpreted.  Code
was written in ZIL (Zork Implementation Language), which was derived from
MDL (or "muddle"), a particularly unhelpful form of LISP.  It was then
compiled by ZILCH to assembly code which was passed to ZAP to make the ZIP. 
We refer to code as "Z-code" to avoid confusion with "Zip", the name of Mark
Howell's interpreter (by far the best available).


However, in talking about "the Z-machine", what do we really mean: the
design Infocom had in mind, the syntax which seems to be in their surviving
game files, or what is actually done by various interpreters, theirs or
ours?  Aided by the patient detective work of my predecessors (e.g.
disassembling Infocom-written interpreters, and going through all existing
game files) I shall try to give all three specifications.  But Inform
programmers need to bear in mind that it is the third that really counts.

For the standard format (version 3) there are many existing games and there
isn't much conflict.  But for later versions, there are few games, not all
the opcodes were ever used and the interpreters publically available
disagree about what to do with some of the obscure ones.  To some extent
this account is an attempt to settle arguments.


Finally, note that the Z-machine does not provide the bulk of the parser. 
The parser has to be coded, and the tables it uses (which some investigators
think are part of the Z-code format) are in fact the same across different
Infocom games only because they contain similar parsers.  So they are not
specified here.  An account of the parsing tables generated by Inform can be
found in the body of the manual.



---------------------------------------------------------------------------
A1. The early Z-machine
---------------------------------------------------------------------------


There were six main versions of the Z-machine, and several minor variant
forms.  These are recognisably similar but with labyrinthine differences,
like different archaic dialects of the same language.  (And, of course, the
job of decipherment is made harder by the fact that the archaeological
record suddenly stops in about 1989 when the civilisation in question
collapsed.)

Broadly, these fall into two groups: early (versions 1 to 3) and late
(4 to 6).  This appendix will give an expository account of versions 3
and 5 (as representative of these two groups) but will conclude with
brief tables and specification for all versions.

Since it is easiest to understand, and since the majority of extant Infocom
story files use it, version 3 is the place to begin.


The version 3 Z-machine has a memory map of at most 128K long.  Addresses
within it are nonetheless held in 2-byte words, which is why some addresses
are stored as half their actual values, and why some items (routines and
static strings) are always stored at even addresses.

Here, for the sake of example, is a memory map produced by Inform when
compiling a smallish game with the -z (display the Z-machine) switch set:

   Dynamic +---------------------+   00000
   memory  |       header        |
           +---------------------+   00040
           |   synonym strings   |
           + - - - - - - - - - - +   00042
           |    synonym table    |
           +---------------------+   00102
           |  property defaults  |
           + - - - - - - - - - - +   00140
           |      objects        |
           + - - - - - - - - - - +   002f0
           | object descriptions |
           |   and properties    |
           +---------------------+   006e3
           |  global variables   |
           + - - - - - - - - - - +   008c3
           |       arrays        |
           +=====================+   00b48
   Static  |    grammar table    |
   data    + - - - - - - - - - - +   010a7
           |       actions       |
           + - - - - - - - - - - +   01153
           |     preactions      |
           + - - - - - - - - - - +   01201
           |     adjectives      |
           +---------------------+   0124d
           |     dictionary      |
           +---------------------+   01a0a
           |       Z-code        |
           +---------------------+   05d56
           |       strings       |
           +---------------------+   06ae6


1. The Header
-------------

The first 64 bytes contain a header, which is detailed fully in (A8).  It
contains (mainly) addresses of other tables and flags, and is both a
vehicle for the game to tell the interpreter what to do, and for the
interpreter to tell the game what it can do.

To briefly run through the essential points of the version-3 header:
the first 4 bytes are

03  <Flags>  <Release Number>
             ----2 bytes-----

3 indicates version 3; the release number is as set in the program; for
the flags, see (A8).

Next come seven word addresses, at words 2 to 8:

2     <Start of Routines>    Where routines begin, in bytes

Actually, in some games, read-only data seems to continue here: this
pointer actually tells the interpreter where the "resident" data ends,
i.e. the part of the game which is kept in memory at all times rather
than loaded off disc as and when required.

3     <Main Routine>         Address of main routine, in bytes, +1

(This +1 is why Main cannot have local variables - it is a peculiarity
of the standard.  Note also that this is uniquely a routine address in
bytes and not words: Main must occur in the lower 64K of the file.  Inform
always sets word 3 to be word 2, plus 1, because it requires Main to be
the first routine defined.)

4     <Dictionary>           The dictionary table address, in bytes
5     <Object tree>          Object table address, in bytes
6     <Variables>            Global variables address, in bytes
7     <Save area size>       The total number of bytes in a saved game

Saving the game is done by saving this many bytes from the beginning of the
machine.  (Saved games also contain the current state of the Z-machine
stack; the stack is _not_ stored anywhere in the Z-machine's memory.)

8     <More flags>

For which, see (A8).

This is followed by the six bytes from byte 18 to 23, which are the version
number string.  (Inform sets these to the current date, in the form YYMMDD.)
Then more words:

12    <Synonyms table>       Synonym table address in bytes
13    <Length>               Length of file, in words
14    <Checksum>             Sum of bytes from 64 upwards, mod $10000

The length and checksum are only needed to perform "verify", something which
most games only do when explicitly asked: these are set by Inform anyway.

Inform also pads out the file to an exact number of 512-byte blocks with zeros,
since some interpreters still make use of swapping blocks in and out,
virtual-memory style.

The remaining bytes in the header are used by the interpreter and should be
left alone by the game code.

2. Synonyms
-----------

We are now at $0040 and by convention we reach the synonyms.  Usually, the
actual strings (the expansions of the synonyms) are stored here, one after
another, making up 96 strings.  When that is out of the way, the actual
table begins (and this is what the synonyms address points to).  The table
contains 96 two-byte entries, giving the word addresses of the strings
before it.

(Inform initially puts a single dull string "   " (three spaces) at $0040,
then writes the "low strings" and then makes a table of 96 pointers.  The
first 32 always point to the "   " string, and the next 64 to any synonyms
explicitly declared by the source code.  (Any synonyms left undeclared point
to the "   " string as well.))

(Note that before Release 4 Inform did not write the synonym expansions
declared by the user at $0040: but then under version 3 there was no
requirement to.  The reason for the change is given in (A4).)

3. Object Table
---------------

Next is the object table.  In fact it begins with what is sometimes called
the "global properties table", though it is actually a table of default
values of properties.  This is a list of 31 2-byte words.  There is no
property 0, so the first word is always 0000.

(Inform also sets the default for property 1 - the special "name" property -
to 0000; the remainder are set in property definitions.)

After these 62 bytes, the objects begin, beginning from object 1.  An object
entry consists of 9 bytes, looking like:

   <the 32 attribute flags>   <parent>  <sibling>  <child>  <properties>
   ---32 bits in 4 bytes---   ---3 bytes------------------  ---2 bytes--

The three parent-sibling-child bytes are 00 when the object pointed to is
"nothing".  The <properties> is an address (in bytes) of the properties
attached to the given object.

When all these 9-byte entries are out of the way, the properties tables
begin.  (Inform keeps these in the same order as the objects they are
attached to.)  An individual property table has the brief header

  <text-length>   <text of short name of object>
  -----byte----   --some even number of bytes---

(where the text-length is the number of 2-byte words making up the text,
which is stored in the usual format).

Then the properties held are listed, in descending numerical order.  (This
order is essential.)

A property is stored as

  <size byte>   <the actual property data>
                ---between 1 and 8 bytes--

The size byte is arranged as 32*the number of data bytes, plus the property
number.

Each list of properties is ended by a 00 size byte.  This is why there is no
property 0.

4. Global variables
-------------------

When all the property tables are done, we come to the global variable table.
Global variables are numbered from 0 to 239, and this table begins with 240
initial 2-byte values for them.  After this is conventionally left space for
all the arrays, dynamic strings and so on which they point to.

We have now reached the top of the save area.  Everything above here is
never altered.

5. Grammar and parsing tables
-----------------------------

Next is the table of grammar, which is described as above.  It is
immediately followed by the actions table, the preactions table and then the
adjectives table.  Note that the Z-machine knows nothing at all about these
tables, and it is entirely a matter of convention that they tend to have a
standard form.  (Inform compiles these to an approximation of what a typical
version-3 game codes here.)

6. The dictionary
-----------------

And next the dictionary table, described more fully in (15) above.
Briefly, there is a short header:

  n    <list of ASCII codes>  entry-length  number-of-entries
 byte  ------n bytes--------      byte         2-byte word

The codes listed are word-separators: typically (and under Inform
mandatorily) these are '.', ',' and '"'.  " " (space) does not appear
because these characters will not only divide words but also come
out as words in their own right: thus,

  > fred,go

will be lexically analysed as three words: "fred" "," "go".

In V3 each word entry has 2 words of text (giving up to 6 characters,
and padded out to a full 6 Z-characters with the 5 "pad" character
if necessary), plus a few extra bytes of data: almost invariably
(and under Inform mandatorily) three.  In later versions, there
are 3 words of text (9 characters resolution) plus three bytes more.
So entry-length will usually be 7 or 9.

The Z-machine never explicitly looks at these data bytes and in
principle the programmer is at liberty to do as he pleases with
them.  (But not if he wants to use Inform: see (15).)


7. The code area and static strings
-----------------------------------

Next is the code area.  Not all Infocom games begin with Main, but all
Informed ones do.  The code area simply contains a list of routines.

All routines (and static strings) must occur at word addresses, so as to
enable their addresses to be encoded in 2 bytes.  (Inform occasionally
inserts 00 bytes between routines to ensure this.)

A routine begins with one byte indicating the number of local variables the
routine has (from 0 to 15), and then with that many 2-byte words giving
their initial values, if not supplied by the call to the routine.  (Inform
never makes use of this initialisation, and simply stores 0000's here.) 
Unlike global variables, these bytes are _not_ used for the current values
of the variables: they are kept on the stack.

Executable code follows this header.  There is no special marker for the end
of a routine; it is simply expected that in every case a legal return
instruction will be hit.

Finally, from the end of the code to the top of memory are the static
strings.  These are put up here to be out of the way, where they won't clog
up the bottom 64K of memory.  There's no table of their addresses, or pointer
to where they begin; each is referred to by an address in the code or data
given earlier.


---------------------------------------------------------------------------
A2. How text is encoded
---------------------------------------------------------------------------


    "This technique is similar to the five-bit Baudot code, which
    was used by early Teletypes before ASCII was invented."

         ("How to Fit a Large Program Into a Small Machine",
          Marc S. Blank and S. W. Galley)


Text is stored as a sequence of 2-byte words.  Each of these is divided into
three 5-bit pieces, plus 1 bit left over, arranged as

   --first byte-------   --second byte---
   7    6 5 4 3 2  1 0   7 6 5  4 3 2 1 0 
   bit  --first--  --second---  --third--

The bit is set only on the last 2-byte word of the text, and so marks the
end.

The pieces are then characters, with values in the range 0 to 31.

There are three alphabets, in which the numbers 6 to 31 mean:

  A0     abcdefghijklmnopqrstuvwxyz
  A1     ABCDEFGHIJKLMNOPQRSTUVWXYZ
  A2      ^0123456789.,!?_#'"/\-:()

('^' being actually the new-line character: note also that Inform uses
the notation '~' as '"' for convenience.)

Character 0 is a space in all alphabets.  Characters 1, 2 and 3 are used for
abbreviations: thus, 1 followed by 14 means "print entry 14 in the synonym
table"; 2 followed by 5 means "print entry 32+5=37..."; 3 followed by 20
means "print entry 64+20=84..." etc.

The Z-machine provides these for commonly occurring strings to be printed
out as if they were characters, thus saving memory.  Though they are
actually abbreviations, they are by convention called "synonyms".  (In
practice this can save about 10K in a 128K file.)

(Inform makes use of these only when instructed to (e.g. @12 is compiled to
1, 12, meaning print the 12th entry in the synonym table), or when
abbreviations have been declared (see section (19)).)

By default, a character is presumed to be in A0, i.e. to be a lower-case
English letter.  However, the character 4 means that the next one (only) is
in A1; and 5 means the next is in A2.

(Note for purists: actually the full rule is

            A0      A1      A2
    4       [A1->]  [A1->]  [A0->]
    5       [A2->]  [A0->]  [A2->]

but since alphabet changes are now (in versions 3 and onward) not permanent,
it seems pointless ever to use 4 and 5 in alphabets 1 and 2.)


Notice that character 6 in A2 is blank.  It isn't a space: it simply isn't
there.  The sequence 5 followed by 6 indicates that the next two characters
define an ASCII value.  This is the way to get at the characters not in any
of the three alphabets.  For example, the familiar message

  *** You are dead ***

takes four "characters" to produce each of the *'s.

Finally, note that the end-bit only comes up once every three characters,
so that a way is needed to safely use up any spare characters in the last
2-byte block.  This is done by padding out with 5's.  (5 followed by 5 does
nothing.)

This is especially the case with dictionary entries.  Some dictionary
entries, like "i", ought only to take one 2-byte block, but in order to make
all entries two 2-byte blocks and alphabetically sortable by number, they
are padded out by up to five 5's in a row.

(Note that care must be taken to avoid dictionary entries ever containing
use of synonyms.)

In practice the text compression factor is not really very good: for
instance, 155000 characters of text squashes into 99000 bytes.  (Text
usually accounts for about 75% of a story file.) But the encoding does at
least encrypt the text so that casual browsers can't read it.


Notes: The versions 1 and 2 formats are slightly different: see below.

In versions 5 and 6, the three alphabet blocks need not be the
default ones A0 to A2 tabulated above, but instead can be chosen by the
story file itself: see (A8) for details of how to do this.

In version 6, it is expected that the ASCII codes for tab (9) and control-K
(11) are printed slightly differently: a tab at the start of a line should
be a paragraph indentation suitable for the font being used, but anywhere
in the middle of a line should be a space; and 11 should be rendered as
a gap between two sentences.


---------------------------------------------------------------------------
A3. How Z-code is encoded
---------------------------------------------------------------------------


     "We do but teach bloody instructions
      Which, being taught, return to plague th' inventor"

             (Shakespeare, "Macbeth")


The encoding of Z-code is to say the least complicated.  The reader is
warned that there are subtle differences between the various versions.
However, this section presents common information.

There are all kinds of exceptions intended either to make small economies of
code size (these are very seldom worth the effort, in fact) or to provide
new features tacked on at the last minute.

Experimenting with Inform as an assembler, while tracing is turned on, may
be helpful.

This account is to be read in conjunction with the opcode table and
dictionary, so it does not tabulate or individually discuss opcodes.

1. Operands
-----------

The term "operand" is used a little loosely because there are three kinds
of argument to an opcode which do not count as "operand"s: "store"s,
"branch"s and "string"s.

Z-code understands four kinds of operand, and describes these in 2-bit
fields:

  $$00    Large constant (>=256)         2 bytes
  $$01    Small constant (0 to 255)      1 byte
  $$10    Variable                       1 byte
  $$11    Omitted altogether             0 bytes

Variables are described in one byte.  00 means the top of the stack, 01 to
$0f are the local variables of the current routine and $10 to $ff are the
global variables, 0 to 239.  Writing to 00 pushes something onto the stack
and reading from it pulls it off.  The stack can also be manipulated (with
care) using the PUSH, PULL and POP instructions.  The stack is guaranteed to
be at least 512 bytes long, and some interpreters are more generous.  There
isn't any way to check stack overflowing, so be careful with recursion.

(One of the trickiest problems in compiling Z-code is throwing away unwanted
return values of routines which are left on the stack... it can take
hundreds of turns before a game crashes if this is got wrong.)

2. Opcodes
----------

In versions 3 and 4 Z-code opcodes are 1 byte only.  To begin with, look at
the top two bits.  If these are $$11, we shall call it "variable"; if $$10,
"short" (0OP or 1OP, i.e. 0 or 1 operands); and otherwise "long" (2OP:
2 operands).  (In versions 5 and 6, there are also "extended", EXT, opcodes.)


For short opcodes, look at the next two bits (4 and 5).  These give the kind
of operand which the code has.  If this is $11, there isn't an operand and
the opcode has no argument at all.  In this event, the opcode number is the
bottom 4 bits (see table of 0OP opcodes).


If the type wasn't $11, then an operand follows, and the bottom four bits
gives the opcode number (see table of 1OP opcodes).


"Long" opcodes have two operands.  The bottom 5 bits of the opcode say what
it is (see table of 2OP opcodes).

The alert reader will notice that bits 5 and 6 are left spare to be used. 
Now there are two operands to specify, which ought to take up 4 bits, which
obviously won't fit.  So a more economical form is used instead.  Bit 6
refers to the first operand, and bit 5 to the second.  A value of 0 means a
small constant and 1 means a variable.  Now, type $11 (not really there)
operands can't happen, so that's no problem, but there might well be type
$00 (large constant) operands, for example in "@mul x #666 sp".  In this
event, the opcode is instead programmed as a "variable" opcode.


So we must now describe the "variable" or VAR opcode form.  In addition to the
possible opcodes which can arise from overflowing "long" opcodes, there
are others which can only be "variable".  In the former case bit 6 is clear
and in the latter it is set.  In either case the bottom 5 bits contain the
opcode number: see the 2OP or VAR tables accordingly.

Some of these are only of "variable" type because the available codes for
the other types had run out - PRINT_CHAR, for instance.  Others, especially
CALL, need the flexibility to have between 1 and 4 operands.

In the "variable" type opcode, all eight bits of the opcode have been used
up, so we have to add another byte describing the operands.  This is divided
into four 2-bit fields.  For example, $$00101111 means large constant
followed by variable (and no third or fourth opcode).

Once the opcode is out of the way, the operands are simply stored in one or
two-byte form as appropriate.

3. Strings, stores, branches
----------------------------

PRINT and PRINT_RET are followed by text: this is assembled in the usual way
immediately after the opcode (which may well be at an odd address, but this
doesn't matter) and execution resumes after the last 2-byte word of text
(the one with top bit set).


"Store" opcodes return a value: for example, MUL multiplies its two arguments
together, and CALL calls a routine which must return a value.  Such
instructions are followed by a single byte giving the variable (stack
pointer, local or global as usual) to put it in.  This may look like an extra
operand but is not: there is no need to tell the Z-machine what type it has,
since it must be a variable.


Finally, there are instructions which test a condition.  Apart from the
obvious branch instructions (JE and so on), SAVE does this (in version 3),
for example, the test in question being whether or not the save was
successful.  Branches are stored in two different ways for economy reasons:
nearby ones in a single byte at the end of the instruction, farther ones
in two such bytes.

The top bit of the first byte of a branch is the "flag".  If this is clear,
then a branch occurs when the condition came out false.  If it is set, then
the branch occurs when it was true.

If the next bit (bit 6) is set, then the branch is in abbreviated 1-byte
format and the offset is in the bottom 6 bits (0 to 5).  If not, the offset
is in the bottom 15 bits (0 to 6 of the first byte, and all of the second).
This offset can be positive or negative.  (Eg., all 1's means -1 in the
usual way.)

In the abbreviated form, an offset of 1 in fact means "return true from the
current routine" and an offset of $20 (i.e., -31) means "return false".  An
offset of 1 is never useful but -31 might arise, and so it is essential to
use the long form for such branches.

Working out what the offset ought to be is more complicated than it appears
because the PC has already moved on from the start of the instruction when
it reaches the branch.  The bizarre formula in question is

  Offset = Destination address - Address of this instruction - Length + B

where

  Length = number of bytes in instruction (not counting the branch)

and B is 1 for short branches, 0 for long ones.

In practice Inform compiles branches in the long form, considering the
economy to be not worth the nightmarish computation needed to make the
long/short decision.  (One problem is that the number of bytes in each
instruction _must_ be the same in both passes, so that the decision needs to
be made before the value of the offset is known... in a 2-pass compiler this
is insoluble.  Another is that the offsets are affected by the size of the
branch, confusing things considerably on forward branches.)  However, its
assembler mode allows you to make an explicit choice.

JUMP instructions similarly encode their address operand as an offset, but
always as a two-byte (signed) constant.  In this respect they differ from
CALL instructions.  In a CALL, the address is half the absolute routine
address.

A few instructions both store results and branch: if so, the store comes
first.

4. Extended set of opcodes
--------------------------

The extended (or EXT) set only applies in versions 5 and 6.  These are two
byte opcodes, of which the first byte is always 190, the second the opcode
number.  Subsequently, they behave exactly as VAR...

...except that, actually, two of them don't.  Two of them, CALL_VS2 and
CALL_VN2, have up to 7 operands and so have two bytes of type information
instead of one.  Inform does not know this, and they cannot safely be
used.  (It is little loss.)

5. Routine and string addresses
-------------------------------

These are word addresses in version-3 (thus a routine or string must be at
an even byte address in the 128K memory map), longword addresses (thus,
byte addresses divisible by 4 in a 256K map) in versions 4 and 5, and
quadword (divisible by 8) in version-6.

In version-6 they may be offset by an amount in the game header (see (A8))
to enable the memory map to stretch another 64K or so beyond the apparent
512K limit.


---------------------------------------------------------------------------
A4. The six versions of the Z-machine
---------------------------------------------------------------------------


        "Confusion now hath made his masterpiece"

              (Shakespeare, "Macbeth")


Altogether there have been six main versions of the Z-machine, some of which
have had very minor variations.  These are:

  Version 1    Early Apple ][ games for DOS 3.2, and the TRS-80 Models I/II
  Version 2    Early Apple ][ games for DOS 3.3, and the TRS-80 Models I/II

  Version 3    "Standard" series games
  Version 4    "Plus" series games
  Version 5    "Advanced" series games, or, as the marketing division would
               have it, "Solid Gold Interactive Fiction" - a reference to
               the colour (though not composition) of the boxes they came in

  Version 6    Later games with graphics, mouse support, sound effects
               and so on

Such interpreters are sometimes called ZIP (versions 1 to 3), EZIP/LZIP
(V4), XZIP (V5) and YZIP (V6).

Versions 1 and 2 are thought to be extinct, though collectors have a few
fossils and the "Zip" and ITF interpreters implement them anyway.  However,
there are many Version 3 games still in circulation, and enough worthwhile
Version 4 and 5 ones to make the format important.

Most of the Infocom games exist in several different releases, and some
were written for one version and then ported to later ones.  "Zork I", for
instance, exists in at least ten editions, two early, seven in version-3
(with release numbers between 5 to 88 in chronological order) and one in
version 5 (release 52 - the releases go back to 1 when the version changes).

There are few version 6 games, and they are of (arguably) poorer quality.
Few interpreters exist for them, because they are inherently difficult to
port to different machines.  However, there will be a brief discussion of
the version-6 format here and in effect a full specification in the
dictionary which follows the opcode table.


The Z-machine as originally constructed was surprisingly similar to that
in use when Infocom ground to a halt.  Version 1 (1979-80) had essentially
the same object format, for instance, and a similar header, but encoded text
with a different character table and had no concept of synonyms.  Its
addresses were all word-addresses and not byte-addresses, so presumably a
small amount of memory was wasted in null bytes to fix parities everywhere.

Version 2 was quite a minor enhancement, presumably made only because a new
interpreter had to be written anyway.  Synonyms appeared, but only in one
32-word bank, and the six-digit serial number appeared in the header,
though it wasn't always the date in those days: Release 7 of "Zork II",
for instance, is (reputedly) called "UG3AU5".

Version 3 changed the text encoding alphabets again, and tripled the number
of synonyms possible.  (Consequently the previous "caps lock" style
permanent changes of alphabet were dropped.)  The "verify" code and verify
checksums appeared; and a new opcode to print the status bar at the top of
the screen was introduced.  (Previously, this was updated only when input
was taken from the keyboard.)  The earliest Version-3 releases (Deadline,
then Zorks I and II) were in March and April 1982; the latest (the
"Minizork", a cassette-based Commodore sampler of Zork) in November 1987.

A primitive form of screen-splitting (which, presumably, was devised in a
hurry in 1984 and then accidentally became the foundation for the character
graphics designs of later versions) was allowed by some interpreters, in
order to give "Seastalker" a sonar display.  In order that "Seastalker"
should run on less enlightened interpreters, the game itself contained code
to check whether this feature was available before using the opcodes.
And "The Lurking Horror" (1987) has sound effects (on some machines) - another
sign of things to come.

Nevertheless by 1982 the Z-machine had stabilised to a reasonably clean
design.  It was very portable, contained everything reasonably necessary and
most of its complications were optimisations to squeeze a few more bytes out
of the 100K or so available on an early-1980s floppy disc.  (Actually the
Infocom compiler's code generator, although very good at exploiting these
tricks, had little optimisation, and some of its code makes disheartening
reading.  But then the same could be said of Inform.)


By 1985 there were two basic pressures to change.  One was that home
computers were larger, and several fundamental restrictions (the game size
being only 128K, the number of objects only 255, the attributes only 32,
the properties only 30) were beginning to bite.  The other was the drive for
more gimmicks - character graphics, flashier status bars, sound effects,
different typefaces, and so on.  The former led to logical, easy to
understand structural changes in the machine.  The latter, in contrast, made
a mess of the system of opcodes.

More does not mean better: just because the price of paper falls is no
reason to double the size of the modern novel, for instance.  Nor is
literature (pace e. e. cummings) much improved by using four different
typefaces and illustrating it with typewriter pictures.  Also, the relieving
of size restrictions only increased design time - or lowered its quality.

Nonetheless, two excellent games resulted from the lifting of size
restrictions.  In August 1985 the first version-4 game ("A Mind Forever
Voyaging") reached production, and it was followed most notably by
"Trinity" (which had previously been shelved as too ambitious for the
version-3 format).  Still, most of the new 1985/6 games remained in
version-3: after all, there were still plenty of 8-bit home computers
around, too small for version-4 games: and, despite critical acclaim,
the new games consequently did not sell as well.

Version 5 games began to appear in September 1987 with "Beyond Zork" and
"Border Zone".  Both of these games needed new features - character graphics
gone wild in the case of the former, and real-time keyboard interaction in
the latter.  The number of opcodes grew ever faster as a result. 

Although five old games were re-released in Version 5 editions (with an
in-game hints system added, and benefitting from 9-letter word dictionaries,
but otherwise as written), the direction was all too clearly away from
the old text game into graphics.  Having gradually moved this way ("Beyond
Zork" looks like a parody of an early mainframe maze game, for instance)
there was nothing left but to complete the process, and so Version 6 was
born.  After something of a hiatus in 1988, the last few
increasingly-unrecognisable Infocom games appeared: "Zork Zero", "Shogun",
"Journey", "Arthur".

Infocom gradually ceased to exist in about 1987-9 for financial reasons
generally said to be unrelated to their games output.  Whether they would
have continued to release text games of the classical style is arguable.


---------------------------------------------------------------------------
A5. The late Z-machine
---------------------------------------------------------------------------


Versions 4 and 5: Architecture
------------------------------

The bulk of this section is given over to a detailed discussion of the
differences between version 3 and version 5, since those are the two forms
Inform can produce.  (Version 4 is nearer to version 5 than 3.)  We
begin with the architecture.


The memory map doubles to 256K, a change which is surprisingly easy to make. 
But the processor remains 16-bit.  This means that all the word addresses
are now longword addresses (i.e., addresses divided by four).  However,
this only really affects addresses of routines and static strings (which are
now aligned to longword boundaries, not word-boundaries).  Almost all the
addresses in the save area (eg, the property offsets for objects) are byte
addresses still.  This means that the code needs to begin before the lowest
64K is all used up, but in practice this is no problem.

An annoying exception to this rule is that the synonyms table contains word
addresses still, and thus assumes that the synonym strings lie in the lower
128K.  This is understandable because the Z-machine used to rely on virtual
memory (swapping pages of memory on and off of disc), and the synonyms need
to be accessed at virtually all times: keeping them together in low memory
(just after $0040) is therefore efficient, and giving them addresses
divisible by four would waste bytes in the save-game-area.  Nonetheless it
is a nuisance.  Inform therefore provides a "low string" directive to insert
strings in this area.

The only important change to the header, then, is that the length is in
longwords.

A minor new feature in Version 5 is that the game can change the alphabet
tables used for text decoding, putting a pointer to them in the header at
$34-5: this is usually left as $0000, meaning the default alphabets.  See
(A8).  Also, it seems to be expected that the interpreter tells the game
the dimensions of the screen by writing them into the header itself, in play.
Thus it is fairly safe to consult

  Byte 32 - Screen height
  Byte 33 - Screen width

and it's hard to cope without this information, since games after Version 3
have to construct their own status bars.  (Unfortunately it isn't clear that
the various interpreters all understand the same thing by "height" and
"width", and it's probably wise to check these are not zero before
calculating with them - just in case.)


There is effectively no limit on the number of possible objects, since an
object number is no longer expected to fit into a single byte.  This has the
knock-on effect that in most games many properties will have to allow for a
word and not a byte (which is why Inform defaults property definitions as
"long" in version-5 mode), but the only architectural effect is that object
definitions grow in size.  Since the number of attributes is increased from
32 to 48, and of properties from 30 to 62, this would be needed anyway: and
here is the new form:

   <the 48 attribute flags>   <parent>  <sibling>  <child>  <properties>
   ---48 bits in 6 bytes---   ---3 words, i.e. 6 bytes----  ---2 bytes--

giving a 14-byte block.  As before, the properties field is the byte address
of the property table.

The property table is also altered.  A property is now stored as

  <size and number>     <the actual property data>
  --1 or 2 bytes---     --between 1 and 64 bytes--

The property number now occupies the bottom 6 bits, not 5, of the first size
byte, which is why more properties are available.  But this only leaves two
bits.  If these are $$00, the size is taken as 1, and if $$01, then it is
taken as 2.  (These are the most common sizes in practice.)  Otherwise the
top bit is set, which means that the second byte is present, and contains
the size in its bottom six bits.

However, when present the second byte must also have the top bits set to
$$10.  The reason for this is that the size must be parsable either forwards
or backwards - the Z-machine needs to be able to reconstruct the length of a
property given only the address of the first byte of its data.

There are very many (e.g. 2000) property entries in a story file, so this
optimisation is probably worthwhile.


The verb, action, preaction, adjectives and so on tables are generally of
a different format in Version 5 to earlier games.  However the Z-machine
knows nothing of this (and Inform in fact creates version-3 style tables
(which are perfectly adequate) even in version-5 mode).


Whereas Version 3 games have dictionaries giving words to 6-letter accuracy,
all Version 4 and above games have 9-letter accuracy.  (I.e., two and three
words of encoded text respectively.)  Otherwise, the specification is the
same.

The extra resolution makes it reasonable to include hyphenated words, which
might not have been sensible earlier because of the number of five-bit
blocks they would have needed.


These modifications appear at first sight to make much larger, less
efficient code, but this is misleading.  The original version-3 "Curses"
was only 3% larger when first compiled as version-5, and a good part of that
was the extra dictionary resolution.


There is one sensible structural change to the way actual code is written:
in Version 5 (not Version 4, though) the header of a function no longer
contains initialisation values for its local variables.  In practice these
were very often zero, wasting a large number of bytes across the whole
story file.  On the other hand, one peculiarity of the machine is that
functions can be called with 0, 1, 2 or 3 arguments, and routines in
version-3 games used to be able to put a default value in their headers
for any argument not supplied by the caller.  This they can no longer do,
so that they are unable to tell how many arguments actually were supplied:
and so a new branch instruction CHECK_NO_ARGS exists to test this.

Another improvement is in subroutine calls.  In Version 3 code, a CALL
instruction has a variable argument list, which wastes a byte even when
there are no parameters.  Also, every function call returns a value, and
in Version 3 this value had to be written somewhere even when it wasn't
wanted - wasting another byte.  (In fact Inform used to return this to the
stack, and then pop it from the stack - wasting another one.  Nowadays it
stores unwanted return values in a scratch global variable.)  In Version 4
(and to a greater extent in Version 5), new forms of the CALL instruction
are provided which automatically throw away the return value.

This leads to the nightmarish position that there are eight variant forms of
CALL in the Version 5 machine.  Inform christens six of these as follows:

  CALL_VS  <address> <0 to 3 arguments> <place to put answer>

(which is just as in version 3 CALL, and compatible with it),

  CALL_VN  <address> <0 to 3 arguments>

which is the same but throws away the answer, and

  CALL_1N  <address>                   address();
  CALL_1S  <address> <answer>          answer=address();
  CALL_2N  <address> <a1>              address(a1);
  CALL_2S  <address> <a1> <answer>     answer=address(a1);

Two of the others are called CALL_VS2 and CALL_VN2 by Inform: these are
provided for function calls with up to seven arguments, circumventing
the usual restriction on function calls to have at most three: and,
uniquely, they have _two_ bytes of type bits, arranged as eight
two-bit fields.  Inform does not compile these instructions, and does
not make use of them when coding function calls (because it would be
extremely unportable to lower versions).

Versions 4 and 5: Reliable extra features
-----------------------------------------

We now discuss those important extra features which can more or less be
relied upon to be safely interpreted.  Full discussion of "ideal" behaviour
for interpreters is left to the specification given later.  Roughly
speaking, when in doubt consult the table of opcodes to see if an opcode
is actually used in any existing Infocom game, and if it isn't, don't
rely on your interpreter to perform it.

But we must begin with unfortunate clashes with version 3.  Chief among
these is

  POP

which used simply to throw away the top of the stack.  In version 5 no such
instruction exists (there is less need for it anyway given the new N form
of the CALL opcodes).

Also, the READ opcode (although it has the same basic form,

  READ text_buffer parse_buffer

as before) does a subtly different job: it appends the result of parsing the
text to the parse_buffer, rather than over-writing the parse buffer.  It
also no longer prints any kind of status bar.  (To avoid confusion of the
syntax, Inform calls the version-3 opcode SREAD and the version-5 opcode
AREAD; and its higher-level command READ translates into sensible code for
either.)

And since there is no longer any Z-machine "status bar", the old opcode to
display it (SHOW_SCORE) disappears and in theory becomes illegal.


The RANDOM function now makes the random number generator predictable for
a while if given a negative argument (there was an undocumented #RANDOM
opcode for this under Version 3, according to Mark Howell).


Cutting and pasting bits of parse buffer is a common job for Z-code parsers,
and there are new opcodes to help with shuffling tables around.  One can
also (using APARSE) parse from any string, with any supplied dictionary
table (not necessarily the default one).  This might conceivably be useful. 
One may also ENCRYPT text to Z-machine text format - which might perhaps be
useful for altering the dictionary entries to cope with the player naming
objects (as in the burin in "Spellbreaker", for instance).


A few opcodes have been moved around, irritatingly, and there have been
three casualties.  NOT has moved.  SAVE and RESTORE now appear in the
"extended" set, as a result of which they are no longer branch instructions
(presumably because Infocom did not want to have to cope with branch offsets
being different for extended opcodes), as a result of which they have to
take a new, less convenient syntax:

  SAVE <variable>
  RESTORE <variable>

These put return codes in the variable.  They return 0 if they fail; RESTORE
returns 1 if successful, SAVE returns either 1 or 2.  The ambiguity is
because a successful RESTORE results in execution continuing from
immediately after the SAVE instruction which produced the save game file...
so in order that the program could know whether a restore had just taken
place, or only a save of a game after which normal execution continued,
the return value is altered.

Being in the extended set does give them extra functions but not very useful
ones.  It is possible to imagine saving a "preferred settings" file, for
instance.

(Inform compiles a little code to make SAVE and RESTORE emulate the version
3 opcodes, for portability between versions.  To get at the raw opcodes,
they must be assembled in @ mode.)


Now for the graphics routines.  The simplest of these allows for different
text styles: boldface, underlining and reverse video (e.g. white on black if
text would normally be black on white).  These effects are modelled on the
VT100 (design of terminal) and cannot safely be combined, even though the
codes for them look like bit masks:

  SET_TEXT_STYLE 0     Default: Inform calls this "Roman"
                 1     Reverse video
                 2     Boldface
                 4     Underlined (or italic)

An interpreter providing coloured text may implement these with colour
changes: my own represents bold as blue lettering instead of black on white,
for instance, which is quite pleasant.

Beware of allowing the screen to scroll while in Reverse Video, because on
some interpreters this will result in an entirely-reversed next line, upon
which normal text may then be invisible.

Remember also that some interpreters do not implement "bold face".  A
stone tablet with keywords picked out in bold might be impossible to
decipher to some players.

(There is another option, 8, which forces use of a fixed-spaced font,
used in "Beyond Zork".)


An upper (usually status bar) screen can be split off from the main screen
with:

  SPLIT_WINDOW <n>

creating one which is n lines tall.  There are then two screens, 0 (the
main screen) and 1 (the upper one).  Text output can be switched between
them by

  SET_WINDOW 0       to lower
             1       to upper

The lower window is just a text stream and its cursor position cannot be
set: on the other hand, when it is returned to, the cursor will be where
it was before it was left.

Within the upper window, anyway, the cursor can be moved by

  SET_CURSOR <line> <column>

where (1,1) is the top left hand character.  Printing on the upper window
overlies printing on the lower, and is always done in a fixed-space font,
and does not appear in a printed transcript of the game.


However, before printing to the "status bar" screen, it is essential to
change the printing format - this is the BUFFER_MODE opcode alluded to
earlier.  Before printing, execute

  BUFFER_MODE 0

and when returning to the normal screen,

  BUFFER_MODE 1

Otherwise, the interpreter may continue trying to split lines at word breaks,
and make a horrid mess.  Some interpreters ("Zip", for instance) cope
regardless, but many ports of the InfoTaskForce one do not.


Also, the status bar screen must be tall enough to include all the cursor
positions you want to write to.  If it is not quite tall enough, different
interpreters flounder about in different ways: some will scroll the upper
window, some won't.


A common thing to want to do is to erase areas of screen - especially a
status bar which is being redisplayed.  Opcodes

  ERASE_WINDOW $ffff  - erases whole screen, both windows
  ERASE_LINE          - erases from cursor to end of line   [Achtung!]

are provided for this.  If you are in reverse video mode, they erase to the
reversed colour: a particularly unpleasant effect is achieved by
"SET_TEXT_STYLE 1; ERASE_WINDOW $ffff;".

Unfortunately ERASE_WINDOW (which is intended to erase window n,
or all windows if n=-1) is not fully implemented by some interpreters and
so cannot safely be used except in this drastic way.  (Interestingly,
the Version 4 file "Trinity", for instance, only uses it thus.)

ERASE_LINE is implemented in some interpreters, but does slightly
unpredictable things in reverse video mode, which is a nuisance since it
would otherwise be ideal for blanking out an out-of-date status bar.
However, no existing V4 or V5 game uses this opcode and so it may not
be relied upon.  (It's interesting to note that the Version-5 edition of
"Zork I" - one of the earliest Version 5 files - blanks out lines by looking
up the screen width and printing that many spaces.)


Players can be gratuitously annoyed (under some interpreters, anyway) by the
BEEP opcode.  This is the only remotely portable sound effect.  (Sound
effects in games like "The Lurking Horror" were actually coded by the
interpreter: the sampled noises were not contained in the Z-machine.)


There are new arithmetic opcodes:

  ART_SHIFT x y z        z=x arithmetically shifted y bits
  LOG_SHIFT x y z        z=x logically shifted y bits


Version 5 games effectively have "undo" provided for them, though the
logic is tricky to get right (from a programmer's point of view).  The
two relevant opcodes are SAVE_UNDO and RESTORE_UNDO, which work in exactly
the same way as SAVE and RESTORE except that they save the game internally
to spare memory.  The idea is that if the game is saved before any action,
then the last action can be undone by restoring this memory-saved game.

SAVE_UNDO provides one more return code than SAVE: it returns -1 if the
interpreter is unable to manage internal saves (presumably this was
provided for machines tight on memory).  Now, of course, an interpreter
which knows about SAVE_UNDO enough to return this code probably knows
enough to implement it fully.

In particular, the InfoTaskForce interpreter currently does _not_ provide
this feature (and SAVE_UNDO returns 0).  (Albeit Mark Howell's "Zip"
interpreter does.)  This is probably the biggest feature it lacks.  In any
case, "undo" is such a worthwhile feature and so easy to code that games
probably ought to provide it in hope.



From hereon opcodes become yet worse interpreted:

BUFFER_MODE 0 switches to unbuffered input/output, and 1 to buffered i/o. 
Input and output streams can be set with INPUT_STREAM and OUTPUT_STREAM.

Keyboard reading is yet another function implemented strangely by
interpreters: see details of READ_CHAR in (A6) but take them with a pinch
of caution.  These features - with timers, real-time response, function
key control - will be especially useful for anyone trying to implement,
say, Space Invaders in the Infocom format.


Version 6
---------

The architecture of the Version 6 Z-machine is extremely similar to that
of Version 5.  Addresses of functions and strings are now in quadwords
(i.e. they are at byte addresses divisible by 8).  Also, optionally,
offsets are provided in the header which can be added to function and
static string addresses.  This allows the memory map to stretch yet
further.  ("Shogun", for instance, is about 335K long.)

Pictures and sampled sounds are not stored in the Z-machine itself and it
is simply expected that the interpreter has them to hand.  They were
thus stored in different formats for different machines.

A few opcodes are changed (mostly the character graphics ones) and
many new ones are added: these are documented below.

The graphical features are the most disheartening to interpreter writers,
but most of them seem to be optional.  For instance, the interpreter
can declare itself unable to draw pictures, or to produce sound effects.
It is not impossible to imagine that a fairly portable if primitive
version-6 interpreter could be constructed.

The display is expected to be arranged in pixels.  Coordinates are usually
given in the form (y,x), with (1,1) in the top left.

There is a generalised colour scheme intended to look like the basic IBM
PC colours (which is to say, not very pleasant).

There are eight, instead of two, windows, and they have more elaborate
possibilities.  But essentially they are quite similar to the two in
Version 4.

There may be a mouse, but if so it is not expected to do much beyond move
an arrow around and have one or more buttons.

Similarly, there may be a concept of "menus" - this seems primarily
furnished for Apple Macintoshes.


---------------------------------------------------------------------------
A6. Complete table of opcodes in versions 1 to 6
---------------------------------------------------------------------------


This table might be called a variorum edition of the Z-machine
specification: it contains all 120 or so possible opcodes for every version
of the Z-machine, from 1 to 6 and (taken with the accompanying dictionary)
almost completely documents them and their corresponding Inform assembly
language syntax.

A few opcodes do not in fact occur in any existing files, but they can
be deduced by disassembling Infocom-supplied interpreters.  This table
specifies also which opcodes occur in V1 to V5 files, at least.

As of Release 4a, Inform names all the opcodes, even the version-6 ones.
These names are provided for the benefit of interpreter writers who may
want to assemble test files, and in the hope of providing a common lexicon.
The standard names come initially from Mark Howell's disassembler and have
been added to with some semblance of rationality.  A few are less than
ideal (compare_pobj, for instance, or print_paddr) but these are too deeply
entrenched to be worth changing now.

It must also be stressed that almost all features beyond version 4 are
interpreted by, for instance, the InfoTaskForce interpreter in a fairly
rough way.  Guidance on this may be found in (A4).  The author hopes that
the specification here may encourage those who maintain interpreters to
add those last few opcodes and finish them off.

1. Reading the opcode table
---------------------------

The two columns "St" and "Br" (store and branch) mark whether an
instruction stores a result in a variable, and whether it must provide a
label to jump to, respectively.

The "Opcode" is written

   TYPE:Decimal

where the TYPE is 2OP, 1OP, 0OP, VAR or EXT: two operands, one operand, no
operands, variable number of said, and variable number of said but
occurring in the "extended" set.  The extended set of opcodes are two-byte
opcodes where the first byte is (decimal) 190.

Briefly, single byte opcodes have types as follows:

  0 to 31, 32 to 63, 64 to 95, 96 to 127:  forms of 2OP, the opcode number
                                               being the value mod 32
  128 to 143, 144 to 159, 160 to 175:      forms of 1OP, the opcode number
                                               being the value mod 16
  176 to 191:                              0OP, the opcode number
                                               being the value mod 16
  192 to 223:                              2OP opcodes implemented in the
                                               VAR form, the opcode number
                                               being the value mod 32
  224 to 255:                              VAR, the opcode number
                                               being the value mod 32

The decimal number is the lowest possible decimal opcode value.  The hex
number is the opcode number within each TYPE.

The "V" column gives the version information.  If nothing is specified,
the opcode is as stated from version 1 onwards.  Otherwise, it exists
only from the version quoted onwards.  Before this time, its use is
illegal.  Some opcodes change their meanings and these have more than
one line of specification.  Others become illegal again, and these are
marked [illegal].

In a few cases, the version is given as "3/4" or some such.  The first
number is the version number whose specification the opcode belongs to,
and the second is the earliest version in which the opcode is known
actually to be used.  A dash means that it is never used at all (in
versions 1 to 5 at least: possibly a few of the 5/- opcodes may be used
in version 6).

The table explicitly marks opcodes which remain unused in all six versions
of the Z-machine as "------".  In principle, the interpreter is at liberty
to crash if it finds them, though in practice ignoring them is more polite.

However, the extended set, which could in principle run from $00 to $FF,
stops at $1B: subsequent codes $1C to $FF were never used, even in
version 6.


2. Inform assembly language
---------------------------

An Inform line beginning with an @ is sent direct to the assembler.  The
syntax is as laid out in the tables below.  (Remember that opcodes can only
be used if the version number is right, and note that the more esoteric
opcodes are not recognised by editions of Inform before Release 4a.)

<variable> and <result> must be variables (or "sp", the stack pointer);
<label> a label.  In a branch instruction, the logical effect can be
negated using a tilde ~ before the label name, so for instance

  @je a b ~Different;  ! Jump to Different if a not equal to b

The programmer must specify whether a branch is in the "near" or "far" form,
the default being "near".  A question mark ? before the label (and the tilde,
if there is one) forces it to be far, it otherwise being "near" (which is
cheaper and more likely).

<string> must be literal text in quotation marks "thus" and it is translated
in the usual Inform way.  When "function" is listed, a constant is expected to
be a function address divided by 2 in version-3, or by 4 in versions higher.
Inform assembles these in the right way if you just name a function at the
appropriate point.

Generally speaking any Inform constant term (such as 'a', or #n$beetle)
can be used as an operand but a compound expression (which would obviously
incur extra assembly) cannot.


===========================================================================
Two-operand (long) opcodes
---------------------------------------------------------------------------
   St  Br  Opcode Hex  V  Inform name and syntax
===========================================================================
           ------   0  ------
       *   2OP:1    1     je              a b <label>            
       *   2OP:2    2     jl              a b <label>             
       *   2OP:3    3     jg              a b <label>              
       *   2OP:4    4     dec_chk         <variable> value <label>             
       *   2OP:5    5     inc_chk         <variable> value <label>              
       *   2OP:6    6     compare_pobj    obj1 obj2 <label>
       *   2OP:7    7     test            bitmap flags <label>
   *       2OP:8    8     or              a b <result>              
   *       2OP:9    9     and             a b <result>             
       *   2OP:10   A     test_attr       object attribute <label>
           2OP:11   B     set_attr        object attribute
           2OP:12   C     clear_attr      object attribute
           2OP:13   D     store           <variable> value
           2OP:14   E     insert_obj      object destination
   *       2OP:15   F     loadw           table index <result>
   *       2OP:16  10     loadb           table index <result>
   *       2OP:17  11     get_prop        object property <result>
   *       2OP:18  12     get_prop_addr   object property <result>
   *       2OP:19  13     get_next_prop   object property <result>
   *       2OP:20  14     add             a b <result>
   *       2OP:21  15     sub             a b <result>
   *       2OP:22  16     mul             a b <result>              
   *       2OP:23  17     div             a b <result>              
   *       2OP:24  18     mod             a b <result>              
   *       2OP:25  19  4  call_2s         function arg1 arg2 <result>
           2OP:26  1A  5  call_2n         function arg1 arg2
           2OP:27  1B  5  colour          foreground background
           2OP:28  1C 5/- throw           value stack-frame
           ------  1D  ------
           ------  1E  ------
           ------  1F  ------
===========================================================================
One-operand opcodes
---------------------------------------------------------------------------
   St  Br  Opcode Hex  V  Inform name and syntax
===========================================================================
       *   1OP:128  0     jz              a <label>
   *   *   1OP:129  1     get_sibling     object <result> <label>
   *   *   1OP:130  2     get_child       object <result> <label>
   *       1OP:131  3     get_parent      object <result>
   *       1OP:132  4     get_prop_len    property-address <result>
           1OP:133  5     inc             <variable>
           1OP:134  6     dec             <variable>
           1OP:135  7     print_addr      byte-address-of-string
   *       1OP:136  8  4  call_1s         function arg1 <result>
           1OP:137  9     remove_obj      object
           1OP:138  A     print_obj       object
           1OP:139  B     ret             value
           1OP:140  C     jump            <label>
           1OP:141  D     print_paddr     word-address-of-string
   *       1OP:142  E     load            value <result>
   *       1OP:143  F 1/4 not             value <result>
                       5  call_1n         function arg1
===========================================================================
Zero-operand opcodes
---------------------------------------------------------------------------
   St  Br  Opcode Hex  V  Inform name and syntax
===========================================================================
           0OP:176  0     rtrue
           0OP:177  1     rfalse
           0OP:178  2     print           <string>
           0OP:179  3     print_ret       <string>
           0OP:180  4 1/- nop 
       *   0OP:181  5  1  save            <label>
                       5  [illegal]
       *   0OP:182  6  1  restore         <label>
                       5  [illegal]
           0OP:183  7     restart
           0OP:184  8     retsp
           0OP:185  9  1  pop
   *                   5  catch           <result>
           0OP:186  A     quit
           0OP:187  B     new_line
           0OP:188  C  3  show_score
                       4  [illegal]
       *   0OP:189  D  3  verify
           0OP:190  E  5  [first byte of extended opcode]
       *   0OP:191  F  5  piracy
===========================================================================
Variable-operand opcodes
---------------------------------------------------------------------------
   St  Br  Opcode Hex  V  Inform name and syntax
===========================================================================
   *       VAR:224  0  1  call            function ...args... <result>
                          icall           address <result>
                       4  call_vs         function ...args... <result>
           VAR:225  1     storew          table word value
           VAR:226  2     storeb          table byte value
           VAR:227  3     put_prop        object property value
   *       VAR:228  4  1  sread           text-buffer parse-buffer
                       5  aread           text parse time function
           VAR:229  5     print_char      ascii-value
           VAR:230  6     print_num       value
   *       VAR:231  7     random          range <result>
           VAR:232  8     push            value
   *       VAR:233  9  1  pull            <result>
                      5/- pull            stack <result>
           VAR:234  A  3  split_window    lines
           VAR:235  B  3  set_window      window
   *       VAR:236  C  4  call_vs2        [not properly assembled]
           VAR:237  D  4  erase_window    window
           VAR:238  E 4/- erase_line      value
                       6  erase_line      pixels 
           VAR:239  F  4  set_cursor      line row
                       6  set_cursor      line row window
           VAR:240 10 4/- get_cursor      table
           VAR:241 11  4  set_text_style  style
           VAR:242 12  4  buffer_mode     flag
           VAR:243 13  3  output_stream   number
                       5  output_stream   number table
                       6  output_stream   number table width
           VAR:244 14  3  input_stream    number
           VAR:245 15  4  beep
                      5/3 sound_effect    number effect volume
                          sound_effect    number effect repeats volume
                       6  sound_effect    number effect volume repeats
   *       VAR:246 16  4  read_char       1 time function <result>
   *    *  VAR:247 17  4  scanw           x table len form <result> <label>
   *       1OP:248 18 5/- not             value <result>
           VAR:249 19  5  call_vn         function ...args...
           VAR:250 1A  5  call_vn2        [not properly assembled]
           VAR:251 1B  5  aparse          text parse dictionary flag
           VAR:252 1C  5  encrypt         ascii-text length from coded-text
           VAR:253 1D  5  copy_table      from to size
           VAR:254 1E  5  print_table     ascii-text width height skip
        *  VAR:255 1F  5  check_no_args   argument-number
===========================================================================
Extended opcodes
---------------------------------------------------------------------------
   St  Br  Opcode Hex  V  Inform name and syntax
===========================================================================
   *       EXT:256  0  5  save            table bytes name <result>
   *       EXT:257  1  5  restore         table bytes name <result>
   *       EXT:258  2  5  log_shift       number places <result>
   *       EXT:259  3 5/- art_shift       number places <result>
   *       EXT:260  4  5  set_font        font window <result>
           EXT:261  5  6  draw_picture    picture-number y x
        *  EXT:262  6  6  picture_data    picture-number table <label>
           EXT:263  7  6  erase_picture   picture-number y x
           EXT:264  8  6  set_margins     left right window
   *       EXT:265  9  5  save_undo       <result>
   *       EXT:266  A  5  restore_undo    <result>
           -------  B  ------
           -------  C  ------
           -------  D  ------
           -------  E  ------
           -------  F  ------
           EXT:272 10  6  move_window     window y x
           EXT:273 11  6  window_size     window y x
           EXT:274 12  6  window_style    window flags operation
   *       EXT:275 13  6  get_wind_prop   window property-number <result>
           EXT:276 14  6  scroll_window   window pixels
           EXT:277 15  6  pop_stack       items stack
           EXT:278 16  6  read_mouse      table
           EXT:279 17  6  mouse_window    window
        *  EXT:280 18  6  push_stack      value stack <label>
           EXT:281 19  6  put_wind_prop   window property-number value
           EXT:282 1A  6  print_form      formatted-table
        *  EXT:283 1B  6  make_menu       number table <label>
===========================================================================

Notes: 1. The opcodes 5, 6, 7, 8 in the extended set were very likely in the
V5 specification, and are named in some interpreter sources (though only
very haphazardly implemented) but they do not occur in any existing V5 story
file.

2. The notation "5/3" for "sound_effect" is because this plainly version-5
feature was used also in one solitary Version-3 game, "The Lurking Horror"
(the sound version of which was the last V3 release, in September 1987).
Thus a V3 interpreter may ignore this, but not crash.

3. The opcode 0 (in the 2-operand set, i.e. the actual byte 00) was possibly
intended for setting break-points in debugging.  It was not "nop".


---------------------------------------------------------------------------
A7. Dictionary of opcodes and specifications
---------------------------------------------------------------------------


       "The highest ideal of a translation... is achieved when the
       reader flings it impatiently into the fire, and begins
       patiently to learn the language for himself."

            (Philip Vellacott)


This dictionary is alphabetical and includes entries on every opcode listed
in the table (A6), as well as brief notes on some Inform internal synonyms
which might otherwise be confused with opcodes.  Although concise it
essentially documents correct interpreter behaviour.


add:  Signed 16-bit addition

and:  Bitwise and

aparse:  The parser (strictly speaking, the lexical analyser) from "aread".
    The given text is parsed into the given parse table.  Unlike in version
    3, aread appends to the parse table, not over-writes it.

    If a non-zero dictionary is supplied, it is used (if not, the ordinary
    game dictionary is).  If the flag is set, unrecognised words are not
    listed as zero in the parse table: this is presumably so that if several
    aparses are done in a row, each fills in more slots without wiping those
    filled by the others.

    Parsing a user dictionary is slightly different.  A user dictionary
    should look just like the main one, except that it should have no
    "separator" characters listed (the ones listed in the main one are
    valid instead), and that it need not be alphabetically sorted.  If the
    number of entries is given as -n, then the interpreter reads this as
    "n entries unsorted".  This is very convenient if the table is being
    altered in play: if, for instance, the player is naming things.

aread:  Advanced form of "read".  This behaves just as the standard form
    does (see the "read" command in (8)) if the last two operands are not
    supplied, except that: (i) the status line is not redisplayed, and
    (ii) if the parse buffer supplied is zero, no attempt is made to parse
    the input.

    The parse buffer is appended to, not over-written as in version 3.

    If all four operands are supplied, then every (time) seconds
    while the player is working on her input, the function is called: if it
    returns 1 (true) then the reading process is interrupted.  (The function
    obviously needs to run pretty quickly.)

art_shift:  Does an arithmetic shift of number by the given number of places,
    shifting left (i.e. increasing) if places is positive, right if negative.
    In a right shift, the sign bit is preserved as well as being shifted on
    down.  (The alternative behaviour is log_shift.)

beep:  Beeps in a more or less irksome fashion and possibly flashes the
    display.

buffer_mode:  If set to 1, text output is buffered up so that it can be
    word-wrapped properly.  If set to 0, it isn't.  There is little need for
    this opcode.

call:  The only call instruction in version-3, Inform reads this as call_vs
    in higher versions: it calls the function with 0, 1, 2 or 3 arguments
    as supplied and stores the resulting return value.

call_1n:  Executes function(arg) and throws away result

call_1s:  Stores function(arg)

call_2n:  Executes function(arg1, arg2) and throws away result

call_2s:  Stores function(arg1, arg2)

call_vn:  Like "call", but throws away result

call_vs:  See "call"

call_vn2:  Call with a variable number (from 0 to 7) of arguments, then
    throw away the result.  This (and call_vs2) uniquely have an extra byte
    of opcode types to specify the types of arguments 4 to 7.

call_vs2:  See "call_vn2"

catch:  Opposite to "throw", and occupying the same opcode that "pop" used
    to in versions 3 and 4, but now with a store argument.  "Catch" gives the
    stack frame of the current routine: see "throw" for what to do with it
    subsequently.

check_no_args:  Branches if the given argument-number (1 being the first of
    these) has been provided by the function call to the current routine.
    (Default values would otherwise be difficult to provide in versions 5
    and 6.)

clear_attr:  Make object not have attribute

clear_flag:  A name once used for one of the not-really-present extended v5
    opcodes.

colour:  If coloured text is available, set text to be foreground-against-
    background, where colour numbers are borrowed from the IBM PC:
    2 - black, 3 - red, 4 - green, 5 - yellow, 6 - blue, 7 - magenta, 8 - cyan,
    9 - white: in addition, 0 means keep the current colour setting, 1 means
    use the default and -1 means the colour of the pixel under the mouse arrow

    One of the V5 games, Beyond Zork, uses this (Paul David Doherty reports it
    as used "76 times in 870915 and 870917, 58 times in 871221") and from
    the structure of the table it clearly logically belongs in version 5.

    Text styles such as bold and underline may also be realised with colour
    changes, if this is used.

compare_pobj:  Compare parent objects of the two given: jump if equal

copy_table:  Copies size bytes from the first table to the second.  If the
    second table is given as 0, then it zeroes the bytes in the first table.
    If the length is positive, it copies backwards:

        copy_table $1000 $1001 20

    would push the first 20 bytes forward by one.  However, if the length is
    negative, it copies forwards.  Thus the same operation with -20 would
    result in the byte at $1000 being copied into the 20 following bytes.

dec:  Decrement variable

dec_chk:  Decrement variable, and jump if now equal to value

div:  Signed 16-bit division

draw_picture:  Displays the picture with the given number from the library of
    pictures which the interpreter is expected to have (which is not resident
    in the Z-machine itself).  The Z-machine knows nothing of what picture
    format is being used.  By default, this appears at the current cursor
    position in the current window.  Y and X pixel coordinates from the top
    left can be given instead, though (the top left having coordinates (1,1)).

    Pictures are numbered from 1 and need not be numbered contiguously.

encrypt:  Translates an ASCII word to the internal (z-encoded) text format,
    suitable for dictionary use.  The text begins at "from" in the "ascii-text"
    and is "length" characters long, which should contain the right length
    value _even though_ in fact the interpreter translates the word as far
    as a 0 terminator.  A 6-byte z-encoded string results: this is the
    dictionary resolution in versions 4, 5 and 6 and usually represents
    9 characters of ASCII.

erase_line:  Before version 6: erase the current cursor line in the current
    window.  (This is badly interpreted.)
    In version 6: if the value is 1, do just that: if not, erase the given
    number of pixels across from the cursor (clipped to the window size).

erase_picture:  Like "draw_picture", but wipes the appropriate region to
    the background colour for the given window.

erase_window:  Erases window with given number (to the background colour in
    version-6), or if -1 it unsplits the screen and clears the lot.  The
    cursor moves back to top left.  (In version 6, -2 means clear the whole
    screen but don't unsplit it.)

extended:  This byte (decimal 190) is not really an instruction, but
    indicates that the opcode is "extended": the next byte contains the
    number in the extended set.

get_next_prop:  Gives the number of the next property provided by the
    quoted object.  This may be zero, indicating the end of the property list;
    if called with zero, it gives the first property number present.  (If
    called with the number of a property not present, the Z-machine crashes.)

get_prop:  Read property from object (resulting in the default value if it
    had no such declared property).

get_prop_addr:  Get address of property data for given object's property

get_prop_len:  Get length of property data

get_child:  Get first object contained in given object, branching if there
    are none (i.e., if this is "nothing", or 0).

get_cursor:  Puts the current cursor line and row into the first two bytes
    of the supplied table.  (Warning: badly interpreted, for no very good
    reason.)

get_parent:  Get parent object (this has no "branch if nothing" clause:
    though in fact it's common for room objects under Inform to have
    "nothing" as a parent).

get_sibling:  Get next object in tree, branching if this is "nothing" (i.e. 0)

get_wind_prop:  The eight windows (in version 6) have 16 properties, numbered
    0 to 15, which can be read using this call and (in some cases) written
    using "put_wind_prop".  The 16 properties are:

      0  y coordinate   6   left margin size              12  font number
      1  x coordinate   7   right margin size             13  font height
      2  y size         8   newline interrupt function    14  attributes
      3  x size         9   newline interrupt countdown   15  line count
      4  y cursor       10  highlight mode
      5  x cursor       11  colour data

    These properties are all explained elsewhere except for 8 and 9, about
    "newline interrupts".  If the countdown is set non-zero, it begins to
    count downwards, once per new-line.  When it then hits zero, the
    interrupt function is called.  This is provided so that text can be
    shaped past crinkly margins (e.g., to roll nicely around a picture)
    because the interrupt function can fix the margins at the crucial moment.
    The interrupt function should not attempt to print anything to the same
    window!

icall:  This is an Inform internal name for "call to a function whose address
    is supplied, not its name".  It allows calculated calls; but takes no
    arguments.  It stores the result as "call" does.

inc:  Increment variable

inc_chk:  Increment variable, and jump if now equal to value

input_stream:  Switches the input stream (the source of the player's commands).
    0 is the keyboard, and 1 a command file (the idea is presumably that a
    list of commands produced by output_stream 4 could be fed back in again,
    and it would be nice if interpreters provided this).

insert_obj:  Moves object to destination (it need not be removed from the tree
    first)

je:  Jump if a = b

jg:  Jump if a > b  (note: not a>=b)

"jge":  Inform used to call "jg" this, which was rather confusing, and now it
    is withdrawn.

jl:  Jump if a < b  (note: not a<=b)

"jle":  Inform used to call "jl" this, which was rather confusing, and now it
    is withdrawn.

jump:  Jump (unconditionally) to the given label.  It is safe to jump into a
    different routine but care is advisable.  (The operand to jump is always
    a 2-byte signed offset: not an absolute routine address.)

jz:  Jump if a = 0

load:  Results in the value of the given variable: so load v1 v2 actually
    does "v2 = v1".  This is better done with "store" or "push" as appropriate
    and Inform never uses it in compiled code.

loadb:  Set  table->index = value

loadw:  Set  table-->index = value

log_shift:  Does a logical shift of number by the given number of places,
    shifting left (i.e. increasing) if places is positive, right if negative.
    In a right shift, the sign is zeroed instead of being shifted on.  (The
    alternative behaviour is art_shift.)

lstore:  Inform provides this to force store to take the "long" form, if the
    value concerned has to be a long constant (programmers should not need
    this).

make_menu:  Provided for the benefit of the Apple Macintosh, and who are
    we to object.  Interpreters which don't provide menus are supposed to set
    a bit to say so in the header, but anyway this instruction can simply
    do nothing and not branch if there are no menus (or if there are too many
    already).

    The menu number to be added has to be more than 2 (since 0 is the Apple
    menu, 1 the File menu, 2 the Edit menu).  If the table supplied is 0,
    the menu is removed.  Otherwise it is a table of tables.  Each table is
    an ASCII string: the first item being a menu name, subsequent ones the
    entries.

mod:  Remainder after signed 16-bit division

mouse_window:  Constrain the mouse arrow to sit inside the given window.
    By default it sits in window 1.  Setting to -1 takes all restriction away.
    (The mouse clicks are not reported if the arrow is outside the window
    and interpreters are presumably supposed to hold the arrow there by
    hardware means if possible.)

move_window:  Moves the given window to pixels (y,x): (1,1) being the top
    left.  Nothing actually happens (since windows are entirely notional
    transparencies): but any future plotting happens in the new place.

mul:  Signed 16-bit multiplication

new_line:  Print carriage return

nop:  Probably the official "no operation" instruction.  Ironically,
    since there is hardly ever any point in using it (self-modifying code is
    illegal in the Z-machine since the code is outside the save area)
    interpreters sometimes do not bother to implement it... and crash.
    (In any event, no V1 to V5 datafile actually uses this opcode.)

not:  Bitwise not (i.e., all 16 bits reversed).  Note: in versions 3 and 4
    this was a one-operand instruction (as would be expected) but in versions
    5 and 6 it was pushed into the extended set to make room for "call_1n".
    (Inform knows which to compile to.)
    (Note also that although this opcode seems to belong to V3, it is not
    in fact used until V4.)

or:  Bitwise or

output_stream:  Text can be output to a variety of different "streams",
    possibly simultaneously.  0 does nothing.  +n switches stream n on,
    -n switches it off.  The output streams are: 1 (the screen),
    2 (the game transcript), 3 (memory) and 4 (script of player's commands).
    Thus, one can turn the screen off and print only to the transcript,
    for instance.  "Zip" does now provide 4, which is extremely useful
    in debugging games.  Other interpreters do not.

    Case 3 is more complicated.  Here the syntax is:

        output_stream 3 table

    and the text is printed into the table+2, the first word always holding
    the number of characters printed.  Printing is never buffered in this
    stream, whatever the state of buffer_mode.

    In Version 6, the total number of pixels width is kept in a field in
    the game's header.  Also, the "width" field may optionally be given,
    and the text will then be justified as if it were in the window with
    that number (if width is positive) or a box -width pixels wide (if
    negative).  Then the table will contain not ordinary text but formatted
    text: see "print_form".

    In version 3 (which does not have this opcode) transcripting is caused
    purely by setting the header bit.  In higher versions games do this
    as well anyway, despite using the opcode.

picture_data:  Asks the interpreter for data on the picture with the given
    number.  This is a branch instruction: if the picture number is not valid,
    no branch is made.  Otherwise information is written to the table and a
    branch occurs.

    If the number is zero, the first word of the table is simply written as
    the highest legal picture number.  

    Otherwise, the first word of the table contains the width and the second
    the height.

piracy:  Branches if the game disc is believed to be genuine by the
    interpreter (which is assumed to have some evil way of finding out).
    Earlier editions of this manual suggested this to be an unconditional
    branch instruction... interpreter writers are urged to code it as such,
    and Z-code programmers not to use it at all.

pop:  This exists only in versions 3 and 4, and simply throws away the top of
    the stack.  (The need for it was largely circumvented by the call-and-
    throw-away-result instructions.)  The same opcode was then used for "catch"
    which tends to crash the machine if used naively.

pop_stack:  In Version 6, a "pop" instruction was finally re-invented.  This
    throws the given number of items off the system stack, unless a stack is
    given as a second argument, in which case it pops off that one instead.

print:  Print the quoted (literal) string

print_addr:  Print (Z-encoded) string at given byte address

print_char:  Print ASCII character

print_form:  Prints a formatted table of the kind produced when the output
    stream is 3.  This is an elaborated version of print_table to cope with
    fonts, pixels and other inconveniences.  It is a sequence of lines,
    terminated with a zero word.  Each line is a word containing the number
    of characters, followed by that many bytes which hold the characters
    concerned.

print_num:  Print (signed) number in decimal

print_paddr:  Print (Z-encoded) string at given word (or in versions 4 and
    above, longword) address (the name of this opcode, short for "print
    packed address", is not ideal, but is too entrenched to be worth
    changing).

print_ret:  Print the quoted (literal) string, and print a new-line, and
    then return true (i.e., 1)

print_table:  Prints a rectangle of text on screen spreading right and
    down from the current cursor position, of given width and height, from
    the table of ASCII text given.  (Height is optional and defaults to 1.)
    If a skip value is given, then that many characters of text are skipped
    over in between each line and the next.  So one could make this display,
    for instance, a 2 by 3 region of a giant 40 by 40 character graphics
    map.

pull:  Pulls value off the stack (crashing if it underflows).  In versions
    5 and 6, the stack in question may be specified as a user one.  A user
    stack is just a table of words in the save area somewhere, whose first
    word always holds the number of spare slots on the stack (so the initial
    value is the capacity of the stack).  User stacks are not well interpreted.

push:  Pushes value onto the system stack

push_stack:  Pushes the value onto the user-specified stack, and branches
    if successful.  If the stack was full already, nothing happens and no
    branch is made.

put_prop:  Write value to the given property of the given object (this crashes
    the machine if the object has no such property).  The interpreter stores
    a word or a byte as appropriate.

put_wind_prop:  Writes a window property (see "get_wind_prop").  This should
    only be used when there is no direct command (such as "move_window") to
    use instead, as some such operations may have side-effects.

quit:  Exit the game.  (Any "Are you sure?" question must be asked by
    the game, not the interpreter.)  It is not legal to return from the main
    routine: this must be used.

random:  Takes a random number between 1 and range (supposing range to be
    positive).  Can crash in some interpreters if range is zero (though it
    shouldn't).  Interpreters vary in how to treat a negative number: some
    use it as a seed for the random number generator, but this seems to be
    not quite right.  Instead a value of, say, -50 should result in the
    random numbers produced next being 1, 2, 3, ..., 50 (probably reduced
    mod. whatever range values subsequent calls give) and the generator then
    lapsing back to proper randomness.  A range of 0 ought to reset the
    generator to randomness in the middle of this process.

read:  The two forms of "read" are called "aread" and "sread" by Inform,
    for the sake of clarity (Advanced and Standard read).  "read" is actually
    a high-level Inform command which compiles suitably portable code for
    either version.

read_char:  Reads a single character.  The stream (the first operand) is
    always 1, meaning the keyboard for some reason.  Time and function are
    optional and dealt with as in "aread".  Function keys return special
    values from 129 onwards:

       up  down  left  right  f1 ... f12  keypad 0...9
       menu click  double mouse click  single mouse click

    (Mice only being at play in version 6.)

read_mouse:  The four words in the table are written with the mouse
    y coordinate, x coordinate, button bits (low bits on the right of the
    mouse, rising as one looks left), and a menu word.  In the menu word,
    the upper byte is the menu number (from 1) and the lower byte is the
    item number (from 0).

restore:  See save.  In version 3, the branch is never actually made,
    since either the game has successfully picked up again from where it
    was saved, or it failed to load the save game file.  From version 5
    it can have optional parameters as "save" does, and returns the number
    of bytes loaded if so.  If the restore fails, 0 is returned, but once
    again this necessarily happens since otherwise control is already
    elsewhere.

restore_undo:  Like restore, but restores from the internal RAM saved game
    made by save_undo.  (The optional parameters of restore may not be
    supplied.)

restart:  Restarts the game.  (Any "Are you sure?" question must be asked by
    the game, not the interpreter.) 

ret:  Returns the value given

retsp:  Pops top of stack and returns that.  This is equivalent to "ret sp",
    but is one byte cheaper

rfalse:  Return false (i.e., 0)

rtrue:  Return true (i.e., 1)

save:  On versions 3 and 4, this attempts to save the game (all questions
    about filenames are asked by interpreters) and branches if successful.
    From version 5 it moves to the extended set, as a result of which it is
    no longer a branch instruction, and works in a different way (see the
    explanation in (A4) above).  This returns 0 for failure, 1 for "save
    succeeded" and 2 for "the game is being restored and is resuming
    execution again from here, the point where it was saved".

    The extension also has (optional) parameters, which save a region of
    the save area, whose address and length are in bytes, and provides a
    suggested filename: name is a pointer to an array of ASCII characters
    giving this name (as usual preceded by a byte giving the number of
    characters).

save_undo:  Like save, except that the optional parameters may not be
    specified: it saves the game into a cache of RAM held by the interpreter.
    (This is typically done once per turn, in order to implement "UNDO", so
    it needs to be quick.)  It may also return -1, meaning that the
    interpreter is unable to offer this feature.  (Alas, most interpreters
    do not understand this opcode well enough to be able to confess to being
    unable to act on it.)

scanw:  Is x one of the words in table, which is len words long?  If so,
    return the address where it first occurs and branch.  If not, return 0
    and don't.

    The form is optional (and only used in version 5?): bit 8 is set for
    words, clear for bytes: the rest contains the length of each field in
    the table.  (The first word or byte in each field being the one looked
    at.)  Thus $82 is the default.

scroll_window:  Scrolls the given window by the given number of pixels
    (a negative value scrolls backwards, i.e., down) writing in blank
    (background colour) pixels in the new lines.  This can be done to any
    window and is not related to the "scrolling" attribute of a window
    (which controls text scrolling, a different matter).

set_attr:  Give object attribute

set_cursor:  Move cursor in the current window to (x,y) character position
    (relative to (1,1) in the top left).  (In version 6 the window is supplied
    and need not be the current one.)  Each window remembers its own cursor
    position.  Using this call may result in any buffered text being printed
    out first (if word-wrapping is going on, for instance).

set_flag:  See "clear_flag".

set_font:  The (text) font in the given window is changed.  All windows
    (and this includes both windows in Version 5, contrary to common
    interpreter practice) seem to be expected to start with a non-fixed-space
    font.  Anyway font 0 means "keep current one" (this seems less than
    altogether useful), font 1 means "default", font 3 refers to character
    graphics fonts (in versions 5 and 6) and font 4 means a fixed space font.

    No such opcode exists in versions 3 and 4:  turning on and off the
    fixed space font is done by altering a bit in the header as usual.  This
    remains the best way for interpreters to work even in higher versions.

set_margins:  Sets the margin widths (in pixels) on the left and right
    for the given window which are by default 0.  These are only used by
    windows which have word-wrapping (i.e., buffer_mode 1) and do nothing
    for others.

set_text_style:  Sets printing style: 0 means normal, 1 means inverse video,
    2 means bold, 4 means underline.  (In version 6, 8 means change to a
    fixed-width characters font.)  In principle the interpreter should
    clear flags in the header according to which of these it is unable to
    provide (in practice, few bother, and it doesn't much matter).

set_window:  Moves text output to one of the windows.  0 is the default
    (lower) window and 1 means the upper one.  This only just counts as a
    version-3 instruction: it was used by "Seastalker" on some machines.

    In version 6 this is much more fulsome.  There are 8 windows, 0 to 7,
    which can do almost anything.  In addition, the window number -3
    means "the current window", in this and all the other calls.

show_score:  (In version 3 only)  Display and update the status line now
    (don't wait until the next keyboard input).  Ideally this should not
    crash in version 5, since the v5 release of "Wishbringer" (V23) contains
    this opcode by accident.

sound_effect:  "The Lurking Horror" used this opcode, but no other version-3
    game did: the v5 game "Sherlock" also used its full form.  See "beep", the
    Inform name for the simpler form of this opcode in versions 4 and 5.

    In Version 6, this produces the given sound (1 meaning a high-pitched
    beep, 2 meaning a low one and other values corresponding to noises
    held by the interpreter) at the given volume (1 to 8: -1 being the
    default, loudest value: Mark Howell suggests $34FB causes fade in
    and $3507, fade out) repeated the given number of times (-1 now meaning
    forever).  The "effect" can be: 1 (prepare), 2 (start), 3 (stop), 4
    (finish with).  (Preparation means in effect loading the sample file
    off disc.)

    Version 5 (and 3) is similar but the parameters seem to be less
    sensibly arranged, as shown.

split_window:  Divides the screen into two windows, an upper one (of the
    stated number of lines) which is in effect a big status bar, and a
    lower one (all the rest).  This only just counts as a version-3
    instruction: it was used by "Seastalker" on some machines.

sread:  Standard (version 3) form of "read".  For details, see the "read"
    command's description in section (8).  Note that this automatically
    redisplays the status line before the keyboard is listened to.

store:  Set variable to value

storeb:  I.e., table->byte = value

storew:  I.e., table-->word = value

sub:  Signed 16-bit subtraction

test:  Jump if any of the flags in bitmap are set (i.e. if bitmap & flags ~= 0)

test_array:  See "clear_flag" (usually interpreted to come out
    unconditionally false, though).

test_attr:  Jump if object has attribute

throw:  Opposite of "catch".  This causes the game to behave as if the
    current routine was that whose stack-frame is given (which was found
    using "catch" at the right moment).  Thus the next return to happen
    will return as if from the "caught" routine.  This is useful for getting
    out of large recursive tangles in a hurry, if an error has occurred.
    (This opcode plainly belongs to the V5 specification, but is not actually
    used in any V5 game.)

verify:  Some version-3 interpreters are said not to implement this.  It
    counts a (two byte, unsigned) checksum of the file from $0040 onwards and
    compares this against the value in the game header, branching if correct.

vje:  Internal Inform name for the variable-length form of "je" (for
    compiling conditions such as (a==1 or 2 or 4)).

window_size:  Change size of window in pixels.  (Does not change the current
    display.)

window_style:  Changes the four attributes for a given window.  The bits in
    question are: 1 - word wrapping (if this is off text is clipped to the
    window size instead), 2 - scrolling, 3 - text to be sent to the printer
    (if transcripting is switched on), 4 - text is buffered.

    The operation, by default, is 0.  0 means "set to these settings".  1 means
    "set the bits supplied".  2 means "clear the ones supplied", and 3 means
    "reverse the bits supplied" (i.e. exclusive or).


---------------------------------------------------------------------------
A8. Table of header format through the ages
---------------------------------------------------------------------------


The initial block of 64 bytes in the Z-machine, the "header", is of
particular fascination to Infocom hackers and many tables have been drawn up
of its contents.  The table here steals from its predecessors (I am
particularly indebted to Paul David Doherty) but also fills some gaps to do
with version-6.

Once again "V" refers to the earliest version in which the feature appeared;
"Dyn" is marked if the entry is dynamic, i.e. changes as the game plays;
"Int" if it is written by the interpreter (otherwise it is set in or by the
game file).

Bits in a byte are numbered from 0 ($01) up to 7 ($80).

===========================================================================
 Hex  V  Dyn Int  Contents
===========================================================================
  0   1           Version number (1 to 6)
  1   3           Flags 1:
      3       *     Bit 0    (unused: possibly a flag to indicate byte sex,
                              i.e. LSB-MSB or MSB-LSB in 2-byte words, at
                              a time when two different forms of game file
                              was considered: no such forms ever emerged)
                        1    Status line type: clear for score/moves,
                               set for time in hours/minutes
              *         2    (unused: set in V3?)
              *         3    The legendary "Tandy" bit (see below)
              *         4    The interpreter sets this if it _cannot_
                               produce a status line
              *         5    Interpreter sets if it _can_ split the screen
                               (only "Seastalker" uses this in V3)
              *         6    Interpreter sets if it uses non-fixed-space
                               fonts
                        7    (unused)
      4       *   Flags 1:   Interpreter sets bits to say what it can do:
       4      *     Bit 0    (always set)
       6      *              Colours available?
       4      *         1    (always set)
       6      *              Picture displaying available?
       4      *         2    Boldface available?
       4      *         3    Underlining available?
                             (the only one of these flags any V4/5 games
                             actually ever looked at)
       4      *         4    Fixed-space font available?
       6      *         5    Sound effects available?
                      6,7    (unused)
  2   1           Release number
  4   1           Start of code area (bytes)
  6   1           Main routine address (uniquely, a byte address which
                    points to first byte of code in routine)
  8   1           Dictionary address (bytes)
  A   1           Object table address (bytes)
  C   1           Global variables table address (bytes)
  E   1           Size of save area (bytes)
 10   3   *       Flags 2:
          *         Bit 0    Printer transcripting happens when the game
                               sets this bit
          *             1    The interpreter is forced to use a fixed-space
                               font when the game sets this bit
                               (does not apply in version 6?)
      6   *   *         2    If the interpreter thinks the status line needs
                               redrawing (because, e.g., the player has
                               dragged a menu across it) it sets this bit.
                               The game should notice, redraw the status
                               line and clear the bit itself.
      6                 3    If set, game wants to use pictures
      3                 4    Set in the Amiga version of The Lurking Horror
                               so presumably to do with sound effects
      5                      If set, game wants to use the UNDO opcodes
      6                 5    If set, game wants to use a mouse
      6                 6    If set, game wants to use colours
      6                 7    If set, game wants to use sound effects
      6                 8    If set, game wants to use menus
                               (In each case except bit 6, if the
                               interpreter cannot manage the given feature,
                               it should clear the relevant bit again.)
                        9    (unused)
          *   *        10    Possibly set by interpreter to indicate an error
                               with the printer during transcription
                    11-15    (unused)
 12   2           Serial number (six characters of ASCII, conventionally
                    the compilation date in the form YYMMDD)
 18   2           Synonyms table address (bytes)
 1A   3+          Length of file (in words (V3) or longwords (V4,5,6))
 1C   3+          Checksum of file (sum of bytes from $0040 to length
                    by unsigned 16-bit addition)
 1E   4       *   Interpreter number, identifying the machine as one of:
                    1   DECSystem-20     6   IBM PC
                    2   Apple IIe        7   Commodore 128
                    3   Macintosh        8   Commodore 64
                    4   Amiga            9   Apple IIc
                    5   Atari ST        10   Apple IIgs
                                        11   Tandy Color
                    The latest versions of the portable interpreters I
                    have seen are: InfoTaskForce 2 Version A
                                   Zip           6 Version B
 1F   4       *   Interpreter version (a single ASCII character,
                    conventionally running through capital letters from A)
 20   4       *   Screen height (lines): 255 means "infinite", i.e. never
                    worry about screen overflow and never produce [MORE]
 21   4       *   Screen width (characters)
 22   5   *   *   Leftmost screen coordinate
 23   5   *   *   Rightmost screen coordinate
 24   5   *   *   Highest screen coordinate
 25   5   *   *   Lowest screen coordinate
 26   5   *   *   Width in these coordinate terms of a character in the
                  current font
 27   5   *   *   Similarly, font height
                  (Note: it is perfectly permissible for 22 to 25 to be
                  character grid positions, and the width and height both
                  to be 1: or they could all be in pixels.)
 22   6       *   Screen width in pixels
 24   6       *   Screen height in pixels
 26   6   *   *   Font height in pixels
 27   6   *   *   Font width in pixels (defined as width of a '0')
                  (Note: 22-27 are similar in V6 to V5, with the coordinates
                  now being pixels, but the highest and leftmost slots are
                  dropped (both values being 1) to give room for 2-byte values,
                  i.e. for resolutions of more than 255 pixels.)
 28   6           Functions extra offset (longwords): this may be 0.  It is
                    added to all function addresses and effectively allows
                    the program to exceed the 256K maximum address space
                    by the size of the save area
 2A   6           Static strings extra offset (longwords): similar (needed
                    since static strings come last, after the functions)
 2C   6       *   Default background colour
 2D   6       *   Default foreground colour
 2E   6           Address of terminating characters table (bytes)
 30   6   *   *   Slot used when the output_stream is to memory, to record
                    total width of text in pixels
 32  ---          (these 2 bytes unused in any version)
 34   5           Character set table address (bytes), or 0 if the default
                    character set is to be used
 36   6           Mouse data table address (bytes)
 38   6       *   8 bytes of ASCII: the player's user-name on Infocom's
                    own mainframe, used for debugging purposes and
                    possibly allowing users access to special features.
===========================================================================

(Some early version-3 files do not contain length and checksum data, hence
the mysterious "3+".)

The "Tandy" bit
---------------
Some early Infocom games were sold by the Tandy Corporation, who seem to
have been sensitive souls.  "Zork I" pretends not to have sequels if it
finds this bit set.  And to quote Paul David Doherty:

   In "The Witness", the Tandy Flag can be set while playing the game,
   by typing $DB and then $TA.  If it is set, some of the prose will be
   less offensive. For example, "private dicks" become "private eyes",
   "bastards" are only "idiots", and all references to "slanteyes" and
   "necrophilia" are removed.

We live in an age of censorship.

The character set table
-----------------------
Is 78 bytes long, arranged as 3 blocks of 26 ASCII values for what
characters to print when translating text.  (The first two characters of
block 3 are ignored anyway as they correspond to newline and the literal
escape code.)  This feature is implemented by "Zip" but not the
InfoTaskForce interpreter at the moment, which means that the German
translation of Zork I (which uses the character set for non-English
letters like 'sz') is illegible on it.

The terminating characters table
--------------------------------
Is a zero-terminated list of character codes which cause READ to finish
(other than new-line).  An entry of 255 means that any function key
terminates input.

The mouse data table
--------------------
Seems to have been intended to grow at some future time, because the first
word is the length of it.  But the only data is the second and third words:
the mouse x and y coordinates respectively.  The interpreter writes these
and they alter.


---------------------------------------------------------------------------
A9. A few statistics
---------------------------------------------------------------------------


To give some idea of the sizes found in typical story files, here are a few
statistics, mostly gathered by Paul David Doherty, whose "fact sheet" file
contains many more.

(i) Length:  The shortest files are those dating from the time of the "Zork"
  trilogy, at about 85K; middle-period version 3 games are typically 105K,
  and only the latest use the full memory map.  In versions 4 and 5, only
  "Trinity", "A Mind Forever Voyaging" and "Beyond Zork" (and the author's
  game "Curses") use the full 256K.  "Border Zone" and "Sherlock", for
  instance, are about 180K.

(ii) Code size:  "Zork I" uses only about 5500 opcodes, but the number rises
  steeply with later games; "Hollywood Hijinx" has 10355 and, e.g.
  "Moonmist" has 15900 (both these being version 3).  Against this, "A Mind
  Forever Voyaging" has only 18700, and only "Trinity" and "Beyond Zork"
  reach 32000 or so.  (Inform games are more efficiently compiled and make
  better use of common code - the library - so perform much better here:
  the version 3, release 10 of "Curses" (128K long, and a larger game than
  any Infocom v3 game) has only 6720 opcodes.)

(iii) Objects and rooms:  Obviously, this varies greatly with the style of
  game.  "Zork I" has 110 rooms and 60 takeable objects, but several quite
  complex games have as few as 30 rooms (the mysteries, or "Hitch-hikers"). 
  The average for version-3 games is 69 rooms, 39 takeable objects.

  "A Mind Forever Voyaging" contains many rooms (178) but few objects (30). 
  "Trinity", a more typical style of game, contains 134 rooms and 49
  objects: the version-5 "Curses" has a few more of each.  Of the version-6
  games, only "Zork Zero" scores highly here, with 215 rooms and 106
  objects.  The average for version 4/5 games is 105 rooms and 54 objects.

(iv)  Dictionary:  Early games such as "Zork I" know about 600 words, but
  again this rises steeply to about 1000 even in v3.  Later games know
  1569 ("Beyond Zork") to the record, 2120 ("Trinity").  (This is achieved
  by heroic inclusion of unlikely synonyms: e.g. the Japanese lady with the
  umbrella can be called WOMAN, LADY, CRONE, MADAM, MADAME, MATRON, DAME or
  FACE with any of the adjectives OLD, AGED, ANCIENT, JAP, JAPANESE,
  ORIENTAL or YELLOW.)  V6 games have smaller dictionaries.


---------------------------------------------------------------------------
Appendix B:  The Craft of the Adventure
---------------------------------------------------------------------------


     "Skill without imagination is craftsmanship and gives us
     many useful objects such as wickerwork picnic baskets.
     Imagination without skill gives us modern art."

          (Tom Stoppard, "Artist Descending A Staircase")


Design is both an art and a craft.  Whereas art cannot be taught, only
commented upon, craft at least can be handed down: but the tricks of the
trade do not make an elegant narrative, only a catalogue.  This appendix
contains just such a string of grits of wisdom and half-baked critical
opinions, which may well leave the reader feeling unsatisfied.  One can only
say to such a reader that any book claiming to reveal the secret of how to
paint, or to write novels, or to have ideas, should be recycled at once into
something more genuinely artistic, say a papier-mache sculpture.

If there is any theme here, it is simply that standards count for something.


The author of a text adventure has to be schizophrenic in a way that the
author of a novel does not.  The novel-reader does not suffer as the player
of a game does: she needs only to keep turning the pages, and can be trusted
to do this by herself.  The novelist may worry that the reader is getting
bored and discouraged, but not that she will suddenly find pages 63 to the
end have been glued together just as the plot is getting interesting.

Thus, the game author has continually to worry about how the player is
getting along, whether she is lost, confused, fed up, finding it too tedious
to keep an accurate map: or, on the other hand, whether she is yawning
through a sequence of easy puzzles without much exploration.  Too difficult,
too easy?  Too much choice, too little?

On the other hand, there is also a novel to be written: the player may get
the chapters all out of order, the plot may go awry, but somehow the author
has to rescue the situation and bind up the strings neatly.  Our player
should walk away thinking it was a well-thought out story: in fact, a novel,
and not a child's puzzle-book.

Thus, although this article is about design, it begins with the player's
eye view.


Then, too, an adventure game is a crossword at war with a narrative.  Design
sharply divides into the global - plot, structure, genre - and the local -
puzzles and rooms, orders in which things must be done.  And this article
divides accordingly.


---------------------------------------------------------------------------
B1. A Bill of Player's Rights
---------------------------------------------------------------------------


     "In an early version of Zork, it was possible to be killed by
     the collapse of an unstable room. Due to carelessness with
     scheduling such a collapse, 50,000 pounds of rock might fall on
     your head during a stroll down a forest path. Meteors, no doubt."

          (P. David Lebling, "Zork and the Future of Computerized
          Fantasy Simulations")


  W. H. Auden once observed that poetry makes nothing happen.  Adventure
games are even more futile: it must never be forgotten that they
intentionally annoy the player most of the time.  There's a fine line
between a challenge and a nuisance: and so the designer should think, first
and foremost, like a player, not a programmer or even an author.

  With that in mind, I hold the following rights to be self-evident:


    1.  Not to be killed without warning

  At its most basic level, this means that a room with three exits, two of
which lead to instant death and the third to treasure, is unreasonable
without some hint.  On the subject of which:

    2.  Not to be given horribly unclear hints
 
  Many years ago, I played a game in which going north from a cave led to a
lethal pit.  The hint was: there was a pride of lions carved above the
doorway.  Good hints can be skilfully hidden, or very brief (I think, for
example, the hint in the moving-rocks plain problem in "Spellbreaker" is a
masterpiece) but should not need explaining even after the event.

  Survival is not enough.  Ideally, we would like...

    3.  To be able to win without experience of past lives

  This rule is very hard to abide by.  Here are three examples:

      (i)  There is a nuclear bomb buried under some anonymous
           floor somewhere, which must be disarmed.  The player knows
           where to dig because, last time around, it blew up there.

      (ii) There is a rocket-launcher with a panel of buttons, which looks
           as if it needs to be correctly programmed.  But the player
           can misfire the rocket easily by tampering with the controls
           before finding the manual.

      (iii) (This from "The Lurking Horror".)  Something needs to be cooked
           for the right length of time.  The only way to find the right
           time is by trial and error, but each game allows only one trial.
           On the other hand, common sense suggests a reasonable answer.

  Of these (i) is clearly unfair, most players would agree (ii) is fair
enough and (iii), as tends to happen with real cases, is border-line.

  In principle, then, a good player should be able to play the entire game
out without doing anything illogical, and, in similar vein:

    4.  To be able to win without knowledge of future events

  For example, the game opens near a shop.  You have one coin and can buy a
lamp, a magic carpet or a periscope.  Five minutes later you are transported
away without warning to a submarine, whereupon you need a periscope.  If you
bought the carpet, bad luck.

    5.  Not to have the game closed off without warning

  Closed off meaning that it would become impossible to proceed at some
later date.  If there is a papier-mache wall which you can walk through at
the very beginning of the game, it is extremely annoying to find that a
puzzle at the very end requires it to still be intact, because every one of
your saved games will be useless.  Similarly it is quite common to have a
room which can only be visited once per game.  If there are two different
things to be accomplished there, this should be hinted at.

  In other words, an irrevocable act is only fair if the player is given
due warning that it would be irrevocable.

    6.  Not to need to do unlikely things

  For example, a game which depends on asking a policeman about something he
could not reasonably know about.  (Less extremely, the problem of the
hacker's keys in "The Lurking Horror".)  Another unlikely thing is waiting
in dull places.  If you have a junction at which after five turns an elf
turns up bearing a magic ring, a player may well never spend five
consecutive turns there and will miss what you intended to be easy.  ("Zork
III" is very much a case in point.)  If you want the player to stay
somewhere for a while, put something intriguing there.

    7.  Not to need to do boring things for the sake of it

  In the bad old days many games would make life difficult by putting
objects needed to solve a problem miles away from where the problem was,
despite all logic - say, putting a boat in the middle of a desert.  Or, for
example, a four-discs tower of Hanoi puzzle might entertain.  But not an
eight-discs one.  And the two most hackneyed puzzles - only being able to
carry four items, and fumbling with a rucksack, or having to keep finding
new light sources - can wear a player's patience down very quickly.

    8.  Not to have to type exactly the right verb

  For instance, "looking inside" a box finds nothing, but "searching" it
does.  Or consider the following dialogue (amazingly, from "Sorcerer"):

    >unlock journal
    (with the small key)
    No spell would help with that!

    >open journal
    (with the small key)
    The journal springs open.

This is so misleading as to constitute a bug.  But it's an easy design fault
to fall into.  (Similarly, the wording needed to use the brick in "Zork II"
strikes me as quite unfair.  Or perhaps I missed something obvious.)  Consider
how many ways a player can, for instance, ask to take a coat off:

    remove coat / take coat off / take off coat / disrobe coat
    doff coat/shed coat

(Believe it or not, play-testers have asked me to implement "don" and
"doff".)  Nouns also need...

    9.  To be allowed reasonable synonyms

  In the same room in "Sorcerer" is a "woven wall hanging" which can instead
be called "tapestry" (though not "curtain").  This is not a luxury, it's an
essential.  For instance, in "Trinity" there is a charming statue of a
carefree little boy playing a set of pan pipes.  This can be called the
"charming" or "peter" "statue" "sculpture" "pan" "boy" "pipe" or "pipes".
And objects often have more than 10 nouns attached.

    10.  To have a decent parser

  If only this went without saying.  At the very least it should provide for
taking and dropping multiple objects.  Some suggestions for a decent
specification are given in Appendix B5.


  Since only God stops with ten commandments, here are seven more.  These
are rather more matters of opinion:

    11.  To have reasonable freedom of action

  Being locked up in a long sequence of prisons, with only brief escapes
between them, is not all that entertaining.  After a while the player begins
to feel that the designer has tied him to a chair in order to shout the plot
at him.  This is particularly dangerous for adventure game adaptations of
books (and most players would agree that the Melbourne House adventures
based on "The Lord of the Rings" suffered from this).

    12.  Not to depend much on luck

  Small chance variations add to the fun, but only small ones.  The thief in
"Zork I" seems to me to be just about right in this respect, and similarly
the spinning room in "Zork II".  But a ten-ton weight which fell down and
killed you at a certain point in half of all games is just annoying.

  There is much to be said for varying messages which occur very often (such
as, "You consult your spell book.") in a fairly random way, for variety's
own sake.

    13.  To be able to understand a problem once it is solved

  This may sound odd, but many problems are solved by accident or trial and
error.  A guard-post which can be passed if and only if you are carrying a
spear, for instance, ought to indicate somehow that this is why you're
allowed past.  (The most extreme example must be the notorious Bank of
Zork, of which I've never even understood other people's explanations.)

    14.  Not to be given too many red herrings

  A few red herrings make a game more interesting.  A very nice feature of
"Zork I", "II" and "III" is that they each contain red herrings explained in
the others (in one case, explained in "Sorcerer").  But difficult puzzles
tend to be solved last, and the main technique players use is to look at
their maps and see what's left that they don't understand.  This is
frustrating when there are many insoluble puzzles and useless objects.  So
you can expect players to lose interest if you aren't careful.  My personal
view is that red herrings ought to be clued: for instance, if there is a
useless coconut near the beginning, then perhaps much later an absent-minded
botanist could be found who wandered about dropping them.  The coconut
should at least have some rationale.

  An object is not a red herring merely because it has no game function: a
useless newspaper could quite fairly be found in a library.  But not a
kaleidoscope.

  The very worst game I've played for red herrings is "Sorcerer", which by
my reckoning has 10.

    15.  To have a good reason why something is impossible

  Unless it's also funny, a very contrived reason why something is
impossible just irritates.  (The reason one can't walk on the grass in
"Trinity" is only just funny enough, I think.)

  Moral objections, though, are fair.  For instance, if you are staying in
your best friend's house, where there is a diamond in a display case,
smashing the case and taking the diamond would be physically easy but quite
out of character.  Mr Spock can certainly be disallowed from shooting
Captain Kirk in the back.

    16.  Not to need to be American    (*)

  The diamond maze in "Zork II" being a case in point.  Similarly, it's
polite to allow the player to type English or American spellings or idiom. 
For instance "Trinity" endears itself to English players in that the soccer
ball can be called "football" - soccer is a word almost never used in
England.

    17.  To know how the game is getting on

  In other words, when the end is approaching, or how the plot is
developing.  Once upon a time, score was the only measure of this, but
hopefully not any more.


(*) Several people have politely pointed out to me that my own game
    "Curses" is, shall we say, slightly English.  But then, like any
    good dictator, I prefer drafting constitutions to abiding by them.


---------------------------------------------------------------------------
B2.  A narrative...
---------------------------------------------------------------------------


     "The initial version of the game was designed and
     implemented in about two weeks."

          (P. David Lebling, Marc S. Blank, Timothy A. Anderson,
           "Zork: A Computerized Fantasy Simulation Game")

     "It was started in May of '85 and finished in June '86."

          (Brian Moriarty on "Trinity": which came from earlier
           ideas yet)


1.  Genre and Getting Started
-----------------------------

The days of games which consisted of wandering around doing unrelated things
to get treasures, are long passed, if they ever were.  Even the two originals,
Crowther and Wood's "Adventure" (sometimes called "Colossal Cave") and the
MIT group's "Zork", went to some effort to avoid this.

Their many imitators, in the early years of small computers, often took no
such trouble.  The effect was almost surreal.  One would walk across the
drawbridge of a medieval castle and find a pot plant, a vat of acid, a copy
of Playboy magazine and an electric drill.  There were puzzles without
rhyme or reason.  The player was a characterless magpie always on the
lookout for something cute to do.  The crossword had won without a fight.

"Adventure", one of the most copied and borrowed-from games ever devised,
was in fact very clean in this respect: at its best it had an austere,
Tolkienesque feel, in which magic was scarce, and its atmosphere and
geography was well-judged, especially around the edges of the map:
the outside forests and gullies, the early rubble-strewn caves, the Orange
River Rock room and the rim of the volcano.  Knife-throwing dwarves
would appear from time to time.  But joky town council officers with
clipboards never would.  "Zork" was condensed, less spacious and never
quite so consistent in style: machines with buttons lay side by side with
trolls and vampire bats.  It was a superb implementation, in almost every
respect nicer than "Adventure": yet "Adventure" remains the better game.

By the 1980s better games had settled the point.  Any player dumped in the
middle of one of "The Lurking Horror" (H. P. Lovecraft horror), "Leather
Goddesses of Phobos" (30s racy space opera) or "Ballyhoo" (mournfully
cynical circus mystery) would immediately be able to say which it was.

If there is a moral here, it is that the essential flavour that makes your
game distinctive and yours is genre.  And so the first decision to be made,
when beginning a design, is the style of the game.  Major or minor key,
basically cheerful or nightmarish, or somewhere in between?  Exploration,
romance, mystery, historical reconstruction, adaptation of a book, film
noir, horror?  In the style of Terry Pratchett, Edgar Allen Poe, Thomas
Hardy, Philip K. Dick?  Icelandic, Greek, Chaucerian, Hopi Indian, Aztec,
Australian myth?

A word of warning about adapting books: remember copyright, which has
broader implications than many non-authors realise.  (For instance, fans of
Anne McCaffrey's "dragon" series of novels are allowed to play network games
set on imaginary planets which do not appear in McCaffrey's works, and to
adopt characters of their own invention, but not to use or refer to hers. 
This is a relatively tolerant position on the part of her publishers.)  And
even if no money changes hands, copyright law is enforceable.  The
quotations from games in this article are legal only because brief excerpts
are permitted for critical or review purposes.  Also, be aware that a direct
linear plot is very hard to successfully implement in an adventure game.  It
will be too long (just as a novel is often too large for a film, which is
nearer to a longish short story in scope) and it will involve the central
character making crucial and perhaps unlikely decisions at the right moment.

If the chosen genre isn't fresh and relatively new, then the game had better
be very good.  It's a fateful decision: the only irreversible one.


2.  Research
------------

Design usually begins with, and is periodically interrupted by, research. 
This can be the most entertaining part of the project and is certainly the
most rewarding, not so much because absolute factual accuracy is important
but because it continually sparks off ideas.

Even the original Adventure began as a simulation of a real cave system
(the Mammoth and Flint Ridge caves): one reason for the plausibility of its
underground geography.

A decent town library, for instance, contains thousands of maps of one kind
or another if one knows where to look: deck plans of Napoleonic warships,
small-scale contour maps of mountain passes, city plans of New York and
ancient Thebes, the layout of the U.S. Congress.  There will be photographs
of every conceivable kind of terrain, of most species of animals and plants;
there will be cutaway drawings of a 747 airliner and a domestic fridge;
shelves full of the collected paintings of every great artist from the
Renaissance onwards.  Data is available on the melting point of tungsten,
the distances and spectral types of the nearest two dozen stars, journey
times by rail and road across France.

History crowds with fugitive tales.  A book on the history of trade with
China may, for instance, say:

  A British mission had been briefly imprisoned in the walled city
  during March 1903: when supplies ran low, a Marine officer led a
  diversionary break-out while the others escaped to the Royal Navy
  frigate at anchor, after hiding for two days in an abandoned temple.
  The subsequent diplomatic incident...

Stories have been spun out of less.

Then, too, useful raw materials come to hand.  A book about Tibet may
mention, in passing, the way to make tea with a charcoal-burning samovar. 
So, why not a tea-making puzzle somewhere?  It doesn't matter that there
is as yet no plot to fit it into: if it's in keeping with the genre, it
will fit somewhere.

Research also usefully fills in gaps.  Suppose a fire station is to be
created: what are the rooms?  A garage, a lounge, a room full of uniforms,
yes: but what else?  Here is Stu Galley, on writing the Chandleresque murder
mystery "Witness":

  "Soon my office bookshelf had an old Sears catalogue and a pictorial
  history of advertising (to help me furnish the house and clothe the
  characters), the "Dictionary of American Slang" (to add colour to the
  text) and a 1937 desk encyclopaedia (to weed out anachronisms)."


The peril of research, on the other hand, is that it piles up fact without
end.  It is essential to condense.  Here Brian Moriarty, on research for
"Trinity", which included geological surveys:

  "The first thing I did was sit down and make a map of the Trinity site. It
  was changed about 50 times trying to simplify it and get it down from over
  100 rooms to the 40 or so rooms that now comprise it. It was a lot more
  accurate and very detailed, but a lot of that detail was totally useless."

There is no need to implement ten side-chapels when coding, say, Chartres
cathedral, merely because the real one has ten.


3.  How Plots Start
-------------------

At this point the designer has a few photocopied sheets, some scribbled
ideas and perhaps even a little code - the implementation of a samovar, for
instance - but nothing else.  (There's no harm in sketching details before
having the whole design worked out: painters often do.  Besides, it can be
very disspiriting looking at a huge paper plan of which nothing whatever is
yet programmed.)

It is time for a plot.

Plot begins with the opening message, rather the way an episode of Star Trek
begins before the credits come up.  Write it now.  It ought to be striking
and concise (not an effort to sit through, like the title page of "Beyond
Zork").  By and large Infocom were good at this, and a fine example is Brian
Moriarty's overture to "Trinity":

  Sharp words between the superpowers. Tanks in East Berlin. And now,
  reports the BBC, rumors of a satellite blackout. It's enough to spoil your
  continental breakfast.

  But the world will have to wait. This is the last day of your $599 London
  Getaway Package, and you're determined to soak up as much of that
  authentic English ambience as you can. So you've left the tour bus behind,
  ditched the camera and escaped to Hyde Park for a contemplative stroll
  through the Kensington Gardens.

Already you know: who you are (an unadventurous American tourist, of no
significance in the world); exactly where you are (Kensington Gardens, Hyde
Park, London, England); and what is going on (World War III is about to
break out).  Notice the careful details: mention of the BBC, of continental
breakfasts, of the camera and the tour bus.  More subtly, "Trinity" is a
game which starts as a kind of escapism from a disastrous world out of
control: notice the way the first paragraph is in tense, blunt,
headline-like sentences, whereas the second is much more relaxed.  So a lot
has been achieved by these two opening paragraphs.

The point about telling the player who to be is more subtle than first
appears.  Gender is especially an awkward point.  In some games the player's
character is exactly prescribed: in "Plundered Hearts" you are a particular
girl whisked away by pirates, and have to act in character.  Other games
take the attitude that anyone who turns up can play.  The game assumes
nothing about the player's gender or attitudes.


Anyway, the player knows who he is.  What is he to do?  Even if you don't
want him to know everything yet, he has to have some initial task.

Games vary in how much they reveal at once.  "Trinity", above, is foreboding
but really only tells the player to go for a walk.  "Curses" gives the
player an initial task which is quite easy - look through some attics for a
tourist map of Paris - but the significance of which is only gradually
revealed, in stages, as the game proceeds.  On the other hand, even the best
of "magic realm" type games (such as "Enchanter") tends to begin...

  You, a novice Enchanter with but a few simple spells in your Book,
  must seek out Krill, explore the Castle he has overthrown, and learn
  his secrets.  Only then may his vast evil...


The most common plots boil down to saving the world, by exploring until
eventually you vanquish something ("Lurking Horror" again, for instance) or
collecting some number of objects hidden in awkward places ("Leather
Goddesses" again, say).  The latter can get very hackneyed (find the nine
magic spoons of Zenda to reunite the Kingdom...), so much so that it becomes
a bit of a joke ("Hollywood Hijinx") but still it isn't a bad idea, because
it enables many different problems to be open at once.

A game which involves really fleshed-out characters other than the player
will obviously offer a much larger range of possible plots.

The ultimate aim in working out a plot is to be able to write a one-page
synopsis of what will happen in the full game: and this ought to have a
clear structure.


4.  Size and Density
--------------------

Once upon a time, the sole measure of quality in advertisements for
adventure games was the number of rooms.  Even quite small programs would
have 200 rooms, which meant only minimal room descriptions and simple
puzzles which were scattered thinly over the map.  (The Level 9 game
"Snowball" - perhaps their best, and now perhaps almost lost - cheekily
advertised itself as having 2,000,000 rooms... though of course 1,999,800 of
them were quite similar to each other.)

Nowadays a healthier principle has been adopted: that (barring a few
junctions and corridors) there should be something out of the ordinary about
every room.

One reason for the quality of the Infocom games is that their version 3
format (the smaller one, but used for the majority of their products) has an
absolute ceiling of 255 objects, which needs to cover rooms, objects and
many other things (e.g., compass directions, or the spells in "Enchanter" et
al).  Many "objects" are not portable anyway: walls, tapestries, thrones,
control panels, coal-grinding machines and so on.

As a rule of thumb, four objects to one room is about right: this means
there will be, say, 60 rooms.  Of the remaining 200 objects, one can expect
15-20 to be used up by the game's administration (eg, a "darkness" room, 10
compass directions, a player and so on).  Another 50-75 or so objects may be
portable but the largest number, at least 100, will be furniture.

So an object limit can be a blessing as well as a curse: it forces the
designer to make the game dense.  Rooms are too precious to be wasted.

Similarly, in the version-3 format, there was room for 150K of text at the
most.  This is the equivalent of about a quarter of a modern novel, or
perhaps the analogy is that there are enough bytes to store a very
substantial book of poetry. Roughly, then, one can afford to spend 2K of
text (say, 350 words) in each room - about ten times the level of detail of
the original mainframe Adventure.

So it is wise to begin working out resources early.  If there are only 60
rooms to allocate, how will they be divided up among the stages of the
game?  Is the plan too ambitious, or too meek?


5.  Structure: The Prologue
---------------------------

Just as most Hollywood films are three-act plays (following a convention
abandoned decades ago by the theatre), there is a conventional game
structure.

Most games have a prologue, a middle game and an end game, usually quite
closed off from each other.  Once one of these phases has been left, it
generally cannot be returned to (though there is sometimes a reprise at the
end, or a premonition at the beginning).


The prologue has two vital duties.  Firstly, it has to establish an
atmosphere, and give out a little background information.

The original mainframe Adventure had the above-ground landscape; the fact
that it was there gave a much greater sense of claustrophobia and depth to
the underground bulk of the game.  Similarly, most games begin with
something relatively mundane (the guild-house in "Sorcerer", Kensington
Gardens in "Trinity") or else they include the exotic with dream-sequences
(for instance, "The Lurking Horror").  Seldom is a player dropped in at
the deep end (as "Plundered Hearts", which begins in the middle of a sea
battle).

And the other duty is to attract a player enough to make her carry on
playing.  It's worth imagining that the player is only toying with the game
at this stage, and isn't drawing a map or being at all careful.  If the
prologue is big, the player will quickly get lost and give up.  If it is too
hard, then many players simply won't reach the middle game.

Perhaps eight to ten rooms is the largest a prologue ought to be, and even
then it should have a simple (easily remembered) map layout.  The player can
pick up a few useful items - the traditional bottle, lamp and key, whatever
they may be in this game - and set out on the journey by one means or
another.


6.  The Middle Game
-------------------

The middle game is both the largest and the one which least needs detailed
planning in advance, oddly enough, because it is the one which comes nearest
to being a collection of puzzles.

There may be 50 or so locations in the middle game.  How are they to be
divided up?  Will there be one huge landscape, or will it divide into zones? 
Here, designers often try to impose some coherency by making symmetrical
patterns: areas corresponding to the four winds, or the twelve signs of the
Zodiac, for instance.  Gaining access to these areas, one by one, provides
a sequence of problems and rewards for the player.

Perhaps the fundamental question is: wide or narrow?  How much will be
visible at once?

Some games, such as the original Adventure, are very wide: there are thirty or
so puzzles, all easily available, none leading to each other.  Others, such as
"Spellbreaker", are very narrow: a long sequence of puzzles, each of which
leads only to a chance to solve the next.

A compromise is probably best.  Wide games are not very interesting (and
annoyingly unrewarding since one knows that a problem solved cannot lead to
a whole new landscape), while narrow ones can in a way be easy: if only one
puzzle is available at a time, the player will just concentrate on it, and
will not be held up by trying to use objects which are provided for
different puzzles.

Just as the number of locations can be divided into rough classes at this 
stage, so can the number of (portable) objects.  In most games, there are
a few families of objects: the cubes and scrolls in "Spellbreaker", the
rods and Tarot cards in "Curses" and so on.  These are to be scattered
about the map, of course, and found one by one by a player who will come to
value them highly.  The really important rules of the game to work out at
this stage are those to do with these families of objects.  What are they
for?  Is there a special way to use them?  And these are the first puzzles
to implement.

Most games in the "fantasy" style have some kind of "magic" system, some
way of allowing the player to transform her surroundings in a wholly
unexpected and dramatic way which would not be possible in real life.  There
are two dangers here: firstly, many systems have already been tried - and
naturally a designer wants to find a new one, somehow linked to the objects
of the game and gradually revealed during it.

Secondly, magic is surreal almost by definition and surrealism is dangerous
(unless it is deliberate, something only really attempted once, in "Nord 'n'
Burt Couldn't Make Head Nor Tail Of It").  The marvellous T-Removing Machine
of "Leather Goddesses of Phobos" (which can, for instance, transform a
rabbit to a rabbi) is a stroke of genius but a risky one.  The adventure
game is centred on words and descriptions, but the world it incarnates is
supposed to be solid and real, surely, and not dependent on how it is
described?  To prevent magic from derailing the illusion, it must have a
coherent rationale.  This is perhaps the definition of mystic religion, and
there are plenty around to steal from.


So a first-draft design of the middle game may just consist of a rough
sketch of a map divided into zones, with an idea for some event or meeting
to take place in each, together with some general ideas for objects. 
Slotting actual puzzles in can come later.


7.  The End Game
----------------

Some end games are small ("The Lurking Horror" or "Sorcerer" for instance),
others large (the master game in some implementations of the mainframe
Adventure).  Nonetheless, almost all games have one.

End games serve two purposes.  Firstly they give the player a sense of being
near to success, and can be used to culminate the plot, to reveal the game's
secrets.  This is obvious enough.  But secondly they also serve to stop the
final stage of the game from being too hard.

As a designer, you don't usually want the last step to be too difficult; you
want to give the player the satisfaction of finishing, as a reward for
having got through the game.  (But of course you want to make him work for
it.)  An end game helps, because it narrows the game, so that only a few
rooms and objects are accessible.

In a novelist's last chapter, ends are always tied up (suspiciously neatly
compared with real life).  The characters are all sent off with their fates
worked out and issues which cropped up from time to time are settled.  So
should the end game be.  Looking back, as if you were a winning player,
do you understand why everything that happened did?  Of course, some
questions will forever remain dark.  Who did kill the chauffeur in "The Big
Sleep"?

Most stories have a decisive end.  The old Gothic manor house burns down,
the alien invaders are poisoned, the evil warlord is deposed.  If the end
game lacks such an event, perhaps it is insufficiently final.

Above all, what happens to the player's character, when the adventure ends?

The final message is also an important one to write carefully, and, like the
overture, the coda should be brief.  To quote examples here would only spoil
their games.  But a good rule of thumb, as any film screenplay writer will
testify, seems to be to make the two scenes which open and close the story
"book-ends" for each other: symmetrical and matching.


---------------------------------------------------------------------------
B3.  ...at war with a crossword
---------------------------------------------------------------------------

     Forest sways,
     rocks press heavily,
     roots grip,
     tree-trunk close to tree-trunk.
     Wave upon wave breaks, foaming,
     deepest cavern provides shelter.

          (Goethe, "Faust")


And so from the large to the small.  The layout is sketched out; a rough
synopsis is written down; but none of the action of the game is clear quite
yet.  In short, there are no puzzles.  What are they to be?  How will they
link together?


1.  Puzzles
-----------

Puzzles ought not to be simply a matter of typing one well-chosen line.  The
hallmark of a good game is not to get any points for picking up an easily
available key and unlocking a door with it.  This sort of low-level
achievement - like wearing an overcoat found lying around, for instance -
should not be enough.  A memorable puzzle will need several different ideas 
to solve (the Babel fish dispenser in "The Hitch-hiker's Guide to the
Galaxy", for instance).

My personal rule with puzzles is never to allow one which I can code up in
less than five minutes.

Still, a good game mixes the easy with the hard, especially near the
beginning.  The player should be able to score a few points (not many) on
the very first half-hearted attempt.

There are three big pitfalls in making puzzles:

-- The "Get-X-Use-X" syndrome.  Here, the whole game involves wandering
about picking up bicycle pumps and then looking for a bicycle: picking up
pins and looking for balloons to burst, and so on.  So every puzzle needs
one object.  As soon as it has been used it can be dropped, for it surely
will not be required again.

-- The "What's-The-Verb" syndrome.  So you have your bicycle pump and
bicycle: "use pump" doesn't work, "pump bike" doesn't work... only "inflate
tyre" does.  There are games where this linguistic challenge is most of the
work for the player.  An especially tricky form of this problem is that in
most games "examine", "search" and "look inside" are different actions: it
is easy to code a hidden treasure, say, so that only one of these produces
the treasure.

-- The "In-Joke" syndrome.  In which the player has to play a parody of your
company office, high school class, etc., or finds an entirely inexplicable
object (say, a coat with a mysterious slogan on) which is only there because
your sister has a very funny one like it, or meets endless bizarre
characters modelled on your best friends and enemies.

Then again, a few puzzles will always be in the get-x-use-x style, and that
does no harm: while pursuing tolerance of verbs to extremes leads to
everything being "moved", not "pushed", "pulled", "rotated" and so on: and
what artist has not immortalised his madder friends at one time or another?

Variety in style is very important, but logic is paramount.  Often the
designer begins knowing only as much as that in a given place, the player is
to put out a fire.  How is this to be done?  Will the means be found nearby?
Will the fire have other consequences?  Will there be partial solutions to
the problem, which put the fire out but leave vital equipment damaged?  If
the player takes a long time not solving the problem, will the place burn
down so that the game becomes unwinnable?


2.  Machinery
-------------

In some ways the easiest puzzles to write sensibly are machines, which need
to be manipulated: levers to pull, switches to press, cogs to turn, ropes to
pull.  They do not have to respond to conversation.  They often need tools,
which brings in objects.  They can transform things in a semi-magical way
(coal to diamonds being the cliche) and can plausibly do almost anything if
sufficiently mysterious and strange: time travel, for instance.

They can also connect together different locations with machinery: chains,
swinging arms, chutes may run across the map, and help to glue it together.

A special kind of machine is the kind to be travelled in.  Many Infocom
games have such a vehicle (since the code was already written for it in Zork
I) and cars, tractors, fork-lift trucks, boats, hot-air balloons have all
made appearances.  They need a little care (for instance, not being able to
drive upstairs, or through a narrow crevice) but suggest a whole range of
new puzzles: petrol, ignition keys, a car radio perhaps.  And travelling
in new ways adds to the realism of the landscape, which is no longer a set
of rules about walking.


3.  Keys and Doors
------------------

Almost invariably games close off sections of the map (temporarily) by
putting them behind locked doors, which the player can see and gnash her
teeth over, but cannot yet open.  And almost every variation on this theme
has been tried: coded messages on the door, illusory defences, gate-keepers,
the key being in the lock on the wrong side, and so on.  Still, the usual
thing is simply to find a key in some fairly remote place, bring it to the
door and open it.

If there are people just inside, do they react when the player knocks on the
door, or tries to break it down or ram it?  If not, why not?

In some situations doors should be lockable (and open- and closeable) on
both sides.  This is irritating to implement but adds considerably to the
effect.

In a large game there may be several, perhaps five or six, keys of one kind
or another: it's essential not to make these too similar in appearance. 
Some games have "master keys" which open several different locks in a
building, for instance, or "skeleton keys", or a magic spell to get around
this.


4.  Air, Earth, Fire and Water
------------------------------

The elements all tangle up code but add to the illusion.  Fire has many
useful properties - it makes light, it destroys things, it can cause
explosions and chemical reactions, it cooks food, it softens materials, it
can be passed from one object to another - but in the end it spreads,
whereas code doesn't.  If the player is allowed to carry a naked flame
around (a burning torch, for instance), then suddenly the game needs to know
whether or not each item in the game (a curtain, a pot plant, a book) is
flammable.  Even the classic matchbook of matches can make for grisly
implementation.

As in Robert Redford's film, so in the best game landscaping: a river runs
through it.  But in any room where water is available, players will try
drinking, swimming, washing, diving.  They will try to walk away with the
water.  (This also applies to acid pools, natural oil pits and the like.)

Liquids make poor objects, because they need to be carried in some container
yet can be poured from one to another, and because they are endlessly
divisible.  "Some water" can easily be made into "some water" and "some
water".  If there's more than one liquid in the game, can they be mixed? 
Pouring liquid over something is likely to make a mess of it: yet why should
it be impossible?  And so on.

The compromise solution is usually to have a bottle with a "capacity" of,
say, 5 units of water, which can be refilled in any room where there is
water (there is a flag for this, say), and then 1 unit at a time is drunk,
poured out, etc.  The player who tries to pour water over things is simply
admonished and told not to.

Implementing swimming, or being underwater, is a different order of
difficulty again.  What happens to the objects being held?  Can a player
swim while wearing heavy clothes, or carrying many things?

Moreover, does the player run out of air?  In many games there is some such
puzzle: a room where the air is poor, or open space, or underwater: and a
scuba mask or a space helmet is called for.  One should not kill the player
at once when he enters such a hostile environment unprotected, since he will
probably not have had fair warning.  Some games even implement gases:
helium, explosive hydrogen, laughing gas.

And so to earth.  One of the oldest puzzles around is digging for buried
treasure.  The shovel can be found in just about every traditional-style
game.  Of course in real life one can dig very nearly anywhere outdoors:
there's just little cause to.  Games really can't afford to allow this. It's
quite difficult to think of a persuasive way of breaking the news to the
player, though.

Still, digging in some form makes a good puzzle: it artificially creates a
new location, or a new map connection, or a new container (the hole left
behind).


5.  Animals and Plants
----------------------

Vegetation fits into almost any landscape, and in most games plays some part
in it.  This is good for variety, since by and large one deals with plants
differently from machines and people.  Pulling the undergrowth away from
ruins, for instance, or picking flowers.

A plant which can be watered to make it grow into a beanstalk is now,
perhaps, rather a cliche.  So, of course, naturally no self-respecting
author would write one.

Trees and creeping plants (wistaria or ivy, for instance) ought to be
climbable, even if this does no good.

Animals are even more useful, for several reasons: they move, they behave in
curious and obsessive ways: they have amusingly human characteristics, but
do not generally react to conversation and need not be particularly
surprised by the player doing something very shocking nearby, so they are
relatively easy to code: and they add a splash of colour.  What would the
Garden of Eden have been without turtles, elephants, rabbits, leopards and
guinea pigs?

The classic, rather predictable puzzle with animals is solved by feeding
them some apposite food to make them obedient, then getting them to do
something.  Good games find something better.  (Curiously, the animal
puzzles in "Adventure" - the bear, the bird and the snake - are more
original than most of those in later games.)


6.  People
----------

And so dawns the sixth day of creation: we have the mountains, rivers,
plants and animals, but as yet no people.

The trap with "people" puzzles should perhaps be called the Get-X-Give-X
syndrome.  People are a little more complicated than that.  The nightmare
of coding real characters is illustrated well by one of Dave Lebling's
example bugs from "Suspect":

   > SHOW CORPSE TO MICHAEL
   Michael doesn't appear interested.

   Of course, Michael is only Veronica's husband; why would he be
   interested?

People are the hardest elements of any game to code up.  They can take five
times the amount of code attached to even a complicated room.  They have to:

-- react to events (as above!);

-- make conversation of some kind or another;

-- understand and sometimes obey instructions ("robot, go south");

-- wander around the map in a way consistent with the way the player does;

-- have some attitude to the player, and some personality.

They often have possessions of their own and can expect to be attacked,
have things given to or thrown at them, or even kissed by a desparate
player.  All this requires code.  Good player characters also do surprising
things from time to time, in a random way.  In some games they have a vast
stock of knowledge and replies.  The woman selling bread-crumbs at the very
beginning of "Trinity" (who does not play a huge role in the game) can say
over 50 different things.

Most conversation is added to the code in play-testing.  If the play-testers
complain that "ask waiter about apples" does nothing, then add some reply,
even if not a terribly useful one.

Good player-characters may come and go, turning up at different times during
the game: they are part of the larger plot.  But there is also room for the
humble door-keeper who has nothing to do but check passes.


7.  Mazes...
------------

Almost every game contains a maze.  Nothing nowadays will ever equal the
immortal

  You are in a maze of twisty little passages, all alike.

But now we are all jaded.  A maze should offer some twist which hasn't been
done before (the ones in "Enchanter" and "Sorcerer" being fine examples).

The point is not to make it hard and boring.  The standard maze solution is
to litter the rooms with objects in order to make the rooms distinguishable.
It's easy enough to obstruct this, the thief in "Zork I" being about the
wittiest way of doing so.  But that only makes a maze tediously difficult.

Instead there should be an elegant quick solution: for instance a guide who
needs to be bribed, or fluorescent arrows painted on the floor which can
only be seen in darkness (plus a hint about darkness, of course).

Above all, don't design a maze which appears to be a standard impossibly
hard one: even if it isn't, a player may lose heart and give up rather than
go to the trouble of mapping it.


8.  ...and Other Cliches
------------------------

There are a few games which do not have "light source" puzzles, but it's
hard to think of many.  The two standards reduce to:

-- the player's lamp slowly runs down and will need new oil at least once;

-- a dark room, full of treasure, can apparently only be reached through a
very narrow passage, one which cannot be passed by a player carrying
anything (including the lamp).

Most games contain both, and perhaps most always will, but variations are
welcome.  (There is a superbly clever one in "Zork III", for instance.)


Similarly, unless there are very few portable objects, it becomes ridiculous
that a player can carry hundreds of bulky and fiddly things around all the
time: so most games impose a limit on how much can be carried, by convention
four (because that's what Adventure did).  It is bad form to set puzzles
making life difficult because the limit is four and not five (after all, in
case of emergency, a player could always carry something else).  Of course
the norm is to provide a bag for carrying things.

Sophisticated games also quietly work out the total weight being carried. 
(One of the Infocom games contains a marvellously heavy red herring which
can be carried anywhere, but is terribly exhausting to move.)

Mention of exhaustion raises the question of the player's state of health. 
Some games take a quite role-playing-style view of this, with (perhaps
hidden) attributes of "strength" and "constitution".  The player grows weary
and needs food, tired and needs sleep, wounded and needs recuperation.
A puzzle which really exploits this would be difficult to make fair.


9.  Rewards and Penalties
-------------------------

There are two kinds of reward which need to be given to a player in return
for solving a puzzle.  One is obvious: the game advances a little.  But the
player at the keyboard needs a reward as well, that the game should offer
something new to look at.  In the old days, when a puzzle was solved, the
player simply got a bar of gold and had one less puzzle to solve.

Much better is to offer the player some new rooms and objects to play
with, as this is a real incentive.  If no new rooms are on offer, at least
the "treasure" objects can be made interesting, like the spells in the
"Enchanter" trilogy or the cubes in "Spellbreaker".

In olden days, games killed the player in some way for almost every wrong
guess (or altered the state of the game so that it had become unwinnable).
This was annoying and meant that virtually all players were so paranoid
as to save the game before, say, picking up any new object.  Nowadays
it is thought polite not to kill the player without due warning, and to
make smaller mistakes recoverable-from.  A good alternative to the death
sentence is exile (i.e., in some way moving the player somewhere
inconvenient but returnable-from).


10.  Writing Room Descriptions
------------------------------

First, a warning: it is tempting, when beginning to code, to give rooms
"temporary" descriptions ("Slab room." "Cloister."), and leave the writing
for later.  There is no more depressing point than when facing a pile of 50
room descriptions to write, all at once, and feeling that one's enthusiasm
has altogether gone.  (The same warning applies to making an over-detailed
design before doing any coding.)  Besides, when testing the rooms concerned,
one has no feeling of what the game will look like except tatty, and this
is also depressing.  Also, writing room descriptions forces the author to
think about what the room is ultimately for, which is no bad thing.  So
write a few at a time, as coding goes on, but write them properly: and edit
later if necessary (it will be).

Size doesn't matter.  It is all too easy to write a huge room description,
rambling with irrelevant details: there are usually one to three essentials
to get across, and the rest should be cut.

But even the most tedious junctions deserve description, and description is
more than a list of exits.  Here is "Adventure" at its most graceful:

   You're in a large room carved out of sedimentary rock.  The floor and
   walls are littered with bits of shells embedded in the stone.  A shallow
   passage proceeds downward, and a somewhat steeper one leads up.  A low
   hands and knees passage enters from the south.

   You are walking along a gently sloping north/south passage lined with
   oddly shaped limestone formations.

Note the geology, the slight unevenness of the ground and the variation in
the size of the tunnels.  Even if nothing happens here, these are real
places.

Flippant, joky room descriptions are best avoided if they will be often
revisited.  About once in a game an author can get away with:

   Observation Room
   Calvin Coolidge once described windows as "rectangles of glass."  If so,
   he may have been thinking about the window which fills the western wall
   of this room.  A tiny closet lies to the north.  A sign is posted next to
   the stairs which lead both upwards and downwards.

a characteristic piece of Steve Meretzky from "Leather Goddesses of Phobos",
which demonstrates the lengths one has to go to when faced with a
relentlessly ordinary junction-with-window.  The sentence which the whole
description has been written to avoid is "You can go up, down or north."


Room descriptions are obliged to mention the obvious exits - and it is
certainly poor form to fail to mention one in particular unless there is
good reason - but there are ways to avoid what can be a tiresomely
repetitive business.  For instance,

   Dark Cave
   Little light seeps into this muddy, bone-scattered cave and already
   you long for fresh air.  Strange bubbles, pulsing and shifting as if
   alive, hang upon the rock at crazy, irregular angles.

   Black crabs scuttle about your feet.

   > SOUTH
   The only exit is back out north to the sea-shore.

In other words, the "You can't go that way" message is tailored to each
individual room.

Avoiding repetition is well-nigh impossible, and experienced players will
know all the various formulae by heart: "You're in", "You are in", "This
is", "You have come to" and so forth.  I usually prefer impersonal room
descriptions (not mentioning "you" unless to say something other than the
obvious fact of being present).

As in all writing, vocabulary counts.  If there is a tree, what kind is it,
oak, juniper, hawthorn, ash?  Then, too, don't make all room descriptions
static, and try to invoke more than just sight at times: smell, touch and
sound are powerfully evocative.  Purity and corruption, movement and
stillness, light and dark have obsessed writers through the ages.

Above all, avoid the plainness of:

   You are in the Great Hall.  You can go north to the Minstrel's Gallery,
   east to the fireplace and down to the kitchens.

   There is a sword here.

So much for bad room descriptions.  The following example (which I have not
invented) is something much more dangerous, the mediocre room description:

   Whirlpool Room
   You are in a magnificent cavern with a rushing stream, which cascades
   over a sparkling waterfall into a roaring whirlpool which disappears
   through a hole in the floor.  Passages exit to the south and west.

...seems a decent enough try.  But no novelist would write such sentences. 
Each important noun - "cavern", "stream", "waterfall", "whirlpool" - has its
own adjective - "magnificent", "rushing", "sparkling", "roaring".  The two
"which" clauses in a row are a little unhappy.  "Cascades" is good, but does
a stream cascade "over" a waterfall?  Does a whirlpool itself disappear? 
The "hole in the floor" seems incongruous.  Surely it must be underwater,
indeed deep underwater?

Come to that, the geography could be better used, which would also help to
place the whirlpool within the cave (in the middle? on one edge?).  And why
"Whirlpool Room", which sounds like part of a health club?  As a second
draft, then, following the original:

   Whirlpool Ledge
   The path runs a quarter-circle from south to west around a broken ledge
   of this funnel cavern.  A waterfall drops out of the darkness, catching
   the lamplight as it cascades into the basin.  Sinister, rapid currents
   whip into a roaring whirlpool below.

Even so: there is nothing man-made, nothing alive, no colour and besides
it seems to miss the essential feature of all the mountain water-caves I've
ever been to, so let us add a second paragraph (with a line break, which
is much easier on the eye):

   Blue-green algae hangs in clusters from the old guard-railing, which has
   almost rusted clean through in the frigid, soaking air.

The algae and the guard-rail offer distinct possibilities of a puzzle or
two...  Perhaps there are frogs who could eat the algae; perhaps the player
might find a use for iron oxide, and could scrape rust from the railing. 
(Herbalists probably used to use rust for something, and an encyclopaedia or
a chemistry text book might know.)  Certainly the railing should break if a
rope is tied to it.  Is it safe to dive in?  Does the water have a hypnotic
effect on someone who stares into it?  Is there anything dry which would
become damp if the player brought it through here?  Might there be a second
ledge higher up where the stream falls into the cave?  - And so a location
is made.


11.  The Map
------------

Puzzles and objects are inextricably linked to the map, which means that the
final state of the map only gradually emerges and the author should expect
to have to keep changing it to get it right - rather than to devise an
enormous empty landscape at first and then fill it with material.

Back to atmosphere, then, because throughout it's vital that the map should
be continuous.  The mark of a poor game is a map like:

                            Glacier
                               |
             Dungeon  --  Oriental Room  --  Fire Station
              (fish)       (megaphone)         (tulips)
                               |
                           Cheese Room

in which nothing relates to anything else, so that the game has no overall
geography at all.  Much more believable is something like:

                   Snowy Mountainside
                            \  
                         Carved Tunnel
                               |
                         Oriental Room  -- Jade Passage -- Fire Dragon
                            (buddha)       (bonsai tree)      Room
                               |
                         Blossom Room

The map should reflect some large-scale geography too: the mountainside
should extend across the map in both directions.  If there is a stream
passing through a given location, what happens to it?  And so on.  Maps
of real mountain ranges and real cave systems can be quite helpful when
trying to work out an interesting geography.


A vexed question is just how much land occupies a single location.  Usually
a location represents a "room", perhaps ten yards across at the most. 
Really large underground chambers - the legendary "Hall of Mists" in
Adventure, the barge chamber in "Infidel" - are usually implemented with
several locations, something like:

                 Ballroom NW     ---     Ballroom NE
                     |      \           /    |
                     |       Dance Floor     |
                     |      /           \    |
                 Ballroom SW     ---     Ballroom SE

This does give some impression of space but it can also waste locations in a
quite dull way, unless there are genuinely different things to do at some
of the corners.

On the other hand, sometimes an entire meadow, or valley, might be one
single location, but then its description will have to be written carefully
to make this clear.


In designing a map, it adds to the interest to make a few connections in the
rarer compass directions (NE, NW, SE, SW) to prevent the player from a
feeling that the game has a square grid.  There should also be a few
(possibly long) loops which can be walked around, to prevent endless
retracing of steps and to avoid the appearance of a bus service map,
half a dozen lines with only one exchange.

If the map is very large, or if a good deal of to-and-froing is called for,
there should be some rapid means of moving across it, such as the magic
words in Adventure, or the cubes in "Spellbreaker".  This can be a puzzle
in itself - one that players do not have to solve, but will reward them
if they do.


12.  Looking Back at the Shape
------------------------------

A useful exercise, towards the end of the design stage, is to draw out a
tree (or more accurately a lattice) of all the puzzles in a game.  At the
top is a node representing the start of the game, and then lower nodes
represent solved puzzles.  An arrow is drawn between two puzzles if one has
to be solved before the other can be.  For instance, a simple portion might
look like:

                               Start
                              /     \
                             /       \
                      Find key     Find car
                             \        |
                              \       |
                               Start car
                                   |
                                   |
                             Reach motorway

This is useful because it checks that the game is soluble (for example, if
the ignition key had been kept in a phone box on the motorway, it wouldn't
have been) but also because it shows the overall structure of the game.
Ask:

  Do large parts of the game depend on one difficult puzzle?
  How many steps does a typical problem need?
  How wide is the game at any given time?

Bottlenecks should be avoided unless they are reasonably guessable:
otherwise many players will simply get no further.  Unless, of course,
they are intended for exactly that, to divide an area of the game into
earlier and later.

Just as some puzzles should have more than one solution, some objects should
have more than one purpose.  In bad old games, players automatically threw
away everything as soon as they'd used them.  In better designed games,
obviously useful things (like the crowbar and the gloves in "Lurking
Horror") should be hung on to by the player throughout.

A final word on shape: one of the most annoying things for players is to 
find, at the extreme end of the game (in the master game, perhaps) that
a few otherwise useless objects ought to have been brought along, but that
it is now too late.  The player should not be thinking that the reason for
being stuck on the master game is that something very obscure should have
been done 500 turns before.


---------------------------------------------------------------------------
B4.  Varnish and veneer
---------------------------------------------------------------------------


So you have a game: the wood is rough and splintered, but it's recognisably
a game.  There's still a good month's work to do, though it is easier work
than before and feels more rewarding.

1.  Scoring
-----------

The traditional way to score an adventure game is to give a points score out
of some large and pleasing number (say, 400) and a rank.  There are usually
ten to fifteen ranks.  A genuine example (which shall remain nameless):

  Beginner (0), Amateur Adventurer (40), Novice Adventurer (80), Junior
  Adventurer (160), Adventurer (240), Master (320), Wizard (360),
  Master Adventurer (400)

in which, although ranks correspond to round numbers, still they have
perhaps been rigged to fit the game.  Another amusing touch is that ranks
tend to be named for the player's profession in the game - so, a musician
might begin as "Novice" and rise through "Second Violinist" to "Conductor".
One of the wittiest is in the detective game "Sherlock", where the lowest
rank - the zero-achievement rank - is "Chief Superintendent of Scotland
Yard".

Among the questions to ask are: will every winner of the game necessarily
score exactly 400 out of 400?  (This is very difficult to arrange if even
small acts are scored.)  Will everyone entering the end game already have a
score of 360, and so have earned the title "Wizard"?  Will the rank
"Amateur" correspond exactly to having got out of the prologue and into the
middle game?

So what deserves points?  Clearly solving the major puzzles does.  But do 
the minor, only halfway-there-yet puzzles?  Here, as ever, games vary
greatly.  In "Zork III", the scoring is out of 7 and corresponds to seven
vital puzzles (though a score of 7 does not mean the game is over).  In "The
Lurking Horror", 20 major puzzles are awarded 5 points each, making a
maximum of 100.

Alternatively, there is the complicated approach, typified by the original
Adventure.  Points are awarded in twos and threes for small acts, and then
in larger doses for treasures - silver bars 5, gold amulets 10, platinum
pendants 20.  Treasures are scored twice, once when found, once when removed
to safety - to the trophy case in "Zork I", or inside the packing case of
Level 9's game "Dungeon".  Furthermore, 1 point is awarded for each room
visited for the first time, and 1 for never having saved the game - a
particularly evil trick.

In some games (such as the earliest British game of real quality, "Acheton",
written at Cambridge University in 1979-80 and later implemented on Acorn
microcomputers) score actually falls back when the player is wasting time
and nothing is being achieved: the player's mana gradually fades.  This
annoys some players intensely (no bad thing).

Games used to have a "Last Lousy Point" by custom - a single point which
could only be won by doing something hugely unlikely, such as going to a
particular area of the Pirate's Maze and dropping a key.  This custom,
happily, has fallen into disuse.


2.  Wrong Guesses
-----------------

For some puzzles, a perfectly good alternative solution will occur to
players.  It's good style to code two or more solutions to the same puzzle,
if that doesn't upset the rest of the game.  But even if it does, at least
a game should say something when a good guess is made.  (Trying to cross the
volcano on the magic carpet in "Spellbreaker" is a case in point.)

For example, in "Curses" there are (at time of writing) four different ways
to open the child-proof medicine bottle.  They are all quite hard to guess,
they are all logically reasonable and most players get one of them.


One reason why "Zork" held the player's attention so firmly (and why it took
about ten times the code size, despite being rather smaller than the
original mainframe Adventure) was that it had a huge stock of usually funny
responses to reasonable things which might be tried.

My favourite funny response, which I can't resist reprinting here, is:

   You are falling towards the ground, wind whipping around you.
   >east
   Down seems more likely.                                  ["Spellbreaker"]

(Though I also recommend trying to take the sea serpent in "Zork II".)  This
is a good example because it's exactly the sort of boring rule (can't move
from the midair position) which most designers usually want to code as fast
as possible, and don't write with any imagination.


Another form of wrong guess is in vocabulary.  Unless exceptionally large, a
good game ought to have about a 1000-word vocabulary: too much less than
that and it is probably missing reasonable synonyms; too much more and it is
wasting space and time.  Remember too that players do not know at first what
the relevant and irrelevant objects in a room are.  For instance:

   Old Winery
   This small cavity at the north end of the attic once housed all manner of
   home-made wine paraphernalia, now lost and unlamented.  Steps, provided
   with a good strong banister-rail, lead down and to the west, and the
   banister rail continues along a passage east.

   (and some more follows)

This clearly mentions a banister, which (as it happens) plays no part in the
game, but merely reinforces the idea of an east-west passage including a
staircase which (as it happens) is partly for the use of a frail relative. 
But the player may well try tieing thing to the rail, pulling at it and so
on.  So the game knows "banister", "rail" and (not entirely logically, but
players are not entirely logical) "paraphernalia" as names of irrelevant
things. An attempt to toy with them results in the reply

    That's not something you need to refer to in the course of this game.

which most players appreciate as fair, and is better than the parser either
being ignorant or, worse, pretending not to be.

A feature which some games go to a great deal of trouble to provide, but is
of arguable merit (so think I), is to name every room, so that "search
winery" would be understood (though of course it would do nothing almost
everywhere... and a player would have to try something similar everywhere on
the off chance).  Some games would even provide "go to winery" from nearby
places.  These are impressive features but need to be coded carefully not to
give the player information she may not yet have earned.


3.  Hints and Prizes
--------------------

A good game (unless written for a competition) will often contain a hints
service, as the Infocom games did in latter days.  Most players will only
really badly be stuck about once in the course of a game (and they vary
widely in which puzzle to be really badly stuck on) and it is only fair
to rescue them.  (If nothing else, this cuts down on the volume of email
cries for help which may arrive.)  There are two ways to provide hints:

-- in the game itself, by having some sage old worthy to ask;

-- properly separated from the game, with a "hint" command which offers
one or more menus full of possible questions.

Of course, a hint should not be an explicit answer.


At the end of the game, when it has been won, is there anything else to be 
said?  In some games, there is.  In its final incarnations (alas, not the
one included in the "Lost Treasures of Infocom" package), "Zork I" offered
winners access to the hints system at the RESTART, RESTORE or QUIT prompt. 
"Curses" goes so far as to have a trivia quiz, really to tell the player
about some of the stranger things which can be done in the game.  (If
nothing else, this is a good chance for the game's author to boast.)


4.  User Interface, and all that jazz
-------------------------------------

No, not windows and pull-down menus, but the few meta-commands which go to
the game program and do not represent actions of the player's character in
the game.  Of course,

  SAVE, RESTORE, RESTART, QUIT

are essential.  Games should also provide commands to allow the player to
choose whether room descriptions are abbreviated on second visits or not. 
Other such options might be commands to control whether the game prints out
messages like

  [Your score has just gone up by 10 points.]

and commands to transcribe to the printer or to a file - these are extremely
useful when receiving comments from play-testers.

UNDO is difficult to code but worth it.  In "Curses", UNDO can even restore
the player posthumously (though this is not advertised in the game: death,
where is thy sting?).

Abbreviations (especially "g" for again, "z" for wait, "x" for examine) must
now be considered essential.

Some games produce quotations or jokes from time to time in little windows
away from the main text of the game.  Care is needed to avoid these
overlying vital text.  It ought to possible to turn this feature off.

The author's only innovations in this line are to provide a "full score"
feature, which accounts exactly for where the player's score has come from
and lists achievements so far, and to provide "objects" and "places"
commands:

   >places
   You have visited: Attic and Old Furniture.

   >objects
   Objects you have handled:

   the crumpled piece of paper   (held)
   the electric torch   (held)
   the chocolate biscuit   (held)
   the bird whistle   (in Old Furniture)
   the gift-wrapped parcel   (lost)

These features may or may not catch on.


5.  Debugging and Testing
-------------------------

Every author will need a few "secret" debugging commands (still present in
several of the Infocom games, for instance) to transport the player across
the map, or get any object by remote control.  Since debugging never ends,
it's never wise to remove these commands: instead, protect them with a
password in released editions.

An unobvious but useful feature is a command to make the game non-random.
That is, if there is a doorway which randomly leads to one of three places,
then this command will make it predictable.  This is essential when testing
the game against a transcript.

During design, it's helpful to keep such a script of commands which wins the
game from the start position.  Ideally, your game ought to be able to accept
input from a file of commands as well as from the keyboard, so that this
script can be run automatically through.

This means that when it comes to adding a new feature towards the end, it is
easy to check whether or not it upsets features earlier on.

Bugs are usually easy to fix: they are mostly small oversights.  Very few
take more than five minutes to fix.  Especially common are:

-- slips of punctuation, spelling or grammar (for instance, "a orange");

-- rooms being dark when they ought to be light (this tends not to show if
the player habitually carries a lamp anyway), or not changing their state
of light/darkness when they should, as for instance when a skylight opens or
closes;

-- other object flags having been forgotten, such as a fish not being
flagged as edible;

-- map connections being very slightly out, e.g. west in one direction and
northeast in the other, by accident;

-- something which logically can only happen once, such as a window being
broken, actually being possible more than once, with strange consequences;

-- general messages being unfortunate in particular cases, such as "The ball
bounces on the ground and returns to your hand." in mid-air or while
wading through a ford;

-- small illogicalities: being able to swim with a suit of armour on, or
wave the coat you're wearing, or eat while wearing a gas mask;

-- parser accidents and misnamings.

Do not go into play-testing until the scoring system is worked out and
the game passes the entire transcript of the "winning" solution without
crashing or giving absurd replies.


6.  Playtesting
---------------

The days of play-testing are fun but harrowing.  The first thing to do is to
get a few "friends" and make them play for a while. Look over their
shoulders, scribble furiously on a piece of paper, moan with despair and
frustration, but do not speak.  Force yourself not to explain or defend,
whatever the provocation.  Expect to have abuse heaped on you, and bear up
nobly under the strain.  To quote Dave Lebling (on testing "Suspect", from
the "New Zork Times"):

   > BARTENDER, GIVE ME A DRINK
   "Sorry, I've been hired to mix drinks and that's all."

   > DANCE WITH ALICIA
   Which Alicia do you mean, Alicia or the overcoat?

   Veronica's body is slumped behind the desk, strangled with a lariat.
   > TALK TO VERONICA
   Veronica's body is listening.

   Little bugs, you know?  Things no one would notice.  At this point the
   tester's job is fairly easy.  The story is like a house of cards -- it
   looks pretty solid but the slightest touch collapses it...

After a cleaning-up exercise (and there's still time to rethink and
redraft), give the game to a few brave beta-testers.  Insist on reports in
writing or email, or some concrete form, and if you can persuade the testers
then try to get a series of reports, one at a time, rather than waiting a
month for an epic list of bugs.  Keep in touch to make sure the testers are
not utterly stuck because a puzzle is impossible due to a bug, or due to it
just being far too hard.  Don't give hints unless they are asked for.

Play-testing will produce a good 100 or so bugs, mostly awesomely trivial
and easily fixed.  Still, expect a few catastrophes.

Good play-testers are worth their weight in gold.  They try things in a
systematically perverse way.  To quote Michael Kinyon, whose effect may be
felt almost everywhere in "Curses",

   A tester with a new verb is like a kid with a hammer; every problem
   seems like a nail.

And how else would you know whether "scrape parrot" produced a sensible
reply or not?

Unless there is reason not to (because you know more than they do about how
the plot will work out), listen to what the play-testers say about style and
consistency too.  Be sure also to credit them somewhere in the game.


7.  It's Never Finished
-----------------------

Games are never finished.  There's always one more bug, or one more message
which could be improved, or one more little cute reply to put in.  Debugging
is a creative process and adds to the life of the game.  The first
incarnation of my game "Curses" was finished after about 80K of coding, but
after play-testing rose to 128K long.  In other words, over a third of
a game is devoted to "irrelevant" features, blind alleys, flippant replies
and the like.

Roughly 200 bugs in "Curses" have been spotted since it was released
publically one year ago (I have received well over a thousand email messages
on the subject), and that was after play-testing had been "finished".  About
once a week I make this week's corrections, and about once every three
months I re-issue the mended version.  Thus, many people who suggested
little extensions and repairs have greatly contributed to the game, and
that's why there are so many names in the credits.


8.  Afterword
-------------

An adventure game, curiously, is one of the most satisfying works to have
written: perhaps because one can always polish it a little further, perhaps
because it has so many hidden and secret possibilities, perhaps because
something is made as well as written.  For myself, though, perhaps also
because each day somebody new may wander into its world, as I did when
occasionally taken to a Digital mainframe in the 1970s, through a dark
warren of passages untidier even than my bedroom: so that the glow of the
words has not quite faded from my eyes.


---------------------------------------------------------------------------
B5.  Talking to parsers
---------------------------------------------------------------------------


     "It was easy to drop in new parsers, which happened frequently,
     since everyone and his uncle tried his hand at writing a parser
     (Marc finally became obsessed with it, and wrote the last 40 or
     50 of them himself)."

          (Tim Anderson, "The History of Zork", part 1)  

     "Colourless green ideas sleep furiously."

          (a meaningless but grammatically clear sentence
           devised by Noam Chomsky)


This lengthy dialogue is meant to demonstrate what a player can expect from
a parser, and some of the pitfalls in designing one.

At each stage, lines 2a, 2b, ... etc are alternative inputs. Comments are in
square brackets.  It is taken as read that the parser can cope with words
(such as "plant") being nouns, verbs or prepositions depending on context.


      Parser Demo
      Welcome to the demonstration cave.

      You can see an Elvish-made sword and a Dutch-made sword.

[To begin with, an easy ambiguity.  There may be many other swords
elsewhere, but these should not obstruct the parser.]

      You can see an Elvish-made sword and a Dutch-made sword.

1a.   > take the dutch sword
      Taken.
1b.   > remove a sword
      (the Elvish-made sword)
      Taken.
1c.   > get sword
      Which do you mean, the Elvish-made sword or the Dutch-made sword?

[Suppose you tried 1c.  There are four possible responses: you
don't care which, you want both, you say exactly which, or you give
a command again in full.]

2a.   > either
      (the Elvish-made sword)
      Taken.
2b.   > both
      Elvish-made sword: Taken.
      Dutch-made sword: Taken.
2c.   > elvish
      Taken.
2d.   > pick up the dutch sword
      Taken.

[2a may seem unnecessary - but what if the two objects were
absolutely indistinguishable from each other?  At least this would
allow the player to pick up one of them.]

[Now the player holds the Dutch sword, say, but the Elvish one is on
the floor.  The parser should therefore be able to decide which you
mean when you want to take or drop.]

3a.   > drop sword
      (the Dutch-made sword)
      Dropped.
      > drop the dutch sword
      It is already on the ground.
3b.   > take sword
      (the Elvish-made sword)
      Taken.

[Note that the parser accepts "drop the dutch sword", even when the
Dutch sword is already on the ground, exactly so as to allow the
production of the helpful message.  This shows that requests can be
contextually allowable, even when the parser knows they are illegal.]

      A dwarf comes in and deposits a Roman sword on the floor.

[Next, plurals.  The three swords are now on the floor, suppose, and
so are a Jersey cow, a red herring and a postage stamp.]

4a.   > take all the swords
      Roman sword: Taken.
      Dutch-made sword: Taken.
      Elvish-made sword: Taken.
4b.   > take every sword except the dutch
      Roman sword: Taken.
      Elvish-made sword: Taken.
4c.   > take the roman and dutch swords
      Roman sword: Taken.
      Dutch-made sword: Taken.
4d.   > take all swords but roman, elvish and dutch
      Nothing to do!
4e.   > get everything except the swords and the fish
      Jersey cow: Too large.
      postage stamp: Taken.

[Some verbs ought not to allow multiple objects.]

5a.   > examine everything
      That verb can't take multiple objects.

[Others can be abbreviated.  Common abbreviations are "x" for "examine",
"i" for "inventory", "l" for "look", "z" for "wait", "g" for "again".]

6a.   > x roman sword
      A gladius, or one-handed short sword.

[Words like "it" or "them" ought to refer to the last-mentioned item.]

7a.   > take it
      Taken.

[But beware: this is dangerous if the object is no longer in context.]

8a.   > drop it into chasm
      The Roman sword vanishes into darkness.
      > x it
      The Roman sword is no longer available.

[Also, to some extent "it" should follow the game.  It would be usual to
code the following by removing the sword object and replacing it with an
Eagle one - but what happens to "it"?]

9a.   > wave magic wand at it
      The Roman sword transmogrifies into the Eagle of the Ninth Legion.
      > x it
      The Eagle is the standard of the legion...

[Vagueness: and more on resolving ambiguity.  To begin with, you should
have the opportunity to specify what you want more fully - but only if
it is not obvious:]

10a.  > take
      What do you want to take?
      > the postage stamp
      Taken.
10b.  > drop
      (the Eagle of the Ninth)
      Dropped.

[One can take this dangerously far.  Should the parser be allowed to
implicitly solve a problem for the player?  Suppose you dropped
a sandwich by mistake a while back, and now intend to eat it...]

11a.  > eat
      (the plant root)
      Mmm, the plant root isn't bad, but what strange things are
      happening to your vision...

[The parser should be aware, when resolving ambiguities and handling
plurals, of the distinction between objects being worn and merely being
carried.]

12a.  > inventory
      You're wearing a taffeta dress and carrying a cotton blouse.
      > drop all
      cotton blouse: Dropped.
12b.  > drop
      (the cotton blouse)
      Dropped.
12c.  > drop taffeta
      It's suddenly rather cold in here.

[Similarly, there is a distinction between living and dead objects:]

13a.  > say hello
      (to the dwarf)
      The dwarf grunts with irritation.
      > look
      A dwarf guards a cotton blouse and a postage stamp.
      > take all
      cotton blouse: The dwarf bars you.
      postage stamp: The dwarf bars you.

[Which brings us to conversation.  By convention, the standard format
is:]

14a.  > dwarf, hello
      The dwarf grunts with irritation.
14b.  > dwarf, go east
      The dwarf trundles off east.
14c.  > dwarf, take
      What do you want the dwarf to take?
      > postage stamp
      The dwarf angrily refuses.
14d.  > dwarf, drop everything
      dwarvish shield: The dwarf drops the shield.
      mithril armour: The dwarf refuses.

[Note that in the latter case, context for the dwarf is not the same as
context for the player, and "everything" must be read differently.]

[A particularly nasty, if unlikely case to resolve is:]

15a.  > dwarf, examine
      What do you want the dwarf to examine?
      > dwarf, stamp

[Is the correct idea that the dwarf should look at himself and the
postage stamp?  Or that he should stamp his feet?]

[Another problem with conversation is that the parser should accept
it even when it doesn't make sense in game terms.  After all, you might
really mean this...]

16a.  > dwarf, get your lousy beard out of here
      The dwarf spits.

[A parser may well have to accept arbitrary numbers or words at some
point.  For instance:]

17a.  > write earth on cube
      You write "earth" on the featureless white cube.
17b.  > enter 132
      You type "132" at the keyboard, and the safe opens.

[But care is sometimes needed, unless the parser insists on the player
using double-quotes:]

18a.  > enter safe
      You type "safe" at the keyboard.
18b.  > enter the safe
      You enter the walk-in safe.

[In a complicated command, information should gradually accumulate:]

19a.  > transfer sword
      Which do you mean, the Roman sword or the Dutch-made sword?
      > roman
      What do you want to transfer the Roman sword to?
      > filing
      Which do you mean, the green filing cabinet or the blue filing
      cabinet?
      > blue
      Transferred.

[However if, say, "transfer" is a verb which always takes the
preposition "to" - ie, which must have the form "transfer x to y" - the
parser ought to be able to manage if there's only one container handy:]

20a.  > transfer a sword
      (the Roman sword to the green filing cabinet)
      Transferred.

[The fact that a single verb may have many possible forms (as many as
a dozen, for instance) means that a parser may have to make many
different guesses to resolve ambiguities.  These may clash.  At the
very least, the parser shouldn't ask the player for a ruling more than
once: and if it changes its mind, it should only print up

      (what it inferred you meant)

once, for the pattern which got nearest to acceptance.  Another pitfall
is:]

21a.  The dwarf takes everything away, then returns with the Sword of
      Damocles and the Sword of Alexander.
      > take sword of damocels
      You can't see any such thing.

[This appears obvious.  The trap is that the parser may have recognised
that "sword of" might refer to one of two things, and ask the player which
is intended, and only afterwards reach the inevitable conclusion that the
command doesn't make sense, because "damocels" isn't a preposition which
"take" can have.]

[Containers complicate the issue of context a little.  Consider these
alternative lines:]

22a.  > look
      There are a red apple and two boxes here, a glass box and a steel box:
      both open.
      > i
      You carry a rucksack (which is empty), a torch, a banana and an
      apple.  You are wearing a patterned dress.
      > put everything in the rucksack
      torch: Transferred.
      banana: Transferred.
      green apple: Transferred.
      > empty rucksack into glass
      torch: Transferred.
      banana: Transferred.
      green apple: Transferred.
      > get apple from glass box                (*)
      Taken.
      > drop it in glass box
      Done.
      > close glass
      You close the glass box.
      > x apple
      Which apple do you mean, the red apple or the green apple?
      > green
      The apple is not yet ripe.
      > take it
      But the glass box is closed.
22b.  > drop all except torch into the steel box
      rucksack: Dropped.
      banana: Dropped.
      green apple: Dropped.
      > put dress in steel box
      (taking it off first)
      Done.
      > x dress
      It has pictures of tulips on.
      > close steel box
      You close the steel box.
      > x dress
      You can't see any such thing.

[Note the way no attempt is made to put the rucksack inside itself.
Also, note that in the former line, objects can still be seen (if not
manipulated) because the glass box has transparent walls.  In the
latter, they become invisible when the box closes.

At (*), "get apple" would have been ambiguous.  In most games, so
would "get apple from box", though a really astute parser could deduce
that the box must be the glass one, because the other does not contain
an apple, and that the apple must be the green one, because the red one
isn't in anything.]

[Containment complicates the rules governing darkness considerably -
what happens after...]

22c.  > put torch in steel box
      Done.
      > close steel box
      It is now pitch dark!
      > open steel box

[Is the steel box now in context?  Most parsers would insist that objects
on the floor of a dark room are not in context.  But that punishes the
player rather severely for her mistake, and not very realistically.  On
the other hand...]

23a.  > east
      It's pitch dark in here.
      > get gelignite
      Taken.

[...in circumstances where the gelignite has never been seen before, is
regrettable.]

[To what extent should a parser issue implicit commands on behalf of the
player?  In some cases, this is clearly good practice.  In others, it is
not so clear.  For instance:]

24a.  > drop dress
      (taking off the patterned dress first)
      Dropped.
24b.  > read newspaper
      (taking the copy of the Daily Telegraph)
      "The Prime Minister today proved his brilliant grasp of..."
24c.  > drop newspaper
      (taking the copy of the Daily Telegraph)
      Dropped.
24d.  > examine delicate bomb label
      (taking the delicate bomb)
      The bomb explodes at your first touch!

[The first pair are clearly right, the second pair wrong.  This illustrates
also that the parser cannot handle "implicit taking" and the like in a
naive way: it must use the same game code as if the player had asked
explicitly.  Otherwise, the player could sneakily use, say, "drop chains"
to get the parser to remove her chains, even though the game itself would
not have allowed this.  Similarly, which of these will a player be more
impressed by?]

25a.  > drop all
      newspaper: Dropped.
      delicate bomb: You don't really mean that!
25b.  > drop all
      newspaper: Dropped.
      delicate bomb: The bomb explodes cataclysmically, killing you!

[A degree of customisation also makes for a happier player.  For instance,
in the author's game "Curses", the tedious rule is maintained that a player
can't hold more than five things at once, to which there is the tedious
solution of carrying a rucksack around to hold miscellaneous plunder.  It
becomes very boring to type all the "put x in rucksack" commands by hand, so
the parser infers these:]

25a.  > get red herring
      (putting the cypher into the rucksack to make room)
      Taken.

[But a parser has to know a certain amount to do this sensibly: not to try
putting the rucksack into itself, not to put the light source into the
rucksack, and to try disposing of the item longest ignored.]

["Again" is surprisingly hard to code in a context-sensitive way, but
players want it:]

26a.  > throw herring into chasm
      It disappears into the darkness.
      > again
      I can't see what you're referring to.

[And another is-it-fair? darkness problem...]

27a.  > press switch
      It is now pitch dark in here!
      > again
      I can't see what you're referring to.

[These are at least correct behaviour.  The disaster would be to continue
to allow the player to refer to the herring after it had fallen into the
chasm.  So the obvious solution is simply to parse the player's original
words all over again in the situation as it now is.  But then...]

28a.  > press button
      Which button do you mean, the red button or the blue button?
      > blue
      Click!
      > again
      Click!

[...would not have worked - the question would have been asked all over
again.  So the player's clarifications have to be kept as well.]

[Another tricky bit of coding is for corrections, i.e. "oops".]

29a.  > throw swrod at the dwarf
      You can't see any such thing.
      > oops sword
      The dwarf expires untidily.

[In practice it probably isn't worth coding this in an unduly clever way -
it only needs to work in most easy cases.  Even so it can be difficult to
point to the "obvious" wrong word, when the user's input as failed to
match against many different patterns.]


The conclusion of all this is that:

(i)  a parser is a major part of the game, and implicitly contains many
     of its rules and assumptions;
(ii) while it's obviously desirable to separate it as much as possible
     from the game proper, it must be customised to some degree and so
     cannot be separated altogether.

Thus, although it means very much more work, there is something to be said
for a game-design system which obliges the designer to provide a parser
himself.  Inform adopts the compromise of providing one which is as general
as possible, and held at arm's length, but which can be modified when
needed.


---------------------------------------------------------------------------
C1. A Hello Cruel World program
---------------------------------------------------------------------------


>   !
>   ! A great step backward in interactive fiction...
>   !
>
>   Object hillside "Bare hillside" nothing;
>
>   global place = hillside;
>   global score = 0;
>   global turns = 1;
>   
>   [ Main;
>   
>     print "^^^^^^^^^^^You wake up, shivering to see that Morgoth \
>            the Flatulent Devil is towering over you...^^";
>     Message();
>     print "^^...and he squashes you effortlessly.\
>            ^^   *** You have died ***^^^^^";
>   
>     quit;
>   ];
>   
>   [ Message i;
>
>     print "HELLO CRUEL WORLD^\
>            A Non-Interactive Demonstration^\
>            Copyright (c) 1994 by Graham Nelson. All rights reserved.^\
>            Release ", (0-->1) & $03ff, " / Serial number ";
>   
>     for (i=18 : i<24 : i++) print char 0->i;  new_line;
>   ];
>   

Note that the familiar banner has to be produced by your code.  By
convention, the first word (at bytes 2 and 3) of the file is the release
number, and this is what is set by the RELEASE command.  In this file there
isn't a RELEASE command, so it comes out as 1.  Bytes 18 to 23 contain the
serial number, or in fact the serial string of ASCII characters.  By custom
and tradition, these are the date of compilation arranged YYMMDD, and Inform
sets these automatically.

Note also that Message had to be a separate routine since we needed a local
variable, and Main is not permitted to have local variables of its own.

(The above source has changed a little since the first release: if the
object is not included, then some interpreters (not the InfoTaskForce one)
which voluntarily display the status line (when not asked to do so), get in
a quandary printing a location, time and score.  So for their benefit, here
are all three.)

On my machine (an Acorn Archimedes A5000), compiling with statistics
produces something like:

  *inform -s hellow
  Archimedes Inform 5 (v1259/at)
  Input 31 lines (40 statements, 690 chars)
  Version 3 (Standard) story file
     1 objects (maximum 255)        0 dictionary entries (maximum 750)
     0 attributes (maximum 32)      0 properties (maximum 30)
     0 adjectives (maximum 240)     0 verbs (maximum 110)
     0 actions (maximum 125)        0 abbreviations (maximum 64)
     3 globals (maximum 240)      480 variable space (maximum 1500)
   189 symbols (maximum 4000)       2 routines (maximum 400)
   314 characters of text (compressed to 276 bytes, rate 0.878)
  Output story file is   1.5K long (maximum 128K)
  Essential size 1150 bytes: 129922 remaining
  Completed in 1 seconds.

or, in version-5 mode:

  *inform -sv5 hellow
  Archimedes Inform 5 (v1259/at)
  Input 31 lines (40 statements, 690 chars)
  Version 5 (Advanced) story file
     1 objects (maximum 511)        0 dictionary entries (maximum 750)
     0 attributes (maximum 48)      0 properties (maximum 62)
     0 adjectives (maximum 240)     0 verbs (maximum 110)
     0 actions (maximum 125)        0 abbreviations (maximum 64)
     3 globals (maximum 240)      480 variable space (maximum 1500)
   189 symbols (maximum 4000)       2 routines (maximum 400)
   314 characters of text (compressed to 276 bytes, rate 0.878)
  Output story file is   1.5K long (maximum 256K)
  Essential size 1216 bytes: 260928 remaining
  Completed in 1 seconds.

(The second being mostly consumed in printing out the statistics.  In
practice the compilation time is roughly proportional to the output length,
and typically takes 0.5 seconds per K of story file on my machine.)

The "essential size" is the number of bytes actually used: the story file
is rounded up in size to an exact number of 512-byte blocks. The number
remaining is the actual number of bytes free in the Z-machine.

Note: if you try compiling the example games, and get different
statistics outputs, do not worry; it probably means you're using a later
version of Inform than the one that printed the above.  Similarly,
do not worry if your compiled story file shows differences with the
object code in the archive.  It will certainly have a different serial
number (i.e., date of compilation) and possibly also a different Inform
version number embedded in it.

If the "Toyshop" example (see below) compiles without Inform errors and
plays properly, then Inform is probably working OK.

As an extreme example, statistics for "Curses" look something like:

  Archimedes Inform 5 (v1259/at)
  Input 15708 lines (32501 statements, 644502 chars) from 2 files
  Version 5 (Advanced) story file
   465 objects (maximum 511)     1225 dictionary entries (maximum 1300)
    37 attributes (maximum 48)     30 properties (maximum 62)
    31 adjectives (maximum 240)   121 verbs (maximum 140)
   145 actions (maximum 150)       64 abbreviations (maximum 64)
   132 globals (maximum 240)     1558 variable space (maximum 1600)
  5483 symbols (maximum 6400)     458 routines (maximum 500)
     0 classes (maximum 32)         0 fake actions (maximum 150)
  247654 characters of text (compressed to 156272 bytes, rate 0.631)
  Output story file is 223.5K long (maximum 256K)
  Essential size 228392 bytes: 33752 remaining
  Completed in 98 seconds.


---------------------------------------------------------------------------
C2. "Toyshop": a small toy game
---------------------------------------------------------------------------


The "Hello Cruel World" program is enticingly short and easy, but only
because it doesn't contain a parser.  A fully functioning parser is hard
work to write, and occupies a good deal of "Inform" code.  Besides this,
the everyday mechanics of an adventure game involve more coding than most
designers want to go into, at least at the outset.

"Toyshop" is a five finger exercise with the Library.  It contains a
heap of example objects demonstrating various unusual features, but is
not really a game.  Note, for instance, that:

  In the dark room, shutting the fluorescent ball up in the steel box
makes the room go dark, but in the glass box does not;

  The building blocks (implemented by a class) can be piled three high,
but collapse if four high: higher blocks fall down when lower ones are
taken.  Note the way piles are specially described, and that Chris
can pile them four high, if given the blocks and the right instructions;

  The red car (demonstrating two somewhat exceptional rules about how
"trying to drive a vehicle" and "trying to push something to a different
location" are sorted out) can be driven around, or pushed;

  The padded floor can be looked at in all three main locations;

  The helium balloon drifts about with the wind which blows in from the
high window.

The toys in the shop are rather exotic objects: more ordinary ones are
demonstrated by the "Adventure" example.  (And some of the objects may
give old Inform users a certain feeling of deja-vu.)

Compiling "Toyshop" with statistics should produce something like

  Archimedes Inform 5 (v1259/at)
  Input 4277 lines (8880 statements, 138000 chars) from 4 files
  Version 3 (Standard) story file
    41 objects (maximum 255)      305 dictionary entries (maximum 1300)
    30 attributes (maximum 32)     25 properties (maximum 30)
    19 adjectives (maximum 240)    77 verbs (maximum 140)
    87 actions (maximum 150)        0 abbreviations (maximum 64)
    91 globals (maximum 240)     1249 variable space (maximum 1600)
  1807 symbols (maximum 6400)     184 routines (maximum 500)
     1 classes (maximum 32)         3 fake actions (maximum 150)
  12019 characters of text (compressed to 9168 bytes, rate 0.762)
  Output story file is  26.5K long (maximum 128K)
  Essential size 26886 bytes: 104186 remaining
  Completed in 22 seconds.

("Toyshop" is only a little over 500 lines long: the rest is the
library.)
  
Again, don't worry if the details are slightly different.
  

---------------------------------------------------------------------------
C3.  "Adventure": a port of Colossal Cave
---------------------------------------------------------------------------


       "You are in a maze of twisty little passages, all alike."


As a more substantial example, try compiling "Adventure", a port of
the original Crowther and Woods adventure, taken from David M. Baggett's
excellent TADS version (the most faithful reconstruction of the original
available on the Internet, as far as the author can find).

The source code demonstrates a noticeably different feature of Inform 5
over Inform 4 - there are hardly any routines: almost all the source code
is definitions of objects.

The magic words are nice examples of user-defined actions; the dwarves
and the cave-closing mechanism are quite elegantly defined as daemons.
Otherwise most of the code is fairly plain and straight-forward.

Statistics should look something like:


  Archimedes Inform 5 (v1259/at)
  Input 7438 lines (13004 statements, 254985 chars) from 4 files
  Version 5 (Advanced) story file
   259 objects (maximum 511)      663 dictionary entries (maximum 1300)
    32 attributes (maximum 48)     26 properties (maximum 62)
    18 adjectives (maximum 240)    97 verbs (maximum 140)
   107 actions (maximum 150)        0 abbreviations (maximum 64)
   100 globals (maximum 240)     1249 variable space (maximum 1600)
  2556 symbols (maximum 6400)     299 routines (maximum 500)
     5 classes (maximum 32)         3 fake actions (maximum 150)
  56529 characters of text (compressed to 41216 bytes, rate 0.729)
  Output story file is  74K long (maximum 256K)
  Essential size 75324 bytes: 186820 remaining
  Completed in 44 seconds.


---------------------------------------------------------------------------
C4.  A shell game to build on
---------------------------------------------------------------------------


       "Give the public not what they want but what they ought
        to want and dont."

                (George Bernard Shaw on government)


The shell below is the minimum you need to write to use the library
routines.  Note that the order in which things occur is quite important.
Nothing should appear above the #include "Parser" line except possibly
more defined constants and any abbreviations.  The grammar table should
be last.

>   !
>   ! Shell of a game
>   !
>   
>   Constant Story "SHELL";
>   Constant Headline "^An Interactive Skeleton^\
>                Copyright (c) 1993 by (your name here).^";
>   
>   #include "Parser";
>   #include "VerbLib";
>   
>   Object room "Blank Room" nothing
>     with longdesc "An empty room."
>     has  light;
>   
>   [ Initialise;
>     location=room;
>     print "^^^^^Welcome to the shell...^^";
>   ];
>   
>   #include "Grammar";
>   end;



---------------------------------------------------------------------------
(c) Graham Nelson,            gan10@uk.ac.cam.phx  or  phx.cam.ac.uk
    Magdalen College,         nelson@uk.ac.ox.vax  or  vax.ox.ac.uk
    Oxford OX1 4AU,
    UK.                       18th April 1993
                              and 16th May 1993
                              and 14th November 1993
                              and 20th January 1994
                              and 11th June 1994
---------------------------------------------------------------------------
