home *** CD-ROM | disk | FTP | other *** search
Text File | 1994-10-02 | 291.9 KB | 7,462 lines |
- % TeX source for the Inform Designer's Manual
- % ===========================================
-
- % TeX is a fairly readable mark-up language, but if you
- % can't run it, try the PostScript file or in the last
- % resort the approximate plain-text facsimile.
- % Note that up-arrow signifies "make index entry".
-
- \newif\iffiles\filesfalse
- %
- % Manual macros
- %
- % Page layout
- %
- \newif\ifshutup\shutupfalse
- \magnification=\magstep 1
- \hoffset=0.15 true in
- \voffset=2\baselineskip
- %
- % General hacks
- %
- \def\PAR{\par}
- %
- % Font loading
- %
- \font\medfont=cmr10 scaled \magstep2
- \font\bigfont=cmr10 scaled \magstep3
- %\def\sectfont{\bf}
- \font\sectfont=cmbx12
- \def\small{\sevenrm}
- \font\rhrm=cmr8
- \font\rhit=cmsl8
- %
- % Titles
- %
- \newcount\subsectno % Subsection number
- \def\rhead{} % The running head will go here
- %
- \def\newsection#1#2{% To begin a section...
- %\global\titletrue% Declare this as a title page
- \xdef\rhead{{\rhrm #1}\quad #2}% Initialise running head and ssn
- \subsectno=0%
- \iffiles
- \write\conts{\string\sli\string{#1\string}\string{#2\string}\string{\the\pageno\string}}%
- \fi
- }
- %
- \def\section#1#2{\vskip 1 true in\goodbreak\newsection{#1}{#2}
- \noindent{\sectfont #1\quad #2}\bigskip\noindent}
- %
- % Headers and footers
- %
- \newif\iftitle
- \headline={\iftitle\hfil\global\titlefalse%
- \else{\hfil{\rhit \rhead}}%
- \fi}
- \footline={\ifnum\pageno<0\hfil{\tenbf\romannumeral -\pageno}%
- \else\hfil{\tenbf \number\pageno}\fi}
- %\footline={\ifnum\pageno=1\hfil\else\hfil{\tenbf \number\pageno}\fi}
- %
- % (Old date-stamping version:)
- % \footline={\hfil{\rm \number\pageno}\hfil{\rm \number\day/\number\month}}
- %
- % If this works I'll be impressed
- %
-
- \font\ninerm=cmr9
- \font\ninei=cmmi9
- \font\ninesy=cmsy9
- \font\ninebf=cmbx9
- \font\eightbf=cmbx8
- \font\ninett=cmtt9
- \font\nineit=cmti9
- \font\ninesl=cmsl9
- \def\ninepoint{\def\rm{\fam0\ninerm}%
- \textfont0=\ninerm
- \textfont1=\ninei
- \textfont2=\ninesy
- \textfont3=\tenex
- \textfont\itfam=\nineit \def\it{\fam\itfam\nineit}%
- \textfont\slfam=\ninesl \def\sl{\fam\slfam\ninesl}%
- \textfont\ttfam=\ninett \def\tt{\fam\ttfam\ninett}%
- \textfont\bffam=\ninebf
- \normalbaselineskip=11pt
- \setbox\strutbox=\hbox{\vrule height8pt depth3pt width0pt}%
- \normalbaselines\rm}
-
- \def\tenpoint{\def\rm{\fam0\tenrm}%
- \textfont0=\tenrm
- \textfont1=\teni
- \textfont2=\tensy
- \textfont3=\tenex
- \textfont\itfam=\tenit \def\it{\fam\itfam\tenit}%
- \textfont\slfam=\tensl \def\sl{\fam\slfam\tensl}%
- \textfont\ttfam=\tentt \def\tt{\fam\ttfam\tentt}%
- \textfont\bffam=\tenbf
- \normalbaselineskip=12pt
- \setbox\strutbox=\hbox{\vrule height8.5pt depth3.5pt width0pt}%
- \normalbaselines\rm}
-
- \parindent=30pt
- \def\inpar{\hangindent40pt\hangafter1\qquad}
- \def\onpar{\par\hangindent40pt\hangafter0}
-
- \newskip\ttglue
- \ttglue=.5em plus.25em minus.15em
-
- \def\orsign{$\mid\mid$}
-
- \outer\def\begindisplay{\obeylines\startdisplay}
- {\obeylines\gdef\startdisplay#1
- {\catcode`\^^M=5$$#1\halign\bgroup\indent##\hfil&&\qquad##\hfil\cr}}
- \outer\def\enddisplay{\crcr\egroup$$}
-
- \chardef\other=12
-
- \def\ttverbatim{\begingroup \catcode`\\=\other \catcode`\{=\other
- \catcode`\}=\other \catcode`\$=\other \catcode`\&=\other
- \catcode`\#=\other \catcode`\%=\other \catcode`\~=\other
- \catcode`\_=\other \catcode`\^=\other
- \obeyspaces \obeylines \tt}
- {\obeyspaces\gdef {\ }}
-
- \outer\def\beginstt{$$\let\par=\endgraf \ttverbatim\ninett \parskip=0pt
- \catcode`\|=0 \rightskip=-5pc \ttfinish}
- \outer\def\begintt{$$\let\par=\endgraf \ttverbatim \parskip=0pt
- \catcode`\|=0 \rightskip=-5pc \ttfinish}
- {\catcode`\|=0 |catcode`|\=\other
- |obeylines
- |gdef|ttfinish#1^^M#2\endtt{#1|vbox{#2}|endgroup$$}}
-
- \catcode`\|=\active
- {\obeylines\gdef|{\ttverbatim\spaceskip=\ttglue\let^^M=\ \let|=\endgroup}}
-
- \def\beginlines{\par\begingroup\nobreak\medskip\parindent=0pt
- \nobreak\ninepoint \obeylines \everypar{\strut}}
- \def\endlines{\endgroup\medbreak\noindent}
-
- \def\<#1>{\leavevmode\hbox{$\langle$#1\/$\rangle$}}
-
- \def\dbend{{$\triangle$}}
- \def\d@nger{\medbreak\begingroup\clubpenalty=10000
- \def\par{\endgraf\endgroup\medbreak} \noindent\hang\hangafter=-2
- \hbox to0pt{\hskip-\hangindent\dbend\hfill}\ninepoint}
- \outer\def\danger{\d@nger}
- \def\dd@nger{\medskip\begingroup\clubpenalty=10000
- \def\par{\endgraf\endgroup\medbreak} \noindent\hang\hangafter=-2
- \hbox to0pt{\hskip-\hangindent\dbend\kern 1pt\dbend\hfill}\ninepoint}
- \outer\def\ddanger{\dd@nger}
- \def\enddanger{\endgraf\endsubgroup}
-
- \def\cstok#1{\leavevmode\thinspace\hbox{\vrule\vtop{\vbox{\hrule\kern1pt
- \hbox{\vphantom{\tt/}\thinspace{\tt#1}\thinspace}}
- \kern1pt\hrule}\vrule}\thinspace}
-
- \newcount\exno
- \exno=0
-
- \def\xd@nger{%
- \begingroup\def\par{\endgraf\endgroup\medbreak}\ninepoint}
-
- \outer\def\warning{\medbreak
- \noindent\llap{$\bullet$\rm\kern.15em}%
- {\ninebf WARNING}\par\nobreak\noindent}
- \outer\def\exercise{\medbreak \global\advance\exno by 1
- \noindent\llap{$\bullet$\rm\kern.15em}%
- {\ninebf EXERCISE \bf\the\exno}\par\nobreak\noindent}
- \def\dexercise#1{\global\advance\exno by 1
- \medbreak\noindent\llap{$\bullet$\rm\kern.15em}%
- #1{\eightbf ~EXERCISE \bf\the\exno}\hfil\break}
- \outer\def\dangerexercise{\xd@nger \dexercise{\dbend}}
- \outer\def\ddangerexercise{\xd@nger \dexercise{\dbend\dbend}}
-
-
- \newwrite\ans%
- \newwrite\conts%
-
- \iffiles\else\outer\def\answer#1{\par\medbreak}\shutuptrue\fi
-
- \newwrite\inx
- \ifshutup\else
- \immediate\openout\inx=$.games.infocom.ftp.toolkit.mandir.inxdata
- \fi
- \def\marginstyle{\sevenrm %
- \vrule height6pt depth2pt width0pt } %
-
- \newif\ifsilent
- \def\specialhat{\ifmmode\def\next{^}\else\let\next=\beginxref\fi\next}
- \def\beginxref{\futurelet\next\beginxrefswitch}
- \def\beginxrefswitch{\ifx\next\specialhat\let\next=\silentxref
- \else\silentfalse\let\next=\xref\fi \next}
- \catcode`\^=\active \let ^=\specialhat
- \def\silentxref^{\silenttrue\xref}
-
- \newif\ifproofmode
- \proofmodetrue %
-
- \def\xref{\futurelet\next\xrefswitch}
- \def\xrefswitch{\begingroup\ifx\next|\aftergroup\vxref
- \else\ifx\next\<\aftergroup\anglexref
- \else\aftergroup\normalxref \fi\fi \endgroup}
- \def\vxref|{\catcode`\\=\active \futurelet\next\vxrefswitch}
- \def\vxrefswitch#1|{\catcode`\\=0
- \ifx\next\empty\def\xreftype{2}%
- \def\next{{\tt\text}}%
- \else\def\xreftype{1}\def\next{{\tt\text}}\fi %
- \edef\text{#1}\makexref}
- {\catcode`\|=0 \catcode`\\=\active |gdef\{}}
- \def\anglexref\<#1>{\def\xreftype{3}\def\text{#1}%
- \def\next{\<\text>}\makexref} %
- \def\normalxref#1{\def\xreftype{0}\def\text{#1}\let\next=\text\makexref}
-
- \def\makexref{\ifproofmode%
- \xdef\writeit{\write\inx{\text\space!\xreftype\space
- \noexpand\number\pageno.}}\iffiles\writeit\fi
- \else\ifhmode\kern0pt \fi\fi
- \ifsilent\ignorespaces\else\next\fi}
-
- \newdimen\fullhsize
- \def\fullline{\hbox to\fullhsize}
- \let\lr=L \newbox\leftcolumn
-
- \def\doubleformat{\shipout\vbox{\makeheadline
- \fullline{\box\leftcolumn\hfil\columnbox}
- \makefootline}
- \advancepageno}
- \def\tripleformat{\shipout\vbox{\makeheadline
- \fullline{\box\leftcolumn\hfil\box\midcolumn\hfil\columnbox}
- \makefootline}
- \advancepageno}
- \def\columnbox{\leftline{\pagebody}}
-
- \newbox\leftcolumn
- \newbox\midcolumn
- \def\beginindex{
- \fullhsize=6.5true in \hsize=2.1true in
- \global\def\makeheadline{\vbox to 0pt{\vskip-22.5pt
- \fullline{\vbox to8.5pt{}\the\headline}\vss}\nointerlineskip}
- \global\def\makefootline{\baselineskip=24pt \fullline{\the\footline}}
- \output={\if L\lr
- \global\setbox\leftcolumn=\columnbox \global\let\lr=M
- \else\if M\lr
- \global\setbox\midcolumn=\columnbox \global\let\lr=R
- \else\tripleformat \global\let\lr=L\fi\fi
- \ifnum\outputpenalty>-20000 \else\dosupereject\fi}
- \begingroup
- \parindent=1em \maxdepth=\maxdimen
- \def\par{\endgraf \futurelet\next\inxentry}
- \obeylines \everypar={\hangindent 2\parindent}
- \exhyphenpenalty=10000 \raggedright}
- \def\inxentry{\ifx\next\sub \let\next=\subentry
- \else\ifx\next\endindex \let\next=\vfill
- \else\let\next=\mainentry \fi\fi\next}
- \def\endindex{\mark{}\break\endgroup
- \supereject
- \if L\lr \else\null\vfill\eject\fi
- \if L\lr \else\null\vfill\eject\fi
- }
- \let\sub=\indent \newtoks\maintoks \newtoks\subtoks
- \def\mainentry#1,{\mark{}\noindent
- \maintoks={#1}\mark{\the\maintoks}#1,}
- \def\subentry\sub#1,{\mark{\the\maintoks}\indent
- \subtoks={#1}\mark{\the\maintoks\sub\the\subtoks}#1,}
-
- \def\subsection#1{\medbreak\par\noindent{\bf #1}\qquad}
-
- % For contents
-
- \def\cl#1#2{\bigskip\par\noindent{\bf #1}\quad {\bf #2}}
- \def\li#1#2#3{\smallskip\par\noindent\hbox to 5 in{{\bf #1}\quad #2\dotfill #3}}
- \def\sli#1#2#3{\par\noindent\hbox to 5 in{\qquad\item{#1}\quad #2\dotfill #3}}
- \def\fcl#1#2{\bigskip\par\noindent\hbox to 5 in{\phantom{\bf 1}\quad {\bf #1}\dotfill #2}}
-
- % Epigrams
-
- \def\poem{\begingroup\narrower\narrower\narrower\obeylines\ninepoint}
- \def\widepoem{\begingroup\narrower\narrower\obeylines\ninepoint}
- \def\verywidepoem{\begingroup\narrower\obeylines\ninepoint}
- \def\quote{\medskip\begingroup\narrower\narrower\noindent\ninepoint}
- \def\poemby#1#2{\par\smallskip\qquad\qquad\qquad\qquad\qquad -- #1, {\it #2}
- \tenpoint\endgroup\bigskip}
- \def\widepoemby#1#2{\par\smallskip\qquad\qquad\qquad -- #1, {\it #2}
- \tenpoint\endgroup\bigskip}
- \def\quoteby#1{\par\smallskip\qquad\qquad\qquad\qquad\qquad
- -- #1\tenpoint\endgroup\bigskip}
- \def\endquote{\par\tenpoint\endgroup\medskip}
-
- %
- % End of macros
- \titletrue
-
-
- \centerline{\bigfont The Inform Designer's Manual}
- \vskip 0.5in
- \centerline{\sl Last updated 29/9/94}
- \vskip 0.5in
- \sli{}{Introduction}{2}
- \sli{1}{Getting started}{4}
- \sli{2}{Ingredients and lexicon}{7}
- \sli{3}{Objects, properties and attributes}{9}
- \sli{4}{Places, scenery and the map}{15}
- \sli{5}{Causing actions and making new ones}{18}
- \sli{6}{Containers, supporters and sub-objects}{22}
- \sli{7}{Doors}{23}
- \sli{8}{Switchable objects}{25}
- \sli{9}{Things to enter, travel in and push around}{26}
- \sli{10}{Living creatures and conversation}{27}
- \sli{11}{Starting, moving, changing and killing the player}{29}
- \sli{12}{Printing out names of objects}{31}
- \sli{13}{Classes of objects}{32}
- \sli{14}{Daemons and the passing of time}{34}
- \sli{15}{Adding verbs and grammar to the parser}{37}
- \sli{16}{Scope and what you can see}{44}
- \sli{17}{The light and the dark}{48}
- \sli{18}{On inventories and lists}{50}
- \sli{19}{The naming of names}{53}
- \sli{20}{Plural names and groups of similar objects}{55}
- \sli{21}{Miscellaneous constants and scoring}{57}
- \sli{22}{Debugging verbs and tracing}{59}
- \sli{23}{Limitations on the run-time format}{61}
- \sli{24}{A very few, not very special effects}{63}
- \sli{25}{Dirty tricks}{65}
- \sli{A1}{The Inform language}{67}
- \sli{A2}{Library objects, properties and attributes}{74}
- \sli{A3}{All the entry points, library routines and constants}{78}
- \sli{A4}{All the Inform error messages}{81}
- \sli{A5}{Compiler options and memory settings}{87}
- \sli{A6}{Answers to all the exercises}{91}
- \sli{A7}{Index}{102}
- \vfill\eject
- % --------------------------------------------------------------------------
- % Body of text
- % --------------------------------------------------------------------------
- %$
- %$ This plain text version was generated automatically from the TeX
- %$ source, and is an approximate version of the typeset version. In case
- %$ of garbled passages, consult that edition!
- %$
-
- \section{}{Introduction}
-
- \poem
- I will build myself a copper tower
- With four ways out and no way in
- But mine the glory, mine the power...
- \poemby{^{Louis MacNeice} (1907-1963)}{Flight of the Heart}
-
- Inform is an Adventure-game compiler, and this is the book to read about it.
-
- Infocom format `^{story files}' (Adventure games, that is) can be played on
- almost any computer, ancient or modern, and interpreters which run them are
- widely available, from personal organisers to mainframes. They represent
- probably the most portable form in which games can ever be written, as no
- alteration whatever is required to move a game from one model of computer to
- another.
-
- Inform is not just a compiler but an `operating system' too: its library (a
- suite of standard game routines) allows designers to begin coding at once.
- An Inform source file need not contain any of the parser code, or the
- running of the `game universe', only descriptions and exceptions to the
- usual rules. This world is quite rich already, having over 80 verbs and an
- extensive grammar: the library understands rooms, objects, duplicates,
- containers, doors, 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. The parser it uses (which can be
- entirely invisible to the designer, but is programmable and very flexible)
- is sophisticated enough to handle ambiguities, clarify its input by asking
- questions and to cope properly with plurals, vagueness, conversation,
- pronouns and the player becoming someone else in mid-game.
-
- This manual makes occasional reference to the example games provided with
- Inform, at present `Advent' (a full version of the original mainframe
- Adventure, which contains a good deal of `everyday Inform'), `Toyshop'
- (a collection of unusual objects to play with) and `Balances' (a short story
- consisting of puzzles making great use of the parser's flexibility). Try
- to get hold of these programs and preferably print them out. There is also
- a `Shell' game consisting of the minimum code to get going, but all 14
- lines of it are given in \S 1 anyway.
- \bigskip
-
- The text of this book has evolved from five earlier editions. The old
- manual was in places rather technical, with a makeshift and sometimes
- defensive tone (`Inform is an easel, not a painting'). There were
- specifications of the run-time code format and literary critiques of games
- gone by: like an oven manual padded out with both a cookery book and a
- detailed plan of the gas mains. This book contains just the instructions
- for the oven.
-
- So there are three ^{`companion volumes'}. {\sl The Craft of Adventure} is
- an essay on the design of adventure games; {\sl The Specification of the
- Z-Machine} covers the run-time format and Inform assembly language, its
- lowest level; and {\sl The Inform Technical Manual} documents chiefly
- internals, for compiler maintenance and porting.
-
- In trying to be both a tutorial and reference work in a budget of about
- 100 pages of A4, this book aims itself in style halfway
- between the two extremes of manual, Tedium and Gnawfinger's ``Elements of
- Batch Processing in COBOL-66'', third edition, and Mr Blobby's ``Blobby Book
- of Computer Fun''. (This makes some sections both leaden {\sl and}
- patronising.) I have tried to make every passage tell the truth, so that
- even early sections are reliable for reference purposes. Passages which
- divert the main story, usually to tell the unexpurgated truth when this may
- just confuse the newcomer, are marked with a warning triangle $\triangle$ or
- two, and set in smaller type. Lengthy examples are left as exercises, with
- answers in the Appendix; which also contains a language specification, some
- reference lists, definitions of attributes and properties, and a large index.
-
- \bigskip
- The copyright on Inform, the program and its source code, its example games
- and documentation (including this book) is retained by ^{Graham Nelson}, who
- asserts the moral right to be identified as its author. Having said this, I
- am happy for it to be freely distributed to anybody who wants a copy,
- provided that: (a) distributed copies are not substantially different from
- those archived by the author, (b) this and other ^{copyright} messages are
- always retained in full, and (c) no profit is involved. However, a story
- file produced with the Inform compiler (and libraries) then belongs to its
- author, and may be sold for profit if desired, provided that its game banner
- contains the information that it was compiled by Inform, and the Inform
- version number.
-
- At present, the best source for Inform material (executables of the compiler
- for different machines, source code, the library files and example games) is
- the anonymous ftp site |ftp.gmd.de|, and its home directory is:
- \begintt
- if-archive/infocom/compilers/inform
- \endtt
-
- Some of the ideas of Inform came from an incremental multi-player
- game called ^{Tera}, on the ^{Cambridge University} mainframe, written by
- Dilip Sequeira and the author in 1990 (whose compiler was called Teraform);
- in turn, this stole a little from ^{David Seal} and ^{Jonathan Thackray}'s
- game assembler; which dates back to the late 1970s and was written for
- ^{`Acheton'}, perhaps the first worthwhile game written outside America.
- Still, much of the Inform kernel derives ultimately from the {\sl IEEE Computer}
- article ``Zork: A Computerized Fantasy Simulation Game'' by P. David Lebling,
- Marc S. Blank and Timothy A. Anderson; and more was suggested by
- Richard Tucker, among others.
-
- With the advent of Inform 5 in mid-1994, I feel that the underlying language
- came to a satisfactory state. The library files, however, may well go on
- being improved, since users can update these much more easily than the
- compiler (changes to which mean work for many people). The present
- library files (release 5/4) are greatly enhanced from the ^{Inform 5.2} files,
- but compatible with them (except in handling plural nouns and that the
- obselete attribute |autosearch| has been withdrawn).
-
- The list of those who have helped the project along is legion: I should like
- to thank them all, porters, users and critics alike, but especially Volker
- Blasius, Paul David Doherty, Mark Howell, Bob Newell, Robert Pelak, Gareth
- Rees, J\o rund Rian, Dilip Sequeira, Richard Tucker and Christopher Wichura.
-
- One final word. I should like to dedicate this book, impertinently perhaps,
- to our illustrious predecessors: ^{Willie Crowther}, ^{Don Woods} and
- the authors of ^{Infocom, Inc.}
- \medskip
- %$ Graham Nelson
- %$ Magdalen College, Oxford
- %$ September 1994
- %$-3
- \hbox to\hsize{\hfill\it Graham Nelson}
- \hbox to\hsize{\hfill\it Magdalen College, Oxford}
- \hbox to\hsize{\hfill\it September 1994}
- \vfill\eject
-
- \section{1}{Getting started}
-
- The first thing to try is to compile the ^{`Hello Cruel World'} game, a very
- short test file supplied with Inform. If that compiles and runs properly
- (producing a short page of text, then finishing), try the following:^^{`Shell'}
- \begintt
- 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=Blank_Room;
- "^^^^^Welcome to the shell...^^";
- ];
-
- Include "Grammar";
- end;
- \endtt
- If this compiles, Inform is probably 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. (|Include| lines are also sometimes
- written |#include| to make C programmers feel more at home.) The library
- files are:
- \medskip
- \settabs 6 \columns
- \+ & ^|Parser| & The core of the game, and a full parser\cr
- \+ & ^|VerbLib| & Routines for many game verbs, like ``take''\cr
- \+ & ^|Grammar| & A grammar table to decode the player's input from\cr
- \medskip\noindent
- Together, they make up the `library'. They can certainly be modified by
- designers, but great effort has gone into making sure the need hardly ever
- arises.
-
- \noindent Apart from that, the code contains:
- \item{(a)} strings giving the name of the game, and a copyright message, to be
- printed out at the appropriate moments;
- \item{(b)} 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;
- \item{(c)} an object, to be the only room of the game.
- \par\noindent The `Shell' game is very boring: there is nothing for the player
- to do but wait and quit.
- \medskip
-
- In Inform, everything is an object: rooms and things to be picked up,
- scenery, intangible things like mist and even some abstract ideas (like
- the direction `north'). More about this later: for now, here's a new
- object, to go under the |Blank_Room| definition:^^{green cone}
- \begintt
- Nearby cone "green cone"
- with name "green" "cone";
- \endtt
- (|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:
- \begintt
- Nearby cone "green cone"
- with name "green" "cone" "emerald",
- initial "Nearby is an emerald green cone, one foot high.";
- \endtt
- The ^|initial| message now appears when we arrive in the Empty Room. Taking
- things a little further...
- \begintt
- 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;
- \endtt
- (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|: and the player is allowed to
- eat the cone.
-
- \danger |name|, |description| and |initial| are examples of `properties',
- while |edible| is an `attribute': the difference is that the former have
- values, whereas the latter are just on or off.^^{properties}^^{attributes}
-
- So far, we're just filling in a form, and we could go much further
- doing this, but that wouldn't be much of an example. Instead, some
- honest programming:
- \beginstt
- 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;
- \endtt
- The property ^|after| doesn't just have a string for a value: it has a
- routine of its own. 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.
-
- \danger There's no real difference between routines like |Initialise|,
- which are defined outside objects at the `top level', and routines
- inside objects like this |after| routine: except that outside routines
- have to have names, since they aren't identified by belonging to
- any particular object.
-
- Still, the cone doesn't actually do anything! So here it is with a
- (completely unfair) puzzle added:
- \beginstt
- 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;
- \endtt
- 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).
-
- \danger Like many programming languages, Inform braces together blocks of
- code. ^|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,
- and setting it to 2 causes a win.
-
- 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
- \begintt
- "Unfortunately, you seem to be allergic to almonds.";
- \endtt
- 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.
-
- \exercise Extend the green cone so that it is described as sagging after
- it has been dropped back on the ground. (You need a few more properties for
- this.)
-
- \answer{\beginlines
- |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;|
- \endlines
- 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.}
-
-
- \section{2}{Ingredients and lexicon}
-
- Properly speaking, `Inform' means the compiler and its language: whereas this
- book is chiefly about the `library' of code which comes with it. For
- most practical purposes this makes no difference - but it's worth remembering
- that in the last resort you can change almost anything about how the ^{library}
- works.
-
- The basic ingredients of an Inform game are:
- \begindisplay
- {\bf Objects},\quad {\bf Routines},\quad {\bf Actions}\quad {\rm and}\quad {\bf Grammar}.
- \enddisplay^^{lexicon}^^{actions}
- We have already seen examples of Objects and Routines. Actions happen in the
- course of play. The main loop of a game looks like this:
- \medskip
- \item{1.}{Ask the player to type something}
- \item{2.}{Parse this (i.e. decide what it means) and generate any actions it
- calls for}
- \item{3.}{Work out the consequences of these actions and tell the player}
- \item{4.}{Worry about time passing by, and other things happening}
- \medskip\noindent
- a process which ends only in victory or death. (In this respect it is unlike
- life.)
-
- Probably the most complicated programming in any adventure game goes into the
- parser. Inform's parser is fairly advanced, and is designed with the intention
- of being highly programmable at all levels to suit your game: so this manual
- will be returning to features of the parser again and again. It isn't perfect
- by any means, but it does understand things like:
- \begintt
- throw three of the coins into the fountain
- write funny on the lighted cube
- take the sword and all the crowns
- what is a grue
- dwarf, give me the battleaxe
- \endtt
- It also asks questions when it needs to, makes inferences from partial requests
- and tries to make good guesses when faced with ambiguous requests. You can
- teach it new verbs and new forms of old ones: this is ^{Grammar}. (The library
- starts with about 85 verbs, not counting synonyms.)
-
- Until you need to start programming it, the parser sits in the background, and
- you need to know nothing about it. But the parser is where Actions come from.
- An Action can have up to two objects attached to it, and represents something
- which the player is trying to do. For instance,
- \begindisplay
- |Inv| \qquad |Take sword|\qquad |Insert gold_coin cloth_bag|
- \enddisplay
- are all actions. (By this stage the game has reduced them to three numbers
- each, the action number and two object numbers: there's no text floating about.)
-
- \danger Actions are also sometimes produced as a knock-on effect by other
- actions, and they can also be produced by your own code: you can even create
- new actions altogether, which are treated no differently from the standard ones.
-
- \exercise Compile one of the supplied example games, say `Toyshop', with
- the ^|DEBUG| option defined (see the section on debugging) so that you can use
- the special ^{``actions'' verb} to see exactly what all the actions are as they
- happen.
-
- \answer{You may be surprised how many actions take place: often more than one
- per turn.}
-
- \bigskip
- \danger Inform can produce two kinds of game: ``Standard'' and ``Advanced''.
- ^^{Standard games}^^{Advanced games}
- Code is in almost every case portable between these two forms, so that you
- can easily make a version each way from the same program. The latter is
- better, but just in case you have a small computer (such as a personal
- organiser) or a very bad run-time interpreter, you might prefer the former.
- Occasionally this manual will mention a difference between these forms.
-
- \ddanger At this point, we should describe the imaginary machine, sometimes
- called the Z-machine (Z is for ^{`Zork'}) which Inform compiles games for.
- An `interpreter' is a program which simulates this imaginary machine, so that
- it can run the game files that Inform produces: the same files will work
- on any ^{interpreter} on any machine. Interpreters are available for very many
- machines indeed. The ^{Z-machine} is, except in a few corners, a beautiful
- design and is described in great detail in the {\sl Specification of the
- Z-Machine}. For now, a few words about the ^{memory map}. The memory of
- this imaginary computer is 128K long for Standard games and 256K long for
- advanced ones: the format is extremely well compressed, so this is actually
- quite a large memory.
-
- \ddanger Numbers are stored in 16-bit words (2 bytes long), and are signed
- in the usual way, so they hold values^^{numbers}
- $$ -32768 \leq n\leq 32767 $$
- with the hexadecimal value |$ffff| being the same as $-1$. The sign doesn't
- mean anything for ^{addresses}, of course, but there's a catch: given that a
- 2-byte number can only hold a value $0\leq n\leq 65535$, how can an address
- in a 128K or 256K memory map be held? The answer is that there are two
- kinds of address: a `packed address' and a `byte address'. A ^{byte address} is
- just an address in the bottom 64K of memory, and the Z-machine is arranged
- so that everything which could ever change is there: so these are the only
- addresses which matter very much. Packed addresses are addresses divided
- by 2 (or by 4 in Advanced games), so they can only refer to even (divisible
- by four) locations in memory. They hold the addresses of long strings and
- routines, which Inform is careful always to put at even (divisible by four)
- locations.^^{packed address}
-
- \vfill\eject
- \section{3}{Objects, properties and attributes}
-
- \quote
- Objects make up the substance of the world. That is why
- they cannot be composite.
- \poemby{Ludwig Wittgenstein (1889-1951)}{Tractatus}
-
- \quote
- ...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.
- \poemby{Julia Annas}{Classical Greek Philosophy}^^{Aristotle}
-
-
- The ^{objects} of the game form what is sometimes called a `tree', though
- a better analogy would be a forest, and anyway one usually draws the whole
- thing upside down and uses the language of `families' - calling them `children'
- and `parents' of each other. Anyway, here's an example:^^{tree of objects}
-
- %$-9
- \def\ra{\rightarrow}\def\da{\downarrow}
- $$\matrix{
- |Meadow|\cr
- \da\cr
- |Mailbox| & \ra & |Player|\cr
- \da & & \da\cr
- |Note| & & |Sceptre| & \ra & |Cucumber| & \ra & |Torch| & \ra & |Magic Rod|\cr
- & & & & & & \da\cr
- & & & & & & |Battery|\cr} $$
- %$ Meadow
- %$ |
- %$ Mailbox -> Player
- %$ | |
- %$ Note Sceptre -> Cucumber -> Torch -> Magic Rod
- %$ |
- %$ Battery
-
- This is a family tree, then: each object has a parent, a sibling and a child,
- though that object may be the special |nothing| object. (The |Cucumber| has
- child |nothing|, for instance.)
-
- As the game goes on, objects move around: when an object moves, all its
- possessions (that is, children) go with it. The Inform command to move an
- object is^^|move|
- \begintt
- move object to new-owner;
- \endtt
- and it must be emphasized that this prints nothing on the screen, and indeed
- does nothing except to change the tree above.
-
- Inform provides special functions for reading this tree.
- \begindisplay
- ^|parent|,\quad ^|sibling|\quad and\quad ^|child|
- \enddisplay
- all do the obvious things, and in addition there's a function called |children|
- which counts up how many children an object has (only children: grandchildren
- aren't counted). For instance,
- \begintt
- parent ( Mailbox ) = Meadow
- children ( Player ) = 4
- child ( Sceptre ) = 0
- sibling ( Torch ) = Magic Rod
- \endtt
- \danger ^|nothing| isn't really an object: it's just a convenient name for the
- number 0, which is the object number meaning `no such object'. It isn't a good
- idea to meddle with |nothing|, or to apply functions like |parent| to it,
- but then there's never any need.
-
- \ddanger 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
- \smallskip\ninepoint
- \settabs 5 \columns
- \+ &^|youngest| & end of list of possessions\cr
- \+ &^|eldest| & same as |child|\cr
- \+ &^|younger| & same as |sibling|, i.e. rightwards in the picture\cr
- \+ &^|elder| & reverse of |sibling|, i.e. leftwards in the picture\cr
- \smallskip\tenpoint
-
- Objects have more to them than just where they are in the tree. They
- also have collections of variables attached to them.
-
- 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". Attributes all have names,
- which are a single word: like ^|light|, for instance, which indicates that
- something is giving off light. There are about 30 defined by the library.
- They can be tested with a condition like^^|has|
- \begintt
- if (obj has locked) "But it's locked!";
- \endtt
- and can be set with the ^|give| command. So, for instance,
- \begintt
- give brass_lantern light;
- give iron_door locked;
- \endtt
- and they can be taken away with
- \begintt
- give brass_lantern ~light;
- give fake_coin ~scored;
- \endtt
- the |~| sign (or tilde) standing for negation. In fact you can give or take
- many at one go, so for instance
- \begintt
- give wooden_door open openable ~locked;
- \endtt
- \danger You can make your own attributes
- ^^{making attributes}
- with a directive like
- \begintt
- Attribute offered_to_ogre;
- \endtt
- at the start of the program. (A `^{directive}' is a command to Inform directly,
- and happens at compile-time: not something in a routine which is to happen in
- the course of play.)
-
- \ddanger In ^{Standard games} there are few spare attributes available because
- th library takes most of them. To get around this limit
- there's a convenient dodge. 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
- ^^|alias|^^{reusing attributes}^^|Attribute|
- \begintt
- Attribute <new> alias <old>;
- \endtt
- 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. (The library already indulges in a certain
- amount of this chicanery.)
-
- \medskip
- Secondly, there are ``^{properties}''. These are far more elaborate, and not
- every object has every property. For instance: not every object has the
- |door_to| property (it holds the place a door leads to, so things other
- than doors don't usually have it). The current value of a property is
- got at by constructions like:
- \begintt
- iron_door.door_to
- crystal_bridge.door_to
- green_cone.before
- diamond.initial
- \endtt
- You can read the value of |door_to| for something like the |diamond|,
- and you'll just get a dull value like |nothing|, but you can't write to it:
- that is, you can't change |diamond.door_to| unless you declared a |door_to|
- property for it.
-
- \danger You can also define your own properties (again, subject to
- availability, because the library claims many of them).^^{making properties}
- \begintt
- Property door_to;
- Property article "a";
- Property blorple_routine $ffff;
- \endtt
- are all examples of the ^|Property| directive. In the case of |article|,
- we are saying that the value |"a"| should be the default value for any
- object which doesn't declare an |article|.^^{default value of properties}
-
- \ddanger Properties can also ^|alias|. They can also be declared as
- ^|long| or ^|additive|, which is a complicated matter: basically, we'll
- come to |additive| when discussing classes, and properties which might
- start as small numbers (less than 256) and be changed into large ones
- in play, ought to be declared as |long|.
-
- As will be seen from examples, a property value can be many things:
- a string like |"frog"|, a number such as |$ffff| (this is the Inform
- way of writing numbers in ^{hexadecimal}), an object or a routine. You
- can change the current value by something like
- \begintt
- location.door_to = hall_of_mists;
- brass_lantern.short_name = "dimly lit brass lantern";
- grenade.time_left = 45;
- \endtt
-
- \warning The game may crash at run-time 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: see below.)
-
- \danger The Inform language does not have types as such, and strings
- and routines are stored as numbers: as their addresses inside the virtual
- machine, in fact. This means that Inform thinks
- \begintt
- "Hello there" + 45 + 'a'
- \endtt
- is a ^{perfectly sensible} calculation. It's up to you to be careful.
- ^^{types (lack of)}
-
- \ddanger A property can hold more than just one number (be it interpreted
- as a string, a routine or whatever): it can hold a ^{small array} of numbers.
- In ^{Standard games} it can have four numbers (8 bytes' worth), and in
- ^{Advanced games} 32 (64 bytes). For instance, an entry in an object
- definition might read
- \begintt
- found_in Marble_Hall Arched_Passage Stone_Stairs,
- \endtt
- storing a sequence of three values (all objects) in the |found_in|
- ^^|found in|
- property.
- To read or write to this array, you need to know its (byte) address and its
- length. The operators
- \begindisplay
- |object.&property|\quad and\quad |object.#property|
- \enddisplay
- tell you these. (Be warned: |object.#property| tells you the number of bytes,
- not the number of words.)
- If you give a property more than 8 bytes of data in a Standard game,
- Inform warns you and takes only the first 8, but does not cause an
- error: this is so that, say,
- \beginstt
- Object ...
- with name "radio" "wireless" "transistor" "portable" "stereo" "tranny",
- ...
- \endtt
- will compile either way (but the last two synonyms for |"radio"| will not
- enter the dictionary if it's being compiled in Standard form, since a name
- takes two bytes).
-
-
- \ddangerexercise Use the |object.&property| construction to find out whether
- the object in variable |obj| has the |door_to| property defined or not.
-
- \answer{|if (obj.&door_to == 0) { ... }|}
-
- \bigskip\noindent
- Time to make some ^{object definitions}. A typical object definition looks
- something like:
- \beginstt
- 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;
- \endtt
- This is the conventional way to lay out an ^|Object| declaration: with the
- header first, then ^|with| a list of properties and their starting values,
- finishing up with the attributes it initially ^|has|.
-
- |trapdoor| is the name given to the object in the program, and it becomes
- a constant from then on (whose value is the number of the object). The
- |attic| is the object which the |trapdoor| starts out belonging to (as
- any player of ^{`Curses'} will know). Some objects start out not
- belonging to anything (rooms, for example, or treasures which only appear
- half-way through). You can declare these as belonging to |nothing|, but
- it's better just to miss this out altogether:
- \begintt
- Object trapdoor "hinged trapdoor"
- with ...
- \endtt
- If you do declare an object already belonging to another, as above,
- then the other object must already have been defined. (This is no real
- restriction, and ensures that you can't set up a `loop' - one in another
- in a third in the first, for instance.)
-
- Objects can also be declared, in an identical way, by the |Nearby| directive.
- The only difference is that no initial-owner object can be given; it starts
- out belonging to the last thing declared as an |Object|. For example, in
- \begintt
- Object hillside "Panoramic Hillside"
- with ...
-
- Nearby scenery "scenery"
- with ...
- \endtt
- the |hillside| is a room to which the |scenery| will belong. Otherwise,
- ^|Nearby| is the same as |Object|, and this is just a convenience to make
- it easier to move things around in Inform code by cutting definitions out
- and pasting them in elsewhere.
-
- Some properties of objects should be routines. For instance,
- an object can have a ^|describe| property which is a routine to print out
- a description of it.
-
- These could just be listed as names of routines, but usually the actual
- routine is written out then and there as the property value.
- For instance, in the classic Adventure object^^{tasty food}
- \begintt
- 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;
- \endtt
- the |after| property does not name a routine but instead defines it. No
- name is needed or given for the routine. (The semicolon after the |[| is
- needed to show that the routine has no local variables.)
-
- 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.)
-
- \danger The rules for ^{embedded routines} are not quite the same as those
- for ordimary routines. By default, embedded routines return ``false", or 0
- (instead of ``true", or 1, which other routines return by default). Also,
- the handy shorthand:
- \begintt
- Action [, Action2 ...] : ...some code...
- \endtt
- is provided, which executes the code only if the action being considered
- is the one named.
-
- \ddanger It actually does this by setting a special variable called
- |sw__var|
- ^^|sw var|
- to the action number: when it compiles |Action1:| it just
- compiles an |if| statement which sees whether |sw__var| has value |Action1|.
-
- \danger Properly speaking, the full syntax of the header is^^{Object syntax}
- \begindisplay
- |Object| \<obj-name-1> \<obj-name-2> ... \<obj-name-$n$> |"short name"|
- |[|\<parent-obj>|]|\cr
- {\it or}\quad |Nearby| \<obj-name-1> \<obj-name-2> ... \<obj-name-$n$>
- |"short name"|\cr
- {\it or}\quad |Class| \<class-name>\cr
- \enddisplay
- and the parent object must have already been defined.
- A ^|Class| definition is very like an object definition, and will be discussed
- later on. The syntax for an object, then, is
- \begindisplay
- \<Header> |[,]|\cr
- \quad |class| \<class-1> \<class-2> ... \<class-$n$> |[,]|\cr
- \quad |with| \<property-name-1> \<value-1> ... \<value-$n$>|,|\cr
- \qquad \<property-name-2> \<value-1> ... \<value-$n$>|,|\cr
- \qquad ...\cr
- \qquad \<property-name-$n$> \<value-1> ... \<value-$n$> |[,]|\cr
- \quad |has| \<att-1> \<att-2> ... \<att-$n$>\cr
- \enddisplay
- 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.
- (The classes listed under |class| are those which the object inherits from.)
-
- \danger One property is treated differently from the others, and this
- is the special property ^|name|. Its data must be a list of English words
- in double-quotes, as in all the above examples. (Probably the most
- annoying restriction of ^{Standard games} is that this means only 4 names
- at most can be accommodated in that format: you get up to 32 in ^{Advanced
- games}.) It will probably confuse the parser if any of these names is
- something like |"my"|, |"the"|, |"all"|, |"except"| or |"this"|. Numbers
- can safely be used, however.
-
- \ddanger In fact, ^|name| contains a list of byte addresses of dictionary
- words. A quick way to print out the first word in the |name| list is
- therefore
- \begintt
- print_addr obj.name;
- \endtt
-
- \ddanger The attributes \<att-1> and so on can be taken away as well as
- added, thus:
- \begintt
- ...
- has light ~scored;
- \endtt
- which is sometimes useful to over-ride an ^{inheritance} from a class definition.
-
- \ddanger A final curiosity of the |Object| syntax is that objects can be given
- more than one name. This is a ^{hangover} from much earlier days of Inform,
- to do with re-using the same physical object in different logical ways,
- something which the author does not commend to anyone.
-
- \section{4}{Places, scenery and the map}
-
- \quote
- It was a long cylinder of parchment, which he unrolled and spread out
- on the floor, putting a stone on one end and holding the other.
- I saw a drawing on it, but it made no sense.
- \poemby{^{John Christopher}}{The White Mountains}
-
- \poem
- And if no piece of chronicle we prove,
- We'll build in sonnets pretty rooms;
- As well a well wrought urn becomes
- The greatest ashes, as half-acre tombs.
- \poemby{^{John Donne} (1571?-1631)}{The Canonization}
-
- Back to our example. Throw away the old ``blank room" and replace it by...
- \beginstt
- 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;
- \endtt
- ^^{Square Room}
- (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?
- \beginstt
- 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;
- \endtt
- ^^{crystal chandelier}
- This is part of the fittings, hence the |static| attribute (which means it
- can't be taken or moved). But what about the rainbows?
- \beginstt
- Nearby rainbows "rainbows"
- with name "rainbow" "rainbows",
- description "Caused by diffraction, or something like that - \
- you were never very good at physics."
- has scenery;
- \endtt
- ^^{rainbows}
- 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:
- \beginstt
- 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;
- \endtt
- Let us now add a second room:
- \beginstt
- 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;
- \endtt
- ^^{Sloping Corridor}
- and extend the Square Room to:
- \beginstt
- 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;
- \endtt
- 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.
- ^^{map}
-
- 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|
- ^^|cant go|
- message is printed instead. (In fact, as is often the case with properties,
- instead of giving an actual message you can instead give a routine to print
- one out, so that what is printed varies with circumstances.)
-
- Map connections are all one-way, in themselves: they just happen to be
- defined here so that they appear two-way.
- \bigskip
-
- Rooms also have rules of their own. We might write:
- \beginstt
- 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;
- \endtt
- 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.
-
- \ddanger Sometimes 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:
- \beginstt
- after
- [; Go: if (noun==in_obj)
- print "How grateful you are to get out of the rain...^";
- ],
- \endtt
- 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: but the |^| symbol means ``print a new-line",
- so one is actually printed.)
-
- \danger 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.) Moreover, you can change these
- directions (as far as Inform is concerned, only things in the special
- object |compass| can be directions).
-
- \dangerexercise In the first millenium A.D., the Mayan peoples of the
- Yucat\'an Peninsula had `world colours' white ({\it sac}), red ({\it chac}),
- yellow ({\it kan}) and black ({\it chikin}) for what we call the compass
- bearings north, east, south, west (for instance west is associated
- with `sunset', hence black, the colour of night). Implement this.^^{world
- colours}^^{Mayan directions}^^{direction objects}
-
- \answer{Define four objects along the lines of:
- \beginlines
- |Object white_obj "white wall" compass|
- | with name "white" "sac" "wall", article "the", door_dir n_to|
- | has direction scenery;|
- \endlines^^{world colours}^^{Mayan directions}^^{direction objects}
- and add the following line to |Initialise|:
- \beginlines
- |remove n_obj; remove e_obj; remove w_obj; remove s_obj;|
- \endlines
- (We could even |alias| a new property |white_to| to be |n_to|, and then
- enter map directions in the source code using Mayan property names.)
- As a fine point of style, turquoise ({\it yax}) is the world colour for
- `here', so add a grammar line to make this cause a ``look'':
- \beginlines
- |Verb "turquoise" "yax" * -> Look;|
- \endlines}
-
- \dangerexercise (Cf. ^{`Trinity'}.) How can the entire game map
- be suddenly east-west reflected?^^{reflecting the map}
-
- \answer{^^{reflecting the map}\beginlines
- |[ SwapDirs o1 o2 x;|
- | x=o1.door_dir; o1.door_dir=o2.door_dir; o2.door_dir=x; ];|
- |[ ReflectWorld;|
- | SwapDirs(e_obj,w_obj); SwapDirs(ne_obj,nw_obj); SwapDirs(se_obj,sw_obj);|
- |];|
- \endlines}
-
- \ddangerexercise Even when the map is reflected, there may be many
- room descriptions referring to ``east'' and ``west'' by name. Reflect
- these too.
-
- \answer{This is a prime candidate for using ^{variable strings}
- ^|@nn|, a topic properly covered in the {\sl Inform Technical Manual},
- but briefly: at the head of the source, define
- \beginlines
- |Lowstring east_str "east"; Lowstring west_str "west";|
- \endlines^^|Lowstring|^^|String|
- and then add two more routines to the game,
- \beginlines
- |[ NormalWorld; String 0 #east_str; String 1 #west_str; ];|
- |[ ReversedWorld; String 0 #west_str; String 1 #east_str; ];|
- \endlines
- where |NormalWorld| is called in |Initialise| or to go back to
- normal, and |ReversedWorld| when the reflection happens. Write
- |@00| in place of |east| in any double-quoted printable string,
- and similarly |@01| for |west|. It will be printed as whichever
- is currently set. (Inform provides up to 32 such variable strings.)}
-
- \section{5}{Causing actions and making new ones}
-
- \widepoem
- Only the actions of the just
- Smell sweet and blossom in their dust.
- \widepoemby{^{James Shirley} (1594-1666)}{The Contention of Ajax and Ulysses}
- \quote
- ...a language obsessed with action, and with the joy of seeing
- action multiply from action, action marching relentlessly ahead
- and with yet more actions filing in from either side to fall into
- neat step at the rear, in a long straight rank of cause and
- effect, to what will be inevitable, the only possible end.
- \poemby{^{Donna Tartt}}{The Secret History}
-
- One often wants to simulate the effect of a player typing something.
- For instance, in the ^{Pepper Room} the air is full of pepper and every turn
- the player sneezes and drops 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:
- \begindisplay
- You sneeze convulsively, and lose your grip on the toffee apple...\cr
- The toffee apple sticks to your hand!\cr
- \enddisplay
- which (though not ideal) is much better. As an example, here is another
- piece of scenery to clutter up the tiny map so far:
- \beginstt
- 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;
- \endtt
- ^^{low mist}^^|found in|
- 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.
- \medskip
-
- The player will find that smelling the mist produces the same message as
- looking at it. The command
- \begintt
- <<Examine self>>;
- \endtt
- 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
- \begintt
- <<Examine low_mist>>;
- \endtt
- does just the same thing.) After going through the business of examining
- the mist, the routine then returns `true', or 1 (in this case, so that the
- ^{normal rules} for smelling something are stopped in their tracks).
-
- If instead
- \begintt
- <Examine self>;
- \endtt
- had been used, the same would have happened, but the routine would not have
- been returned from. So the mist would be examined; and then the routine for
- |Smell| would resume, and since there's nothing more to it, it would return
- false; whereupon the library's usual rules would make it say something like
- ``You smell nothing unusual.".
-
- All ^{actions} can be written this way:
- \begintt
- <Look>; <<ThrowAt cone chandelier>>;
- \endtt
- will, for instance, look around, then behave as if the player had asked
- to throw the cone at the chandelier, then return true.
- \medskip
-
- \danger Internally, actions like |Look|, |ThrowAt| and |Take| 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
- and sometimes it's convenient to use this directly. For instance, imagine
- a mirror hung very far above the player. Given:
- \begintt
- before
- [; if (action==##Examine) rfalse;
- "The mirror is too high up, out of reach.";
- ]
- \endtt
- ^^{action numbers}
- 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.
-
- \danger
- 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.
-
- \danger
- The actions implemented by the library are in three groups. The useful ones
- are in groups 2 and 3:^^{action groups}
- \beginlines
- |1. Quit, Restart, Restore, Verify, Save, ScriptOn, ScriptOff, Pronouns,|
- | Score, Fullscore, LMode1, LMode2, LMode3, NotifyOn, NotifyOff;|
- \smallskip
- |2. Inv, InvTall, InvWide, Take, Drop, Remove, PutOn, Insert, Transfer,|
- | Empty, Enter, Exit, GetOff, Go, GoIn, Look, Examine, Give, Show,|
- | Unlock, Lock, SwitchOn, SwitchOff, Open, Close, Disrobe, Wear, Eat;|
- \smallskip
- |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|
- \endlines{\ninepoint
- Of course, 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.}
-
- \ddanger 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, using a |Replace|d routine.)
-
- 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.)
-
- \danger The ones which actually do something, and call ^|after|, are:
- \begintt
- Inv, Take, Drop, Remove, PutOn, Insert, Exit, Go, Look, Examine, Unlock,
- Lock, SwitchOn, SwitchOff, Open, Close, Disrobe, Wear, Eat, Search.
- \endtt
- \ddanger 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
- a sequence of |Drop| actions, for instance, and if a sack is emptied into
- a packing case this is considered a multiple insertion.
-
- \ddanger ^|Search| (the searching or looking-inside-something action) is a
- slightly special case between groups 2 and 3. It never actually does anything
- beyond printing messages. What happens is that if it would be sensible to
- look inside the object (i.e. if it's an open or transparent container and
- there is light), |after| is called beforehand. In this way you can use
- |before| to trap searching of random scenery, and |after| to alter rules
- for listing contents of containers.
- \medskip
-
- The library's actions are easily added to. For instance, add the routine:
- \begintt
- [ BlorpleSub;
- "You speak the magic word ~Blorple~. Nothing happens.";
- ];
- \endtt
- (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.^^{making actions}
-
- 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^^{making grammar}
- \begintt
- Verb "blorple"
- * -> Blorple;
- \endtt
- immediately after the inclusion of the |Grammar| file. (The spacing is
- just a matter of convention.) 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. (Far more about grammar later.)
-
-
- \danger
- 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 normal rules can be
- interrupted at eight different stages:\ninepoint
- \item{1.} Call ^|GamePreRoutine| (if there is one). If this returns true,
- stop here.
- \item{2.} Call the |before| of the player. If this returns true, stop here.
- \item{3.} Call the |before| of Bedquilt Room. If this returns true, stop here.
- \item{4.} Then the |before| of the oyster. If this returns true, stop here.
- \item{5.} Actually drop the object.
- \item{6.} Call the |after| of the player. If this returns true, stop here.
- \item{7.} Call the |after| of Bedquilt Room. If this returns true, stop here.
- \item{8.} Then the |after| of the oyster. If this returns true, stop here.
- \item{9.} Call ^|GamePostRoutine| (if there is one). If this returns true,
- stop here.
- \item{10.} Print ``Dropped.''
- \PAR\noindent
- \ddanger
- |GamePreRoutine| and |GamePostRoutine| are examples of `entry points', like
- |Initialise|: routines you can provide to make global rule changes. Their
- use is a drastic measure to be avoided if possible. The player's own
- |before| and |after| will be discussed in \S 11.
- \tenpoint
-
- \ddanger ``Fake actions'' are just like real actions, except that they don't
- occur in any game grammar, so they're never generated by the parser. They're
- a neat way to pass `messages' from one object to another one. Because they
- aren't defined implicitly in the grammar, they have to be explicitly declared
- before use, by the directive:^^{passing messages}
- \begindisplay
- |Fake_Action| \<Action-name>\cr
- \enddisplay^^|Fake Action|
-
- \ddangerexercise How can you make a ^{medicine bottle}, which can be opened
- in a variety of ways in the game, so that the opening-code only occurs in
- the bottle definition?
-
- \answer{Declare a fake action called, say, |OpenUp|. Then:
- \beginlines
- |Object medicine "guaranteed child-proof medicine bottle" cupboard|
- | with name "medicine" "bottle",|
- | description "~Antidote only: no preventative effect.~",|
- | before|
- | [; Open, Unlock: "It's adult-proof too.";|
- | Openup: give self open ~locked; "The bottle cracks open!";|
- | ],|
- | has container openable locked;|
- \endlines
- Any other code in the game can execute |<OpenUp medicine>| to crack open
- the bottle.}
-
- \section{6}{Containers, supporters and sub-objects}
-
- \quote
- The concept of a surface is implemented as a special kind of containment.
- Objects which have surfaces on which other objects may sit are actually
- containers with an additional property of ``surfaceness".
- \poemby{^{P. David Lebling}}{Zork and the Future}
-
- Objects can be inside or on top of one another. An object which has the
- ^|container| attribute 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 a container when it 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.
-
- \exercise Make a ^{glass box} and a ^{steel box}, which behave differently
- when the lamp is shut up inside them.
-
- \answer{\beginlines
- |Nearby glass_box "glass box with a lid"|
- | with name "glass" "box" "with" "lid"|
- | has container transparent openable open;|
- |Nearby steel_box "steel box with a lid"|
- | with name "steel" "box" "with" "lid"|
- | has container openable open;|
- \endlines}
-
- Containers (and supporters) are able to react to things being put inside
- them, or removed from them, by acting on the |Receive| and |LetGo| actions.
-
- \exercise Make the following, rather acquisitive bag:^^{toothed bag}
- \beginstt
- >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.
- \endtt
-
- \answer{^^{toothed bag}
- \beginlines
- |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;|
- \endlines}
-
- \danger ^|LetGo| and ^|Receive| are actually two of the ^{fake actions}:
- they are the actions ^|Insert| and ^|Remove| looked at from the container's
- point of view.
-
- 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.)^^|with key|
-
- As a final example of a container, this is a fairly typical locked
- cupboard:
- \beginstt
- 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;
- \endtt^^{bolted cupboard}
-
- Now suppose you want to make a portable television set which has four
- different buttons on it. Obviously when the television moves, its buttons
- should move with it, and the sensible way to arrange this is to make the
- four buttons possessions of the |television| object.
-
- However, the television isn't a |container|, and the player can't normally
- ``see'' (that is, refer to) the possessions of an
- object. So how do we bring the buttons into the player's ``view'' without
- making them removable, or allowing anyone to put extra things ``into''
- the television?
-
- This is what the ^|transparent| attribute is for: it is an extremely useful
- device to allow the player to ``see'' (i.e. talk about) the contents of
- an object.
-
- \exercise Implement a ^{television set} with attached power button and
- screen.
-
- \answer{\beginlines^^{television set}
- |Object television "portable television set" lounge|
- | with name "tv" "television" "set" "portable",|
- | before|
- | [; SwitchOn: <<SwitchOn power_button>>;|
- | SwitchOff: <<SwitchOff power_button>>;|
- | Examine: <<Examine screen>>;|
- | ],|
- | has transparent;|
- |Nearby power_button "power button"|
- | with name "power" "button" "switch",|
- | after|
- | [; SwitchOn, SwitchOff: <<Examine screen>>;|
- | ],|
- | has switchable;|
- |Nearby screen "television screen"|
- | with name "screen",|
- | before|
- | [; Examine: if (power_button hasnt on) "The screen is black.";|
- | "The screen writhes with a strange Japanese cartoon.";|
- | ];|
- \endlines}
-
- \section{7}{Doors}
-
- \quote
- Standing in front of you to the north, however, is a door surpassing
- anything you could have imagined. For starters, its massive lock is
- wrapped in a dozen six-inch thick iron chains. In addition, a certain
- five-headed monster...
- \poemby{^{Marc Blank} and ^{P. David Lebling}}{^{`Enchanter'}}
- \widepoem
- O for doors to be open and an invite with gilded edges
- To dine with Lord Lobcock and Count Asthma.
- \poemby{^{W. H. Auden} (1907-1973)}{Song}
-
- 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|:
- \item{(a)} give the object the |door| attribute;
- \item{(b)} set the |door_to| property to the destination;
- \item{(c)} set the |door_dir| property to the direction which that would be,
- such as |n_to|;
- \item{(d)} make the room's ^{map} connection in that direction point to the
- door itself.
- ^^|door to|^^|door dir|
- \PAR\noindent For example, here is a closed and locked door:^^{rusty door}
- \beginlines
- |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;|
- \endlines
- (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.
- ^^|when closed|^^|when open|
-
- 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}:^^{steel grate}
- \beginlines
- |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;|
- \endlines
- 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 either above or below.
-
- \danger At first sight, it isn't obvious why doors have the |door_dir|
- ^^|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 (provided the door is actually open) is to cause the |Go| action with
- the given direction.
-
- \danger 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|.
-
-
- \section{8}{Switchable objects}
-
- \quote
- In one corner there is a machine which is reminiscent of a clothes dryer.
- On its face is a switch which is labelled ``START". The switch does not
- appear to be manipulable by any human hand (unless the fingers are about
- 1/16 by 1/4 inch)...
- \quoteby{{\sl Zork}}
-
- 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:^^{searchlight}
- \beginlines
- |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;|
- \endlines
- Here is a lamp which provides for ^{batteries} which will some day run down,
- though the code to actually deplete these batteries (by decrementing |time_left|
- every turn it's switched on) is omitted:^^{brass lantern}
- \beginlines
- |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;|
- \endlines
-
- \section{9}{Things to enter, travel in and push around}
-
- \quote
- ...the need to navigate a newly added river prompted the invention
- of vehicles (specifically, a boat).
- \quoteby{^{P. David Lebling}, ^{Marc Blank} and ^{Timothy Anderson}}
-
- Some objects in a game are ^|enterable|, which means that a player can
- get inside them. 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.) In practice one often
- wants to make an |enterable| thing also a |container|, or, as in this
- example, a ^|supporter|:
- \beginstt
- Object chair "dentist's chair" surgery
- with name "dentists" "chair" "couch",
- has enterable supporter;
- \endtt^^{dentist's chair}
- \medskip
-
- All the classic games have ^{vehicles} (like boats, or fork lift trucks, or
- hot air balloons) which the player can journey in, so Inform makes this
- easy. Here is a simple case:
- \beginlines
- |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;|
- \endlines^^{little red car}^^{The Prisoner}
- Actually, 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.
-
- \danger Because you might want to drive the car ``out'' of a garage,
- the ^{``out'' verb} does not make the player get out of the car. Usually
- the player has to type something like ``get out'' to make this happen,
- though of course the rules can be changed.
-
- \exercise Alter the car so that it won't go up or down stairs.
-
- \answer{Change the car's |before| to\beginlines
- | before|
- | [; Go: if (noun==d_obj or u_obj)|
- | { print "(The car will never get over those stairs.)^";|
- | rfalse;|
- | }|
- | if (car has on) "Brmm! Brmm!";|
- | print "(The ignition is off at the moment.)^";|
- | ],|
- \endlines^^{little red car}}
-
- \danger
- Objects like the car (if the hand brake is off) or, say, an antiquated
- wireless on casters, are obviously too heavy to pick up but the player
- should at least be able to push them from place to place. When the
- player tries to do this, the ^|PushDir| action is generated. Now, if
- the |before| routine returns false, the game will just say that the
- player can't; and if it returns true, the game will do nothing at all,
- guessing that the |before| routine has already printed something more
- interesting. So how does one actually tell Inform that the push
- should be allowed? The answer is that one has to do two things:
- call the ^|AllowPushDir()| routine (a library routine), and then
- return true. So, for example,
- \beginlines
- |Nearby huge_ball "huge plaster-of-paris ball"|
- | with name "huge" "plaster" "ball",|
- | description "A good eight feet across, though fairly lightweight.",|
- | initial|
- | "A huge plaster-of-paris ball rests here, eight feet wide.",|
- | before|
- | [; PushDir: AllowPushDir(); rtrue;|
- | Take, Remove: "There's a lot of plaster in an eight-foot sphere.";|
- | ],|
- | after|
- | [; PushDir:|
- | "The ball rattles about and is hard to stop once underway.";|
- | ],|
- | has static;|
- \endlines^^{plaster of paris}
-
-
- \section{10}{Living creatures and conversation}
-
- \widepoem
- To know how to live is my trade and my art.
- \poemby{^{Michel de Montaigne} (1533-1592)}{Essays}
-
- \widepoem
- Everything that can be said can be said clearly.
- \poemby{^{Ludwig Wittgenstein} (1889-1951)}{Tractatus}
-
- This rummage through special kinds of objects finishes up with the most
- sophisticated kind: living ones.
- 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:
- \medskip
- \noindent ^|Attack|
- \qquad The player is making hostile advances...
- \medskip
- \noindent ^|Kiss|
- \qquad ...or excessively friendly ones.
- \medskip
- \noindent ^|ThrowAt|
- \qquad The player asked to throw |noun| at the creature.
- \medskip
- \noindent ^|Give|
- \qquad The player asked to give |noun| to the creature...
- \medskip
- \noindent ^|Show|
- \qquad ...or just to show it.
- \medskip
- \noindent ^|Ask|
- \qquad The player asked the creature about something: |noun| holds the
- word.
- \medskip
- \noindent ^|Answer|
- \qquad The player tried either of:
- \begindisplay
- ``answer \<word> to troll"\cr
- ``troll, \<something not understood>"\cr
- \enddisplay
- In either case the variable
- |special_word|
- ^^|special word|
- is set to the dictionary entry of the first word, or
- 0 if it isn't in the dictionary, and |special_number|
- ^^|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.)
- \medskip
- \noindent ^|Order|
- \qquad On the other hand, an |Order| happens when the parser does understand
- what the player wants the creature to do: e.g., ``troll, go south".
- |action|, |noun| and |second| are set up
- as usual: in this case |action=##Go| and |noun=s_obj|, while |second=0|.
- \bigskip
-
- If the routine doesn't exist, or returns false, events will take their
- usual course. Here is a full example:
- \beginstt
- 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, Show: "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;
- \endtt^^{sullen snake}
- Of course an |animate| still has |before| and |after| routines like any
- other, so you can trap many other kinds of behaviour. (The library
- understands that, for example, an |animate| creature cannot be taken.)
-
- \danger |DefArt| is a routine which prints the short name of an object
- along with its definite article, usually ``the".
-
- Sometimes creatures should be ^|transparent|, sometimes not. Consider these
- two cases of |animate| characters, for instance:
- \item{$\bullet$} an urchin with something bulging inside his jacket pocket;
- \item{$\bullet$} a hacker who has a bunch of keys hanging off his belt.
-
- \noindent
- The hacker is |transparent|, the urchin not. That way the parser prevents
- the player from referring to whatever the urchin is hiding (even if the
- player has played the game before, and knows what is in there and what it's
- called). But the player can look at and be tantalised by the hacker's
- keys.^^{hacker and urchin}^^{urchin and hacker}
-
- \danger Another way to trap some of these actions (those which do not
- involve conversation, i.e. other than |Order|, |Answer| or |Ask|) is to
- use |before| in the ordinary way. This lets you change rules about, say,
- giving things to people in particular places. The ^|ThrowAt| action is
- also an ordinary one (for coconut shies, greenhouse windows and the like)
- but is given to |life| as well because most creatures react to it, and
- it's a convenience to have all the rules for a creature in one place.
-
- \danger A footnote about |Order|: this is another ``fake action".
- ^^{fake actions}
- 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.)
-
-
- \section{11}{Starting, moving, changing and killing the player}
-
- \quote
- There are only three events in a man's life; birth, life and death;
- he is not conscious of being born, he dies in pain and he forgets
- to live.
- \quoteby{^{Jean de la Bruy\`ere} (1645-1696)}
- \quote
- That is the road we all have to take - over
- the Bridge of Sighs into eternity.
- \quoteby{^{S\o ren Kierkegaard} (1813-1855)}
- ^^{depressed philosophers}
-
- The player normally begins in the room which |location| is set to, and
- setting |location| is the only absolute obligation on a game's ^|Initialise|
- routine. (The room may be initially dark if you so choose, or rather
- if you provide no light source.) In fact |location| could be set to a
- ^{chair} or bed just as easily if the player is to start seated or lying
- down.
- If you would like to give the player some items to begin with, ^|Initialise|
- should also |move| them to |player|.^^{player's origin}^^{initial possessions}
- \medskip
-
- To move the player about (for ^{teleportation} of some kind), two things
- must be done: to move the player object, by^^{moving the player}
- \beginstt
- move player to newroom;
- \endtt
- and also to change the ^|location| variable, which says which room to
- display on the status line:
- \beginstt
- location = newroom;
- \endtt
- 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.^^|PlayerTo|
-
- \danger
- In general |location| can be different from |parent(player)| in two ways:
- it can be ``Darkness" (that is, the special object ^|thedark|, which behaves
- somewhat like a room), or it can be the actual room while |parent(player)|
- is something the player sits inside, like (say) a jeep.
-
- \danger Calling |PlayerTo(place, 1);| will move the player without printing
- anything, and in particular without printing any room description.
- \medskip
-
- The player's whole persona can easily be changed, by setting
- \beginstt
- player.before = #r$MyNewRule;
- \endtt^^{changing the player}
- where |MyNewRule| is a new |before| rule to be applied to every action of
- the player's (or similarly for an |after| rule). For instance, if a cannon
- goes right next to the player, a period of deafness might ensue, and this
- rule could stop the |Listen| action from taking its normal course.
-
- \danger In fact a much more powerful trick is available: the |player| can
- actually become a different character in the game, allowing the real player
- at the keyboard to act through someone else.
- Calling |ChangePlayer(obj)| will transform the player to |obj|. There's
- no need for |obj| to have names like ^{``me''} or ^{``myself''}; the
- parser understands these words automatically to refer to the
- currently-inhabited |player| object. However, it must provide a |number|
- property (which the library will use for workspace). The maximum number
- of items the player can carry as that object will be its ^|capacity|. Finally,
- since |ChangePlayer| prints nothing, you may want to conclude with a |<<Look>>;|
-
- \ninepoint ^|ChangePlayer| has many possible applications. The player
- who tampers with Dr ^{Frankenstein}'s ^{brain transference machine} may
- suddenly become the Monster strapped to the table. A player who drinks
- too much wine could become a ^{`drunk player object'} to whom many different
- rules apply. The ^{``snavig'' spell} of ^{`Spellbreaker'}, which transforms
- the player to an animal like the one cast upon, could be implemented thus.
- More ambitiously, a game could have a stock of half a dozen main characters,
- and the focus of play can switch between them. A player might have a ^{team
- of four adventurers} to explore a dungeon, and be able to switch the one
- being controlled by typing the name. (In this case, an |AfterLife| routine
- -- see below -- may be needed to switch the focus back to a still-living
- member of the team after one has met a sticky end.)^^{`focus' of game}
- \tenpoint
-
- \dangerexercise In Central American legend, a sorceror can transform himself
- into a {\it ^{nagual}}, a familiar such as a spider-monkey; indeed, each
- individual has an animal self or {\it wayhel}, living in a volcanic land
- over which the king, as a jaguar, rules. Turn the player into his
- {\it wayhel}.
-
- \answer{The common man's {\it wayhel} was a lowly mouse. Since we think
- much more highly of the player:
- \beginlines
- |Object hog "Warthog" Caldera|
- | with name "wart" "hog" "warthog", description "Muddy and grunting.",|
- | number 0,|
- | initial "A warthog snuffles and grunts about in the ash.",|
- | before|
- | [; if (player==self && action~=##Go or ##Look or ##Examine)|
- | "Warthogs can't do anything as tricky as that!";|
- | ],|
- | has animate proper;|
- \endlines^^{warthog}^^{nagual}
- and we just |ChangePlayer(warthog);|. Note that this |before| rule is
- carefully written only to affect actions of the player-as-warthog.
- If the player-as-human should find and try to ``take warthog'', this
- |before| routine won't interfere.}
-
- \danger Calling |ChangePlayer(object,1);| will do the same but make the
- game print ``(as Whoever)'' during room descriptions.
-
- \medskip
- The player is still alive for as long as the variable |deadflag| is zero.
- When set to 1, the player dies; when set to 2, the player wins; and all higher
- values are taken as more ^{exotic forms of death}. Now Inform does not know
- what to call these exotica: so if they should arise, it calls the
- ^|DeathMessage| routine, which is expected to look at ^|deadflag| and
- can then print something like ``You have changed''.
-
- Many games allow reincarnation (or, as ^{David M. Baggett} points out, in
- fact ^{resurrection}). You too can allow this, by providing an ^|AfterLife|.
- This routine gets the chance to do as it pleases before any ``You are
- dead'' type message appears, including resetting |deadflag| back to 0 -
- which causes the game to proceed in the normal way, rather than end.
- |AfterLife| routines can be tricky to write, though, because the game
- has to be set to a state which convincingly reflects what has happened.
- (For instance, try collapsing the bridge in ^{`Advent'} by leading the
- bear across it, then being reincarnated and returning to the scene.)
-
-
- \section{12}{Printing out names of objects}
-
- \poem
- And we were angry and poor and happy,
- And proud of seeing our names in print.
- \poemby{^{G. K. Chesterton} (1874-1936)}{A Song of Defeat}
-
- Inform has a special form of print command for this, ^|print object|, but
- {\it do not use it}. Instead, call one of the following library routines:
- \smallskip{
- \settabs 8 \columns
- \+ &^|DefArt(obj)| &&& Print the object with its definite article\cr
- \+ &^|CDefArt(obj)| &&& The same, but capitalised\cr
- \+ &^|InDefArt(obj)| &&& Print the object with indefinite article\cr
- \+ &^|PrintShortName(obj)| &&& Print the object's short name alone\cr
- }
- \medskip
-
- The ^{indefinite article} for an object is held in the property ^|article|
- and is assumed to be `a' if none is declared. That means that if the
- short name starts with a vowel, you need to set it to `an'. But |article|
- offers much more amusement:
- \begindisplay
- a platinum bar, an orange balloon, your Aunt Jemima,\cr
- some bundles of reeds, far too many marbles\cr
- \enddisplay
- are all examples of |article|s.
-
- Definite articles are always ``the'' unless an object is given the
- attribute |proper|, which makes it a ^{proper noun} and so not take a
- ^{definite article} at all. Thus
- \begindisplay
- the platinum bar, Aunt Jemima, Elbereth\cr
- \enddisplay
- are all printed by |DefArt|, the latter two being ^|proper|.
-
- As we shall later see, changing the short name is easy.
-
- \dangerexercise Why does
- \begintt
- print CDefArt(obj), " falls to the floor.^";
- \endtt
- seem to work, but mysteriously print the number 1 after the name of the
- object?
-
- \answer{Because |CDefArt(obj)| is a function call which, as it happens,
- returns the value true, or 1 (not that this signifies anything), and
- |print| thinks it is printing out a number.}
-
- \ddanger The reason |print object| is unsafe is that it prints the real,
- ``hardware and unchangeable'' short name, whereas we want everything to
- work nicely when the user changes the short name of an object in play:
- so the library routines almost all indirect through |PrintShortName|
- (except in two cases to do with |ChangePlayer|, since the current
- player's short name is always ``yourself'').
-
- \section{13}{Classes of objects}
-
- In most games there are groups of objects with certain rules in common.
- As well as individual objects, Inform allows one to define
- ^{classes} in almost exactly the same way. The only
- difference between the layout of a class and object definition is that
- a class has no short name or initial location (since it does not correspond
- to a single real item). For example:
- \beginlines
- | 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;|
- \endlines^^{treasure 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. So
- \beginstt
- 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";
- \endtt^^{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.
-
- \danger |depositpoints| isn't a library property: it's one defined in the
- game this example is drawn from, the ^{`Advent'} example game.
-
- We could also, for instance, have:
- \beginlines
- |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;|
- \endlines^^{valuable cake}
- Now the cake has two |after| rules. Both apply, but the rule in the cake
- itself takes ^{precedence}, i.e., happens first.
-
- \danger
- An object can inherit from several classes at once. Moreover, a class can
- itself inherit from other classes, so one can easily make a class for
- ``like Treasure but with only 8 |depositpoints|''.
-
- \ddanger
- The ^|class| field of an object definition contains a list of classes,
- \begindisplay
- |class| $C_1$ ... $C_n$
- \enddisplay^^{inheritance}
- in which case the object inherits first from $C_1$, then from $C_2$
- and so on. $C_2$ over-rides $C_1$ and so on along the line. These
- classes may well disagree with each other, so the order matters. If $C_1$
- says |depositpoints| is 5, $C_3$ says it is 10 but the object
- definition itself says 15 then the answer is 15.
-
- \ddanger
- With some properties, the value is not replaced but added to: this
- is what happened with |after| above. These
- properties are those which were declared as ^|additive|, e.g. by
- \begintt
- Property additive before $ffff;
- \endtt
- For instance, the standard Inform properties |name| and |before| are
- both additive. So we could add |name "treasure",| to the properties
- in the class definition for |Treasure|, and then all objects of that
- class would respond to the word ``treasure'', as well as their own
- particular names.
-
-
- \section{14}{Daemons and the passing of time}
-
- \quote
- Some, such as Sleep and Love, were never human. From this
- class an individual daemon is allotted to each human being
- as his `witness and guardian' through life.
- \poemby{^{C. S. Lewis} (1898-1963)}{The Discarded Image}
- \widepoem
- Some daemon stole my pen (forgive th' offence)
- And once betrayed me into common sense.
- \poemby{Alexander Pope (1688-1744)}{The Dunciad}
-
- 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 for moving about, throwing
- knives at the player and other pleasantries.^^{daemons}
-
- Each object can have a ^|daemon| of its own. This is set going, and stopped
- again, by calling the (library) routines
- \begintt
- StartDaemon(the-object);
- StopDaemon(the-object);
- \endtt
- Once active, the |daemon| property of the object is called as a routine
- each turn. Daemons are often started by a game's |Initialise| routine,
- and active throughout.^^|StartDaemon|^^|StopDaemon|
-
- \danger 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.
- Actually this is very useful, as it means daemons can be used for
- `^{tidying-up operations}', or for the consequences of the player's actions
- to catch up with him.
-
- Daemons often run a fair amount of code. (There are plenty of good
- examples in ^{`Toyshop'} and ^{`Advent'}.) They shouldn't be ridiculously
- slow if they will run more than once. And some daemons so sit in
- the background for enormously long times: for instance, the daemon in
- ``Advent'' which hides until the player has managed to get all the
- treasures, then pounces. Such daemons ought to
- check their condition and return as quickly as possible if it fails.
-
- \exercise Many games contain ^{`wandering monsters'}, characters who walk
- around the map (usually hand-coded and not moving far abroad). Use a daemon
- to implement one who wanders as freely as the player, like the
- ^{thief in `Zork I'}^^{`Zork I'}.
-
- \answer{This is a crude implementation, for brevity (the real Zork I
- thief has an enormous stock of attached messages).^^{thief in `Zork I'}
- \beginlines
- |Object thief "thief" Danger_Zone|
- | with name "thief",|
- | each_turn "^The thief growls menacingly.",|
- | daemon|
- | [ i p j n k;|
- | if (random(3)~=1) rfalse;|
- | p=parent(thief);|
- | objectloop (i in compass)|
- | { j=p.(i.door_dir);|
- | if (j>player && j<=top_object && j hasnt door) n++;|
- | }|
- | if (n==0) rfalse;|
- | k=random(n); n=0;|
- | objectloop (i in compass)|
- | { j=p.(i.door_dir);|
- | if (j>player && j<=top_object && j hasnt door) n++;|
- | if (n==k)|
- | { move self to j;|
- | if (p==location) "^The thief stalks away!";|
- | if (j==location) "^The thief stalks in!";|
- | rfalse;|
- | }|
- | }|
- | ];|
- \endlines
- This thief walks at random and cannot pass through doors, bridges and the like
- (because these may be locked or have rules attached); it's only a first
- approximation, and in a good game one should occasionally see the thief do
- something surprising, such as open a secret door.}
-
- \exercise
- Use a ^{background daemon} to implement a system of ^{weights}, so
- that the player can only carry a certain weight before her strength gives
- out and she is obliged to drop something. It should allow for feathers to
- be lighter than lawn-mowers.
-
- \answer{First define a new property for object weight:^^{weights}
- \beginlines
- |Property weight 10;|
- \endlines
- (10 being an average sort of weight). Containers weigh more when
- they hold things, so we will need:
- \beginlines
- |[ WeightOf obj t i;|
- | t = obj.weight;|
- | objectloop (i in obj) t=t+WeightOf(i);|
- | return t;|
- |];|
- \endlines
- Now for the daemon which monitors the player's fatigue:^^{fatigue daemon}
- \beginlines
- |Object weigher "weigher"|
- | with number 500,|
- | time_left 5,|
- | daemon|
- | [ w s b bw;|
- | w=WeightOf(player)-100-player.weight;|
- | s=self.number; s=s-w; if (s<0) s=0; if (s>500) s=500;|
- | self.number = s;|
- | if (s==0)|
- | { bw=-1;|
- | objectloop(b in player)|
- | if (WeightOf(b)>bw) { bw=WeightOf(b); w=b; }|
- | print "^Exhausted with carrying so much, you decide \|
- | to discard "; DefArt(w); print ": "; <<Drop w>>;|
- | }|
- | w=s/100; if (w==self.time_left) rfalse;|
- | if (w==3) print "^You are feeling a little tired.^";|
- | if (w==2) print "^You possessions are weighing you down.^";|
- | if (w==1) print "^Carrying so much weight is wearing you out.^";|
- | self.time_left = w;|
- | ];|
- \endlines
- Notice that items are actually dropped with |Drop| actions: one of them
- might be, say, a wild boar, which would bolt away into the forest when
- released. The daemon tries to drop the heaviest item. (Obviously a little
- improvement would be needed if the game contained, say, an un-droppable
- but very heavy ball and chain.) Now the daemon is going to run every turn
- forever, but needs to be started: so put |StartDaemon(weigher);| into the
- game's |Initialise| routine.}
- \medskip
-
- 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| going at the same time.)
- A timer is started with
- \begintt
- StartTimer(the-object, time);
- \endtt^^{timers}^^|StartTimer|
- in which case it will ``go off" (alarm clock-style) in the given number of
- turns. This means that its |time_out|
- ^^|time out|
- property will be called (as a routine), once and once only, when the time comes.
-
- It can be deactivated (so that it will never go off) by calling
- \begintt
- StopTimer(the-object);
- \endtt^^|StopTimer|
-
- A timer is {\sl required} to provide a |time_left| property, to hold the
- amount of time left. If it doesn't, the library will print an error message
- at run-time. You can alter |time_left| yourself, but setting it to 0 does
- not stop the timer: use the routine |StopTimer| for that.
-
- \danger In early releases of the library, a |daemon| needed a |time_left|
- as well, which was illogical and a nuisance: anyway, it's no longer the case.
-
- \danger Normally, you can only have 32 timers or daemons active at the same
- time as each other (there may be any number of inactive ones). But this
- limit is easily raised: just define the constant |MAX_TIMERS|
- ^^|MAX TIMERS|
- to some larger value, putting the definition in your code before the
- |Parser| file is included.
-
- \medskip
- There is yet a third form of timed event. If a room provides an |each_turn|
- routine, then this will be called in each turn when the player is in it;
- if an object provides |each_turn|, this is called whenever the object is
- nearby.^^|each turn| For instance, a ^{radio} might blare out music
- whenever it is nearby; a ^{sword} might glow whenever monsters are nearby;
- or a ^{stream} running through several forest locations might occasionally
- float objects by.
-
- `Each turn' is entirely separate from daemons and timers. Although an object
- can't have both a timer and a daemon at the same time, it can have an |each_turn|
- at the same time, and this is quite useful, especially to run creatures.
- An ^{ogre with limited patience} can therefore have an |each_turn| routine
- which worries the player (``The ogre stamps his feet angrily!'', etc.)
- while also having a timer set to go off when his patience runs out.
-
- \danger `Nearby' actually means `in scope', a term which will be properly
- explained later. The idea is based on ^{line of sight}, which works well
- in most cases.
-
- \ddanger But it does mean that the radio will be inaudible when shut up
- inside most containers - which is arguably fair enough - yet audible when
- shut up inside transparent, say glass, ones. You can always change the
- scope rules using an |InScope| routine to get around this. In case you
- want to tell whether scope is being worked out for ordinary parsing reasons
- or instead for |each_turn| processing, look at the |et_flag| variable
- (0 in the former case, 1 in the latter). Powerful effects are available
- this way - you could put the radio in scope within all nearby rooms so as
- to allow sound to travel. Or you could make a thief audible throughout
- the maze he is wandering around in, as in ^{`Zork I'}.
- ^^|et flag|^^{audibility}^^{earshot}^^{thief in `Zork I'}
- \bigskip
-
- The library also has the (limited) ability to keep track of ^{time of day}
- as the game goes on.
-
- If you're writing a game with the time instead of the score and turns on the
- status line, you can set the time by
- \begindisplay
- |SetTime(| 60$\times$\<hours>$+$\<minutes>|,| rate |);|
- \enddisplay^^|SetTime|
- The current time is held in the variable |the_time|
- ^^|the time|
- and runs on a 24-hour clock. The |rate| controls how rapidly time is moving:
- a |rate| of 0 means it is standing still (that is, that the library doesn't
- change it: your routines still can). A positive |rate| means that that many
- minutes pass between each turn; and negative |rate| means that many turns
- pass between each minute.
-
- The time still won't appear on the game's status line unless you set
- \begintt
- Statusline time;
- \endtt^^|Statusline|
- as a directive somewhere in your code. And remember to start off the clock
- by calling |SetTime| in your ^|Initialise| routine, if you're going to use
- it.
-
- \exercise How could you make your game take notice of the time passing
- midnight, so that the day of the week could be nudged on?
-
- \answer{Either set a daemon to watch for |the_time| suddenly dropping, or
- put such a watch in the game's |TimePasses| routine.}
-
- \ninepoint
- \danger Exactly what happens at the end of each turn is:^^{time sequence}
- \item{1.} The turns counter is incremented.
- \item{2.} The 24-clock is moved on.
- \item{3.} Daemons and timers are run (in no guaranteed order).
- \item{4.} |each_turn| takes place for the current room, and then for
- everything nearby (that is, in scope).
- \item{5.} The game's global |TimePasses()| routine is called.
- \item{6.} Light is re-considered (it may have changed as a result
- of events since this time last turn).
- \par\noindent
- The sequence is abandoned if at any stage the player
- dies or wins.\tenpoint
-
- \dangerexercise Suppose the player is magically suspended in mid-air,
- but that anything let go of will fall out of sight. The natural way
- to code this is to use a daemon which gets rid of anything it finds
- on the floor (this is better than just trapping |Drop| actions because
- objects might end up on the floor in many different ways). Why is
- using |each_turn| better?^^{mid-air location}
-
- \answer{Because you don't know what order daemons will run in. A
- `fatigue' daemon which makes the player drop something might come
- after the `mid-air' daemon has run for this turn. Whereas |each_turn|
- happens after daemons and timers have run their course, and can fairly
- assume no further movements will take place this
- turn.^^{daemon running order}}
-
- \exercise How would a game work if it involved a month-long
- ^{archaeological dig}, where anything from days to minutes pass between
- successive game turns?
-
- \answer{It would have to provide its own code to keep track of time,
- and it can do this by providing a |TimePasses()| routine. Providing
- ``time'' or even ``date'' verbs to tell the player would also be a
- good idea.}
-
- \section{15}{Adding verbs and grammar to the parser}
-
- \poem
- Grammar, which can govern even kings.
- \poemby{^{Moli\`ere} (1622-1673)}{Les Femmes savantes}
- \quote
- Language disguises thought... The tacit conventions on which
- the understanding of everyday language depends are enormously
- complicated.
- \poemby{^{Ludwig Wittgenstein}}{Tractatus}
-
- The next few sections will delve deep into the ^{parser}. Inform goes to
- a great deal of trouble to make the parser as ``open-access'' as possible,
- because a parser cannot ever be general enough for every game without
- being extremely modifiable. So there are very many ways to customise
- the Inform parser, hopefully without the user needing to understand much
- about how it works (because this is quite a long story).
-
- The first essential requirement of any parser is to accept the addition of
- the grammar for a new verb. In Inform code, grammar should appear at the end
- of the source code for a game, and of course most of it is written out
- in the |Grammar| header file, which all games using the library include.
- After this inclusion, you can add extras.^^{making grammar}
-
- The directive for this is called ^|Verb|, and here's a typical example: some
- of the library's grammar for ``take":^^{``take'' verb}
- \beginlines
- |Verb "take" "get" "pick" "lift"|
- | * "out" -> Exit|
- | * multi -> Take|
- | * multiinside "from" noun -> Remove|
- | * "in" noun -> Enter|
- | * multiinside "off" noun -> Remove|
- | * "off" held -> Disrobe|
- | * "inventory" -> Inv;|
- \endlines
- This declares a verb, for which ``take", ``get" and so on are synonyms, and
- which can take seven different courses.
-
- \danger It should be noted that these really are ^{synonyms}: the parser thinks
- ``take" and ``get" are exactly the same. Sometimes this has odd results,
- so that although ``get in bed" is correctly understood as a request to enter
- the bed, ``take in washing" is misunderstood as a request to enter the
- washing. You could either get around this by writing separate grammars for
- the two nearly-synonyms, or can cheat and see if the variable
- |verb_word=='take'| or |'get'|. Mostly, though, you don't mind if a few
- odd things are accepted by the parser: what matters more is that sensible
- things are not rejected by it.
-
- When it ploughs through what the player has typed, the parser tries to match
- each line in turn, starting at the top. The first line will only be matched
- if the player has typed something like ``get out". The second line is more
- interesting: it allows the player to type a single object or a list of
- objects. So the second line could be matched by^^{grammar lines}
- \begindisplay
- take the banana\cr
- get all the fruit except the apple\cr
- \enddisplay
- There need be no grammar at all after the verb: for example, a grammar for
- ``inventory" could be as simple as
- \begintt
- Verb "invent" "inv" "i"
- * -> Inv;
- \endtt
- After the ^|->| in each line is the name of an action. This is how actions
- are defined: they are the names which appear in grammar lines like this
- one. Remember that if you do create an action this way, you also have
- to write a routine to execute the action, even if it's one which doesn't
- do very much. For instance:
- \begintt
- [ XyzzySub; "Nothing happens."; ];
- Verb "xyzzy" * -> Xyzzy;
- \endtt
- will make a new magic-word verb ``xyzzy'', which always says ``Nothing
- happens'' - always, that is, unless some |before| rule gets there first,
- as it might do in certain magic places. (The name of the routine is
- always the name of the action with |Sub| appended.)^^{``xyzzy'' verb}
-
- The new action |Xyzzy| is treated exactly like all the standard Inform
- actions: |##Xyzzy| gives its action number, and you can write |before|
- and |after| rules for it in |Xyzzy:| fields just as you would for, say,
- |Take|.
-
- The individual words in the grammar (after the |*| and before the |->|) are
- called ``tokens". In increasing order of complexity, this is the complete
- list:^^{grammar tokens}^^{tokens}
- {\smallskip\baselineskip=7 true mm\settabs 8\columns
- \+& |"|\<word>|"| && that literal word only\cr
- \+& \cstok{noun} && any object in scope\cr
- \+& \cstok{held} && object held by the player\cr
- \+& \cstok{creature} && an object in scope which is |animate|\cr
- \+& \cstok{multi} && one or more objects in scope\cr
- \+& \cstok{multiheld} && one or more held objects\cr
- \+& \cstok{multiexcept} && one or more in scope, except the other\cr
- \+& \cstok{multiinside} && one or more in scope, inside the other\cr
- \+& \<attribute> && any object in scope which has the attribute\cr
- \+& |noun = |\<Routine> && any object in scope passing the given test\cr
- \+& |scope = |\<Routine> && an object in this definition of scope\cr
- \+& \cstok{special} && {\it any} single word or number\cr
- \+& \cstok{number} && a number only\cr
- \+& \<Routine> && any text accepted by the given routine\cr
- \smallskip\par\noindent}
- (Tokens like \cstok{noun} are so written here to avoid confusion: there is
- a variable called |noun| too, which is quite different.)
- \par
- In the case of |noun = |\<Routine>, the parser applies the following test:
- the variable |noun| is set to the object in question, and the routine is
- called. If it returns true, the parser accepts the object, and otherwise
- it rejects it.
- \par \cstok{number} matches any decimal number from 0 upwards (though it
- rounds off large numbers to 10000), and also matches the numbers ``one''
- to ``twenty'' written in English.
- \par The token \cstok{special} is now obselete.
- \par For now, we shall take ``in scope" to mean ``visible to the player". It
- is quite important in some cases to know exactly what this means, so
- a better definition will be given later.
- ^^{noun token}^^{held token}^^{multiheld token}^^{multiexcept token}
- ^^{creature token}^^{special token}^^{number token}
-
- The \cstok{held} token is convenient for two reasons. Firstly, many actions
- only sensibly apply to things being held (such as |Eat| or |Wear|), and
- using this token in the grammar you can make sure that the action is
- never generated by the parser unless the object is being held. That
- saves on always having to write ``You can't eat what you're not holding"
- code. Secondly, suppose we have grammar
- \begintt
- Verb "eat"
- * held -> Eat;
- \endtt
- and the player types
- \begindisplay
- eat the banana
- \enddisplay
- while the ^{banana} is plainly in view, on a shelf, say. It would be
- rather petty of the game to refuse on the grounds that the banana is
- not being held. So the parser will generate a |Take| action for the
- banana and then, if the |Take| action succeeds, an |Eat| action. (Notice
- that the parser does not just pick up the object, but issues an action
- in the proper way - so if the banana had rules making it too slippery
- to pick up, it won't be picked up.)
-
- The \cstok{multi-} tokens indicate that a list of one or more objects can
- go here. (The parser works out all the things the player has asked
- for, sorting out plural nouns and words like ``except" by itself, and
- then generates actions for each one.) \cstok{multiexcept} is provided
- to make commands like
- \begindisplay
- put everything in the rucksack
- \enddisplay
- parsable: the ``everything" is matched by all of the player's
- possessions except the ^{rucksack} (this stops the parser from generating
- an action to put the rucksack inside itself). Similarly
- \cstok{multiinside} handles:
- \begindisplay
- remove everything from the cupboard
- \enddisplay
- A restriction here is that a single grammar line can only contain
- one \cstok{multi-} token: so ``hit everything with everything" can't be
- parsed (straightforwardly: you can parse anything with a little more
- effort). On the whole, this is no bad thing.
-
- The reason not all nouns can be multiple in the first place is that
- too helpful a parser makes too easy a game. You probably don't want
- to allow something like
- \begindisplay
- unlock the mystery door with all the keys
- \enddisplay
- - you want the player to suffer having to try them one at a time,
- or else to be thinking. (Of course if you do want to allow this it
- is easy enough to change the grammar: the point is that you have the
- option.)
- \medskip
-
- We can also sort out objects according to attributes that they have:
- \begintt
- Verb "use" "employ" "utilise"
- * edible -> Eat
- * clothing -> Wear
- ...and so on...
- * enterable -> Enter;
- \endtt
- and this is how attributes are used as tokens. (The library grammar
- does not contain such an ^{appallingly convenient verb}!)
-
- Since you can define your own attributes, it is therefore easy to
- make a grammar line which matches only your own class of object.
-
- \danger A footnote: the \cstok{creature} token is thus equivalent to
- writing |animate|; but it dates back to the earliest days of Inform,
- and does no harm.
-
- Sometimes even that isn't flexible enough. Here is a verb, ``free",
- which should only apply to animal kept in a cage:
- \begintt
- [ CagedCreature;
- if (noun in wicker_cage) rtrue; rfalse;
- ];
- Verb "free" "release"
- * noun=CagedCreature -> FreeAnimal;
- \endtt^^{``free'' verb}
- So that only nouns which pass the |CagedCreature| test are allowed.
- (The |CagedCreature| routine can appear anywhere in the code, though
- it's tidier to keep it nearby.)
- \medskip
-
- So far, all the tokens were to tell the parser which of the objects in scope
- were acceptable. Exactly what `in scope' means will be gone into later,
- and so will the powerful |scope=...| token. Here we next want the parser to
- match things other than names of objects and prepositions like ``into".
- The simplest useful case is of numbers, for example:
- \begintt
- Verb "type"
- * number -> TypeNum;
- \endtt
- so that the TypeNum action will happen if the player types ``type 504''
- or ``type seventeen''.
-
- \exercise (A beautiful feature stolen from ^{David M. Baggett}'s game
- ^{`The Legend Lives'}, which uses it to great effect.) Some games produce
- ^{footnotes} every now and then. Arrange matters so that these are
- numbered |[1]|, |[2]| and so on in order of appearance, to be read by the
- player when ``footnote 1'' is typed.
-
- \answer{^^{footnotes}
- \beginlines
- |Constant MAX_FOOTNOTES 10;|
- |global footnotes_seen data MAX_FOOTNOTES;|
- |global footnote_count;|
- |[ Note n i pn;|
- | for (i=0:i<footnote_count:i++)|
- | if (n==footnotes_seen->i) pn=i;|
- | if (footnote_count==MAX_FOOTNOTES) "** MAX_FOOTNOTES exceeded! **";|
- | if (pn==0) { pn=footnote_count++; footnotes_seen->pn=n; }|
- | print " [",pn+1,"]";|
- |];|
- |[ FootnoteSub n;|
- | if (noun>footnote_count)|
- | { print "No footnote [",noun,"] has been mentioned.^"; rtrue; }|
- | if (noun==0) "Footnotes count upward from 1.";|
- | n=footnotes_seen->(noun-1);|
- | print "[",noun,"] ";|
- | if (n==0) "This is a footnote.";|
- | if (n==1) "D.G.REG.F.D is inscribed around English coins.";|
- | if (n==2) "~Jackdaws love my big sphinx of quartz~, for example.";|
- |];|
- ||
- |Verb "footnote" "note" * number -> Footnote;|
- \endlines
- And then call, for instance, |Note(1);| to refer in the game to
- the ``English coins'' footnote.}
-
- \danger
- In fact, you're allowed to provide your own ^{number-parsing} routine, so
- many sneaky possibilities are open here - Roman numerals, coordinates
- like ``J4", long telephone numbers (which would be too large to fit into
- integer variables in Inform), understanding English numbers and so on.
- This takes the form
- \begintt
- [ ParseNumber buffer length;
- ...returning 0 if no match is made, or the number otherwise...
- ];
- \endtt
- and examines the supposed ``number" held at the byte address |buffer|,
- which is a row of ASCII characters of the given |length|. If you declare
- a ^|ParseNumber| routine, then the parser will always try this first when
- trying to decode something as a number (and if it fails will fall back
- on its own number-parsing routine).
- \medskip
-
- \ddanger For not-very-good internal reasons, |ParseNumber| can't return
- 0 to mean the number zero. Probably ^{``zero''} won't be needed too often,
- but if it is you can always return some value like 1000 and code the
- verb in question to understand this as 0.
-
- \ddanger You can give a routine to parse anything:
- \begintt
- [ 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;
- ];
- \endtt
- will detect ^{low numbers in French}, and could be used by something like:
- \begintt
- Verb "type"
- * French -> TypeFrenchNum
- * number -> TypeNum;
- \endtt
- The specification for such a routine 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
- \begindisplay
- -1\quad if the user's input isn't understood,\cr
- 1\quad if there is a numerical value resulting, or\cr
- $n$\quad if object $n$ is understood.\cr
- \enddisplay
- In the case of a number, the actual value should be put into the variable
- |parsed_number|.^^|parsed number|
- 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 {\it after} what the routine understood. (Since ^|NextWord| moves
- |wn| on by one each time it is called, this happens automatically unless
- the routine has read too far.)
- \medskip
-
- That's all about tokens: back to verb definition commands, because
- some of the above examples are slightly contrived - 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, and for this the ^|Extend| directive is provided:
- \begintt
- Extend "push"
- * Button -> PushButton;
- \endtt
- A routine called |Button| could then be written to accept things like
- \begindisplay
- ``button j16",\quad ``d11",\quad ``a5 button".
- \enddisplay
- 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.
-
- \ddanger Actually, there's a better way to provide these buttons, so that
- they work with any verb automatically, and that's to make a button object
- with a |parse_name| routine which cunningly extracts the button number
- as it parses: see the game ^{`Balances'} for an example of this.
-
- 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
- \begintt
- * multi -> Take
- \endtt
- quite early on. So if you want to add a grammar line which diverts
- ``take something-edible" to a different action, like so:
- \begintt
- * edible -> Eat
- \endtt
- 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
- \begintt
- Extend "take" first
- * edible -> Eat;
- \endtt
- You might even want to actually replace the old grammar completely, not
- just add a line or two. For this, use^^{replacing grammar}
- \begintt
- Extend "push" replace
- * Button -> PushButton;
- \endtt
- and now ``push" can be used only in this way. To sum up, |Extend| can take
- three keywords:
- {\ninepoint\smallskip\settabs 8\columns
- \+& ^|replace| && completely replace the old grammar with this one\cr
- \+& ^|first| && insert the new grammar at the top of the old one\cr
- \+& ^|last| && insert the new grammar at the bottom of the old one\cr
- \smallskip}\par\noindent
- with |last| being the default (which doesn't need to be said explicitly).
-
- \danger Another convenience is to define ^|meta| verbs - verbs which are not
- really part of the game, such as ``save'', ``score'' and ``quit''.
- (You probably want to add your own debugging commands as meta-verbs: if you
- make them ordinary verbs, then they may work most of the time, but might be
- interfered with by game rules, and will take up ``game time".)
- To declare a verb as |meta|, just add the word after the command.
- For instance, the library defines
- \begintt
- Verb meta "score"
- * -> Score;
- \endtt^^{``score'' verb}
- The parser will match the grammar exactly in the normal way, but treats
- the resulting action as outside the game - taking no time up, and
- possible at any moment.
-
- \ddanger There are (a few) times when verb definition commands are not
- enough. For example, in the original ^{`Advent'} (or ^{`Colossal Cave'}),
- the player could type the name of a not-too-distant place which had
- previously been visited, and be taken there. There are several ways to code
- this - say, with 60 rather similar verb definitions, or with a single
- ``travel" verb which has 60 synonyms, whose action routine looks at the
- parser's |verb_word| variable to see which one was typed - but here's
- another. The library will call the ^|UnknownVerb| routine (if you provide one)
- when the parser can't even get past the first word. This has two options:
- it can return false, in which case the parser just goes on to complain as it
- would have done anyway. Otherwise, it can return a verb word which is
- substituted for what the player actually typed. Here is a foolish example:
- \begintt
- [ UnknownVerb w;
- if (w=='shazam') { print "Shazam!^"; return 'inventory'; }
- rfalse;
- ];
- \endtt^^{``shazam'' verb}^^{flexible verbs}
- which responds to the magic word ``shazam" by printing |Shazam!| and then,
- rather disappointingly, taking the player's inventory. But in the example
- above, it could be used to look for the word |w| through the locations of
- the game, store the place away in some global variable, and then return |'go'|.
- The |GoSub| routine could then be fixed to look at this variable.
-
- \ddangerexercise Why is it usually a bad idea to print text out in an
- |UnknownVerb| routine?
-
- \answer{Because the parser might go on to reject the line it's working on:
- for instance, if the player typed ``inventory splurge'' then the message
- ``Shazam!'' followed by a parser complaint will be somewhat unedifying.}
-
- \ddanger If you allow a flexible collection of verbs (say, names of
- spells or places) then you may want a single `dummy' verb to stand for
- whichever is being typed. This may make the parser produce strange
- questions because it is unable to sensibly print the verb back at the
- player, but you can fix this using the ^|PrintVerb| entry point (see
- the Appendix). See the exercise below.^^{parser questions}
-
- \dangerexercise A tricky one: code a spaceship whose control panel has five
- sliding controls, each of which can be set to a numerical value, so that
- the game looks like:^^{spaceship control panel}
- \beginlines
- |>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 six|
- |You set slide number 4 to the value 6.|
- \endlines
-
- \answer{Here goes: we could implement the buttons 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.^^{spaceship control panel}
- \beginlines
- |[ 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;|
- \endlines}
-
- \ddangerexercise An even trickier one: write a parsing routine which will
- accept any amount of text (including spaces, full stops and commas)
- between double-quotes as a single token.^^{parsing quoted strings}
-
- \answer{^^{parsing quoted strings}
- The ^{blackboard} code in ^{`Toyshop'} contains just such a routine:
- \beginlines
- |Global from_char; Global to_char;|
- |[ QuotedText i j f;|
- | i = parse->((++wn)*4-3);|
- | if (buffer->i=='"')|
- | { for (j=i+1:j<=(buffer->1)+1:j++)|
- | if (buffer->j=='"') f=j;|
- | if (f==0) return -1;|
- | from_char = i+1; to_char=f-1;|
- | if (from_char>to_char) return -1;|
- | while (f> (parse->(wn*4-3))) wn++; wn++;|
- | return 1;|
- | }|
- | return -1;|
- |];|
- \endlines^^{quoted text}
- Note that in the case of success, the word marker |wn| is moved beyond the
- last word accepted (since the Z-machine automatically tokenises
- a double-quote as a single word). The routine then tells the parser it
- has parsed a number, which is a white lie. What it actually does is to
- record the byte positions where the quoted text starts and finishes in
- the raw text |buffer| so that an action routine can easily extract the
- text and use it later. (Note that |""| with no text inside is not
- matched by this routine but only because the last |if| statement throws
- out that one case.)^^{double-quote}^^{tokenisation}}
-
- \ddangerexercise And another: implement the Crowther and Woods feature
- of moving from one room to another by typing its name, discussed above,
- using a dummy verb and without using |Replace| to change any library
- routines.^^{named rooms}
-
- \answer{^^{named rooms}
- Define two properties:
- \beginlines
- |Property place_name;|
- |Property long to_places;|
- \endlines
- The scheme will work like this: a named room should have the |place_name|
- property set to a single dictionary word; say, the Bedquilt cave could
- be called |'bedquilt'|. Then in any room, a list of those other rooms
- which can be moved to in this way should appear in the |to_places| entry.
- For instance,
- \beginlines
- |to_places Bedquilt Slab_Room Twopit_Room;|
- \endlines
- Now the code: see if a not-understood verb is a place name of a nearby room,
- and if so store that room's object number in |goto_room|, converting
- the verb to a dummy.
- \beginlines
- |Global goto_room = 0;|
- |[ UnknownVerb word p i;|
- | p = location.&to_places; if (p==0) rfalse;|
- | for (i=0:(2*i)<location.#to_places:i++)|
- | if (word==(p-->i).place_name)|
- | { goto_room = p-->i; return 'go#room';|
- | }|
- | rfalse;|
- |];|
- |[ PrintVerb word;|
- | if (word=='go#room')|
- | { print "go to "; PrintShortName(goto_room); rtrue; }|
- | rfalse;|
- |];|
- \endlines
- (The supplied |PrintVerb| is icing on the cake: so the parser can
- say something like ``I only understood you as far as wanting to go to
- Bedquilt.'' if need be.) It remains only to put in code
- and grammar for the ^{dummy verb}:
- \beginlines
- |[ GoRoomSub;|
- | if (goto_room hasnt visited) "But you have never been there.";|
- | PlayerTo(goto_room);|
- |];|
- |Verb "go#room" * -> GoRoom;|
- \endlines
- Note that if you don't know the way, you can't go there! A purist might
- prefer instead to not recognise the name of an unvisited room, back at
- the |UnknownVerb| stage, to avoid the player being able to deduce names
- of nearby rooms from this `error message'.}
-
-
- \section{16}{Scope and what you can see}
-
- \quote
- He cannot see beyond his own nose. Even the fingers he outstretches
- from it to the world are (as I shall suggest) often invisible to him.
- \quoteby{^{Max Beerbohm} (1872-1956), of ^{George Bernard Shaw}}
- \poem
- Wherefore are these things hid?
- \poemby{^{William Shakespeare} (1564-1616)}{Twelfth Night}
-
- Time to say what ``in scope" means. This definition is one of the most
- important algorithms in the game, although it is buried inside the parser,
- because it decides what the player is allowed to refer to: so here it is
- in full. The following are in scope:^^{scope}^^{in scope}
- \begindisplay
- the player's immediate possessions;\cr
- the 12 compass directions;\cr
- {\bf if} there is light, the objects in the same place as the player.\cr
- \enddisplay
- {\par\narrower In addition, if an object is in scope then its immediate
- possessions are in scope, {\bf if} it is ^{`see-through'}, which means that:}
- \begindisplay
- the object has |supporter|, {\bf or}\cr
- the object has |transparent|, {\bf or}\cr
- the object is an |open| |container|.\cr
- \enddisplay
-
- The definition of when there is light will be gone into in the next section.
-
- \danger Many things are still in scope in a dark room - so the player can
- still turn a lamp on if it's being carried. On the other hand, a player who
- puts the lamp on the ground and turns it off then loses the ability to
- turn it back on again, because it is out of scope. (This can be changed;
- see below.)^^{darkness}
-
- \danger The compass direction objects make sense as objects. The player can
- always type something like
- \begindisplay
- attack the south wall
- \enddisplay
- (and a |before| rule for the room in question could make something
- unusual happen as a result). The compass directions are visible in the
- dark, as otherwise the player could not still walk around.
-
- \danger The parser applies scope rules to other people too, not just the
- player. Thus ``dwarf, drop sword'' will be accepted even if the sword is
- invisible to the player provided it is visible to the dwarf.
-
- \danger Items with the ^|concealed| attribute may be concealed from
- ordinary descriptions - but the parser still sees them: they are still in
- scope. (If you want things to be both concealed and unreferrable-to,
- put them somewhere else!)
-
- \ddanger Actually, the above definition is not quite right, because
- the compass ^{directions} are not in scope when the player asks for a plural
- number of things, like ``take all the knives". (This makes some of the
- parser's plural algorithms run faster.) Also, for a \cstok{multiexcept}
- token, the other object is not in scope; and for a \cstok{multiinside} token,
- only objects in the other object are in scope. This makes ``take everything
- from the cupboard'' work in the natural way.
- \medskip
-
- The rest of this section is about how to change the scope rules. As usual
- with Inform, you can change them globally, but it's more efficient and
- safer to do so only locally.
-
- A typical example: how do we allow the player to ask questions like
- the traditional
- ^{``what is a grue''}^^{grues}^^{questions}^^{asking questions}?
- The ``grue'' part ought to be parsed as if it were a noun, so that
- we could distinguish between, say, a ``garden grue'' and a ``wild grue''.
- So it isn't good enough to look only at a single word. Here is one
- solution:
- \beginlines
- |Object questions "qs";|
- |[ QuerySub;|
- | print_paddr noun.description; new_line;|
- |];|
- |[ Topic i;|
- | if (scope_stage==1) rfalse;|
- | if (scope_stage==2)|
- | { objectloop (i in questions) PlaceInScope(i);|
- | rtrue;|
- | }|
- | "At the moment, even the simplest questions confuse you.";|
- |];|
- \endlines
- where the actual questions are themselves objects which belong to
- the |questions| object, like so:
- \beginlines
- |Object q1 "long count" questions|
- | with name "long" "count",|
- | description "The Long Count is the great Mayan cycle of time, \|
- | which began in 3114 BC and will finish with the world's end \|
- | in 2012 AD.";|
- \endlines^^{Long Count}^^|scope stage|
- and we also have a grammar line:
- \beginlines
- |Verb "what"|
- | * "is" scope=Topic -> Query|
- | * "was" scope=Topic -> Query;|
- \endlines
- (Note that the |questions| and |q1| objects are out of the game for every
- other purpose. The name ``qs'' doesn't matter; the individual questions
- are named so that the parser might be able to say ``Which do you mean,
- the long count or the short count?'' if the player just asked ``what
- is the count''.) Here's what happens: when the parser reaches
- |scope=Topic|, it calls the |Topic| routine with the variable |scope_stage|
- set to 1. The routine should return 1 (true) if it is prepared to allow
- multiple objects to be accepted here, and 0 (false) otherwise: as we don't
- want ``what is everything'' to list all the questions and answers in the
- game, we return false.
-
- A little later on in its machinations, the parser again calls |Topic|
- with |scope_stage| now set to 2. |Topic| is now under an obligation to
- tell the parser which objects are to be in scope. It can call two
- parser routines to do this.
- \begintt
- ScopeWithin(object)
- \endtt
- puts everything inside the object into scope, though not the object itself;
- \begintt
- PlaceInScope(object)
- \endtt^^|PlaceInScope|
- puts just a single object into scope. It is perfectly legal to declare
- something in scope that ``would have been in scope anyway": or even something
- which is in a different room altogether from the actor concerned, say at the
- other end of a telephone line. Our scope routine |Topic| should then return
- \item{0} (false) to carry on with the usual scope rules, so that everything
- that would usually be in scope still is, and
- \item{1} (true) to tell the parser not to put any more objects into scope.
- \par\noindent
- (So at |scope_stage| 2 it is quite permissible to do nothing but return false,
- whereupon the usual rules apply.) |Topic| returns true because it wants
- only question topics to be in scope, not question topics together with
- everything near the player.
-
- If the player had typed ``what is the long count'', that would be all that
- happens and all would be well. On the other hand, if the player typed
- ``what is the lgon cnout'' owing to a bout of dyslexia, the error message
- which the parser would usually produce (``You can't see any such thing'')
- would be unsatisfactory. So if parsing failed at this token, then
- |Topic| is called at |scope_stage| 3 to print out a suitable error
- message. (It must provide one.)
-
- \danger The |scope=| notation is available only under Inform 5.4 and later.
-
- \danger Note that |ScopeWithin(object)| extends the scope down through
- its possessions according to the usual rules (i.e. depending on their
- transparency, whether they're containers and so in). The definition of
- |Topic| above shows how to put just the direct possessions into scope.
-
- \exercise Write a token which puts everything in scope, so that you could
- have a debugging ^{``purloin'' verb} which could take anything (regardless
- of where it was and the rules applying to it).
-
- \answer{A slight refinement of such a ^{``purloin'' verb} is already defined
- in the library (if the constant |DEBUG| is defined), so there's no need.
- Here's how it could be done:
- \beginlines
- |[ Anything i;|
- | if (scope_stage==1) rfalse;|
- | if (scope_stage==2)|
- | { for (i=1:i<=top_object:i++) PlaceInScope(i); rtrue; }|
- | "No such in game.";|
- |];|
- \endlines^^{token for `any object'}
- (This disallows multiple matches for efficiency reasons - the parser has
- enough work to do with such a huge scope definition as it is.) Now
- the token |scope=Anything| will match anything at all, even things like
- the abstract concept of `east'.}
-
- \bigskip
- Changing the global definition of scope should be done cautiously
- (there may be unanticipated side effects); bear in mind that scope decisions
- need to be taken often - every time an object token is parsed, so perhaps
- five to ten times in every game turn - and hence moderately
- quickly.^^{changing scope}
-
- To do this one provides a routine called
- \begintt
- InScope(actor)
- \endtt
- where the ^|actor| is the person whom the parser is working out scope for;
- usually, then, |actor=player|, but this should not be assumed to be always
- the case. If the routine decides that a particular object should be in
- scope for the actor, it should execute |InScope| and |ScopeWithin| just
- as above, and return true or false (as if it were at |scope_stage| 2).
- Thus, it is vital to return false in circumstances when you don't want
- to intervene.
-
- \danger In the case of a token |scope=Routine|, the |Routine| gets first
- crack at scope-changing, and |InScope| will only be reached if it returns
- false to signify `carry on'.
-
- Here are some examples. Firstly, as promised above, how to change the
- rule that ``things you've just dropped disappear in the dark":
- \beginstt
- [ InScope person i;
- if (person==player && location==thedark)
- objectloop (i near player)
- if (i has moved)
- PlaceInScope(i);
- rfalse;
- ];
- \endtt
- With this routine added, the objects in the dark room the player
- is in are in scope only if they have ^|moved| (that is, have been held by
- the player in the past); and even then, are in scope only to the player.
-
- \dangerexercise Code the following puzzle, which has nasty scope
- complications. In an initially dark room there is a ^{light switch}.
- Provided you've seen the switch at some time in the past, you can turn
- it on and off - but before you've ever seen it, you can't. Inside the
- room is nothing you can see, but you can hear a dwarf breathing. If you
- tell the dwarf to turn the light on, he will.
-
- \answer{For good measure, we'll combine this with the previous rule
- about |moved| objects being in scope in the dark. The following
- can be inserted into the `Shell' game:^^{light switch}
- \beginlines
- |Object coal "dull coal" Blank_Room|
- | with name "dull" "coal";|
- ||
- |Object Dark_Room "Dark Room"|
- | with description "An empty room with a west exit.",|
- | each_turn|
- | [; if (self has general) self.each_turn=0;|
- | else "^You hear the breathing of a dwarf.";|
- | ],|
- | w_to Blank_Room;|
- ||
- |Nearby light_switch "light switch"|
- | with name "light" "switch",|
- | initial "On one wall is the light switch.",|
- | after|
- | [; SwitchOn: give Dark_Room light;|
- | SwitchOff: give Dark_Room ~light;|
- | ],|
- | has switchable static;|
- ||
- |Nearby diamond "shiny diamond"|
- | with name "shiny" "diamond"|
- | has scored;|
- ||
- |Nearby dwarf "dwarf"|
- | with name "voice" "dwarf",|
- | life|
- | [; Order: if (action==##SwitchOn && noun==light_switch)|
- | { give Dark_Room light general;|
- | give light_switch on; "~Right you are, squire.~";|
- | }|
- | ],|
- | has animate; |
- ||
- |[ InScope person i;|
- | if (parent(person)==Dark_Room)|
- | { if (person==dwarf || Dark_Room has general)|
- | PlaceInScope(light_switch);|
- | }|
- | if (person==player && location==thedark)|
- | objectloop (i near player)|
- | if (i has moved || i==dwarf)|
- | PlaceInScope(i);|
- | rfalse;|
- |];|
- \endlines
- Note that the routine puts the light switch in scope for the dwarf -
- if it didn't, the dwarf would not be able to understand
- ``dwarf, turn light on", and that was the whole point.}
-
-
- \danger By combining an |InScope| routine with token-parsing routines
- in grammar, ^{dramatic effects} are possible. See the example game
- `Balances', for instance.
-
- \ddanger Once you begin programming the parser on a large scale, you soon
- reach the point where the parser's ordinary error messages no longer appear
- sensible. So that you can change the rules even at this last hurdle,
- the parser calls your ^|ParserError| routine (if you provide one): the
- argument is the error type, and you return true
- to tell the parser to shut up (as you have already printed a better error
- message than it would have done). The error types are all defined as
- constants:
-
- {\ninepoint
- \settabs 8\columns
- \+& |STUCK_PE| && I didn't understand that sentence.\cr
- \+& |UPTO_PE | && I only understood you as far as...\cr
- \+& |CANTSEE_PE| && You can't see any such thing.\cr
- \+& |TOOLIT_PE| && You seem to have said too little!\cr
- \+& |NOTHELD_PE| && You aren't holding that!\cr
- \+& |MULTI_PE| && You can't use multiple objects with that verb.\cr
- \+& |MMULTI_PE| && You can only use multiple objects once on a line.\cr
- \+& |VAGUE_PE| && I'm not sure what ~it~ refers to.\cr
- \+& |EXCEPT_PE| && You excepted something not included anyway!\cr
- \+& |ANIMA_PE| && You can only do that to something animate.\cr
- \+& |VERB_PE| && That's not a verb I recognise.\cr
- \+& |SCENERY_PE| && That's not something you need to refer to...\cr
- \+& |ITGONE_PE| && You can't see ~it~ (the spell book) at the moment.\cr
- \+& |JUNKAFTER_PE| && I didn't understand the way that finished.\cr
- \+& |TOOFEW_PE| && Only five of those are available.\cr
- \+& |NOTHING_PE| && Nothing to do!\cr
- \+& |NUMBER_PE| && I didn't understand that number.\cr
- \+& |ASKSCOPE_PE| && {\it whatever the scope routine prints}\cr
- \smallskip\par\noindent
- Each time the parser gives up on a line of grammar, it has hit one of these
- conditions. A verb may have many lines of grammar; so by the time the
- parser wants to print an error, all of them must have failed. The error
- message it prints is the most `interesting' one (meaning, lowest down this
- list).}
-
-
- \section{17}{The light and the dark}
-
- \noindent^^{light and dark}^^{definition of darkness}^^{C. P. Snow}
- The library maintains light by itself, and copes with events like:
- \begindisplay
- a total eclipse of the Sun;\cr
- fusing all the lights in the house;\cr
- your lamp going out;\cr
- a dwarf stealing it and running away;\cr
- dropping a lit match which you were seeing by;\cr
- putting your lamp into an opaque box and shutting the lid;\cr
- black smoke filling up the glass jar that the lamp is in;\cr
- the dwarf with your lamp running back into your now-dark room.\cr
- \enddisplay
- The point of this list is to demonstrate that light v. darkness is
- tricky to get right, and that it is best left to the library. Your code
- needs only to do something like
- \begintt
- give lamp light;
- remove match;
- give glass_jar ~transparent;
- move dwarf to Dark_Room;
- \endtt
- and can leave the library to sort out the consequences. As the above
- suggests, the |light| attribute means that an object is giving off light,
- or that a room is currently lit (e.g. by being out of doors in day-time).
-
- If you simply never want to have darkness, and some games never do, a
- sneaky way of doing it is to put the line
- \begintt
- give player light;
- \endtt
- in |Initialise|. The game works as if the player herself were glowing
- enough to provide light to see by. So there's never darkness near the
- player.
- \medskip
-
- The definition of ``when there is light" is complicated, involving
- recursion both up and down. Remember that the parent of the player
- object may not be a room; it may be, say, a red car whose parent is a
- room.
-
- There is light exactly when the parent of the player `offers light'.
- An object ^{`offers light'} if:
- \begindisplay
- it itself has the |light| attribute set, {\bf or}\cr
- any of its immediate possessions `have light', {\bf or}\cr
- it is see-through and its parent offers light, {\bf or}\cr
- it is enterable and its parent offers light;\cr
- \enddisplay
- while an object ^{`has light'} if:
- \begindisplay
- it currently has the |light| attribute set, {\bf or}\cr
- it is see-through and one of its immediate possessions has light.\cr
- \enddisplay
- The process of checking this stops as soon as light is discovered. The
- routines
- \begindisplay
- ^|OffersLight(object)| and ^|HasLightSource(object)|
- \enddisplay
- which return true or false and have no side effects (that is, they merely
- report on the current state without changing anything), are available and
- might occasionally be useful.
-
- \danger So light is cast up and down the tree of objects. In certain
- contrived circumstances this might be troublesome: perhaps an opaque box,
- whose outside is fluorescent but whose interior is dark, and which contains
- an actor who needs not to have other contents of the box in scope...
- `contrived' being the word. The dilemma could be solved by putting an inner
- box in the outer one.
-
- \exercise How would you code a ^{troll} who is afraid of the dark, and needs
- to be bribed but will only accept a light source... so that the troll will
- be as happy with a goldfish bowl containing a ^{fluorescent jellyfish} as he
- would be with a lamp?
-
- \answer{Just test if |HasLightSource(gift)==1|.}
-
- Each turn, light is reconsidered. The presence or absence of light affects
- the |Look|, |Search|, |LookUnder| and |Examine| actions, and
- (since this is a common puzzle) also the |Go| action: you can provide
- a routine called
- \begintt
- DarkToDark()
- \endtt^^|DarkToDark|
- and if you do then it will be called when the player goes from one dark
- room into another dark one. If you want, you can take the opportunity to
- kill the player off or extract some other forfeit. If you provide no such
- routine, then the player can move about freely (subject to any rules which
- apply in the places concerned).
-
-
- \section{18}{On inventories and lists}
-
- \widepoem
- As some day it may happen that a victim must be found
- I've got a little list - I've got a little list
- Of society offenders who might well be underground,
- And who never would be missed
- Who never would be missed!
- \poemby{^{W. S. Gilbert} (1836-1911)}{The Mikado}
-
- The library often needs to reel off a list of objects: when an |Inv|
- (inventory) action takes place, for instance, or when describing the
- contents of a container or a room. Lists are difficult to print out
- correctly `by hand', because there are many cases to get right (especially
- when taking plurals into account). Fortunately, the library's list-maker is
- open to the public. The routine to call is:^^{listing objects}
- \begintt
- WriteListFrom(object, style);
- \endtt^^|WriteListFrom|
- where the list will start from the given object and go along its siblings.
- (Thus, to list all the objects inside |X|, list from |child(X)|.) What the
- list looks like depends on the style, which is a bitmap you can make by
- adding up some of the following constants:^^{style of list}
- \smallskip
- \settabs 8\columns
- \+& |NEWLINE_BIT| && New-line after each entry\cr
- \+& |INDENT_BIT| && Indent each entry by depth\cr
- \+& |FULLINV_BIT| && Full inventory information after entry\cr
- \+& |ENGLISH_BIT| && English sentence style, with commas and `and'\cr
- \+& |RECURSE_BIT| && Recurse downwards with usual rules\cr
- \+& |ALWAYS_BIT| && Always recurse downwards\cr
- \+& |TERSE_BIT| && More terse English style\cr
- \+& |PARTINV_BIT| && Only brief inventory information after entry\cr
- \+& |DEFART_BIT| && Use the definite article in list\cr
- \+& |WORKFLAG_BIT| && At top level (only), only list objects\cr
- \+& && which have the |workflag| attribute\cr
- \smallskip
- \noindent The best way to use this is to experiment. For example, a `tall'
- inventory is produced by:
- \begintt
- WriteListFrom( child(player),
- FULLINV_BIT + INDENT_BIT + NEWLINE_BIT + RECURSE_BIT );
- \endtt^^{narrow inventory}
- and a `wide' one by:
- \begintt
- WriteListFrom( child(player),
- FULLINV_BIT + ENGLISH_BIT + RECURSE_BIT );
- \endtt^^{wide inventory}
- which produce effects like:
- \beginstt
- >inventory tall
- You are carrying:
- a bag (which is open)
- three gold coins
- two silver coins
- a bronze coin
- four featureless white cubes
- a magic burin
- a spell book
- \endtt\beginstt
- >inventory wide
- You are carrying a bag (which is open), inside which are three gold
- coins, two silver coins and a bronze coin, four featureless white
- cubes, a magic burin and a spell book.
- \endtt
- (except that the `You are carrying' part is not done by the list-maker,
- and nor is the final full stop in the second example).
- \medskip
-
- The |workflag| is an attribute which the library scribbles over from time
- to time as temporary storage, but you can use it with care. In this case
- it makes it possible to specify any reasonable list.
-
- \exercise Write a |DoubleInvSub| action routine to produce an inventory
- like so:^^{double inventory}
- \beginstt
- You are carrying four featureless white cubes, a magic burin and a
- spell book. In addition, you are wearing a purple cloak and a miner's
- helmet.
- \endtt
-
- \answer{\beginlines
- |[ DoubleInvSub i count1 count2;|
- | print "You are carrying ";|
- | objectloop (i in player)|
- | { if (i hasnt worn) { give i workflag; count1++; }|
- | else { give i ~workflag; count2++; }|
- | }|
- | if (count1==0) print "nothing.";|
- | else|
- | WriteListFrom(child(player),|
- | FULLINV_BIT + ENGLISH_BIT + RECURSE_BIT + WORKFLAG_BIT);|
- ||
- | if (count2==0) ".";|
- | print ". In addition, you are wearing ";|
- | objectloop (i in player)|
- | { if (i hasnt worn) give i ~workflag; else give i workflag;|
- | }|
- | WriteListFrom(child(player),|
- | ENGLISH_BIT + RECURSE_BIT + WORKFLAG_BIT);|
- | ".";|
- |];|
- \endlines^^{double inventory}}
-
- Some objects ought to print something different when they appear in
- inventory lists: a wine bottle should say how much wine is left, for
- instance. By giving an object an ^|invent| routine, you can alter the
- usual rules.
-
- A typical inventory list looks like:
- \beginstt
- >i
- You are carrying:
- a green cone
- a pair of hiking boots
- your satchel (which is open)
- a green cube
- \endtt
- and each line goes through two stages. Firstly, the object's indefinite
- article and name are printed. Secondly, little informative messages like
- ``(which is open)" are printed, and ^{inventories} are given for the contents
- of open containers.
-
- An object's |invent| routine gets two chances to interfere with this,
- one before each stage. So what happens is this:
- \item{1.} The global variable |inventory_stage| is set to 1.
- \item{2.} The |invent| routine is called (if there is one).
- If it returns true, stop here.
- \item{3.} The indefinite article and short name are printed.
- \item{4.} The global variable |inventory_stage| is set to 2.
- \item{5.} The |invent| routine is called (if there is one).
- If it returns true, go to step 8.
- \item{6.} One or more of the following are printed, as appropriate:
- \begindisplay
- \quad (providing light)\cr
- \quad (being worn)\cr
- \quad (which is open)\cr
- \quad (which is closed)\cr
- \enddisplay
- \item{7.} If it is an open container, its contents are inventoried.
- \item{8.} Linking text (such as a new-line or a comma) is printed,
- according to the current style.^^|inventory stage|
- \par\noindent Note that if an |invent| routine does return true,
- then the contents are never reached.
-
- For example, here is an |invent| routine for a ^{matchbook}:
- \beginstt
- invent
- [ i; if (inventory_stage==2)
- { i=self.number;
- if (i==0) print " (empty)";
- if (i==1) print " (1 match left)";
- if (i>1) print " (",i," matches left)";
- }
- ],
- \endtt
- (The rest of the matchbook definition is given in the ^{`Toyshop'} example
- game.)
-
- \ddanger Changing the rules at |inventory_stage| 1 is kept on for more
- peculiar effects (and is not really recommended).
-
-
- \section{19}{The naming of names}
-
- \verywidepoem
- The Naming of Cats is a difficult matter,
- It isn't just one of your holiday games;
- You may think at first I'm as mad as a hatter
- When I tell you, a cat must have THREE DIFFERENT NAMES.
- \poemby{^{T. S. Eliot} (1888-1965)}{The Naming of Cats}
-
- \quote
- Bulldust, coolamon, dashiki, fizgig, grungy, jirble, pachinko,
- poodle-faker, sharny, taghairm
- \quoteby{Catachrestic words from Chambers English Dictionary}
-
- Providing an |invent| routine doesn't work quite so well for the match
- as for the matchbook. You might try:
- \beginstt
- invent
- [; if (inventory_stage==2)
- { if (self has light) print " (burning away)"; rtrue;
- }
- ],
- \endtt
- \danger Returning true here is a trick to stop ``(providing light)"
- from appearing as well - after all, that's redundant.
-
- This does work but there's a better way, which is to change the object's
- short name itself, from ``unlit match" to ``lit match" say. So
- another property, called |short_name|, is available.
- ^^|short name| Normally, the short name of an object
- is given in the header of the object definition.
- But if a |short_name| routine is given, then whenever the game wants to
- write out the name of the object, the following happens:
- \item{1.} If the |short_name| is a string, it's printed and that's all.
- \item{2.} If it is a routine, then it is called. If it returns true,
- that's all.
- \item{3.} The `real' short name (the one in the object header) is printed.
- \par\noindent So, as promised, here's the better way to code the match:
- \beginstt
- short_name
- [; if (self has light) print "burning match";
- else print "unlit match";
- rtrue;
- ],
- \endtt
- Note that rooms can also be given a |short_name| routine, which might be
- useful to code, say, a grid of four hundred almost exactly similar
- locations, called ``Area 1" up to ^{``Area 400"}.
- \medskip
-
- \danger Now, though, the player is going to want to type ``drop the
- burning match", or ``light the unlit match". (Indeed, there might be two
- matches, only one of which can be called ``unlit".) It's perfectly
- straightforward to alter the ^|name| property of an object (provided one
- remembers what it is: a list of (machine) words, being the byte addresses in
- memory of words in the dictionary) but, again, there is a better and more
- powerful way. This is to give the match object a |parse_name| routine.
-
- \ninepoint^^|parse name|
- A |parse_name| routine is expected to try to match the text which the user
- has typed (available one word at a time from the |NextWord()| routine), and
- to return how many words it managed to match. It is required to go as far
- as it can, i.e., not to stop if the first word makes sense, but to keep
- reading and find out how many words in a row make sense.
-
- It should return:
- \begindisplay
- 0\quad if the text didn't make any sense at all,\cr
- $k$\quad if $k$ words in a row of the text seem to refer to the object, or\cr
- -1\quad to make the parser just do what it would normally do.\cr
- \enddisplay
- For example:
- \beginstt
- Nearby thing "weird thing"
- with parse_name
- [ i; while (NextWord()=='weird' or 'thing') i++;
- return i;
- ];
- \endtt^^{weird thing}
- This definition duplicates (very nearly) what the parser would have done
- if the weird thing had been defined as:
- \beginstt
- Nearby thing "weird thing"
- with name "weird" "thing";
- \endtt
- Which isn't very useful. But the match can now be coded up with
- \beginstt
- parse_name
- [ i j; if (self has light) j='burning'; else j='unlit';
- while (NextWord()=='match' or j) i++;
- return i;
- ],
- \endtt
- so that ``burning" only applies when it is, and similarly ``unlit".
- (Actually the parser automatically recognises ``unlit" and ``lit", so this
- last part was unnecessary.)
- \tenpoint
-
-
- \section{20}{Plural names and groups of similar objects}
-
- \poem
- Abiit ad plures.
- \poemby{Petronius (?-c. 66)}{Cena Trimalchionis}
-
- A notorious problem for adventure game parsers is to handle a collection of,
- say, ten gold coins, allowing the player to use them independently of each
- other, while gathering them together into groups in descriptions and
- inventories. This is relatively easy in Inform, and only in really hard
- cases do you have to provide code.^^{plural objects}
-
- There are two problems to be overcome: firstly, the game has to be able
- to talk to the player in plurals, and secondly vice versa. First, then,
- game to player:
- \beginstt
- Class gold_coin_class
- with name "gold" "coin",
- plural "gold coins";
- \endtt
- \noindent (and similar silver and bronze coin classes here)
- \beginstt
- Object bag "bag"
- with name "bag"
- has container open openable;
- \endtt\beginstt
- Nearby co1 "gold coin" class gold_coin_class;
- Nearby co2 "gold coin" class gold_coin_class;
- Nearby co3 "gold coin" class gold_coin_class;
- Nearby co4 "silver coin" class silver_coin_class;
- Nearby co5 "silver coin" class silver_coin_class;
- Nearby co6 "bronze coin" class bronze_coin_class;
- \endtt
- \noindent Now we have a ^{bag of six coins}. The player looking inside
- the bag will get
- \beginstt
- >look inside bag
- In the bag are three gold coins, two silver coins and a bronze coin.
- \endtt
- How does the library know that the three gold coins are the same as each
- other, but the others different? It doesn't look at the classes but the
- names. It will only group together things which:
- \item{(a)} have a ^|plural| set,
- \item{(b)} are ^{`indistinguishable'} from each other.
-
- \noindent Indistinguishable means they have the same |name| words as each other
- (possibly in a different order), so that nothing the player can type
- will separate the two.
-
- \danger Actually, the library is cleverer than this. What it groups
- together depends slightly on the context of the list it's writing out. When
- it's writing a list which prints out details of which objects are providing
- light, for instance (like an inventory), it won't group together two objects
- if one is lit and the other isn't. Similarly for objects with visible
- possessions or which can be worn.
-
-
- \ddanger This all gets even more complicated when the objects have a
- |parse_name| routine supplied, because then the library can't use the |name|
- fields to tell them apart. If they have different |parse_name| routines, it
- decides that they're different. But if they have the same |parse_name|
- routine, there is no alternative but to ask them. What happens is that
- \begindisplay
- 1.\quad A variable called |parser_action| is set to |##TheSame|;\cr
- 2.\quad Two variables, called |parser_one| and |parser_two| are set to\cr
- \phantom{2.}\quad the two objects in question;\cr
- 3.\quad Their |parse_name| routine is called. If it returns:\cr
- \qquad -1 \quad the objects are declared ``indistinguishable",\cr
- \qquad -2 \quad they are declared different.\cr
- 4.\quad Otherwise, the usual rules apply and the library looks at\cr
- \qquad the ordinary |name| fields of the objects.\cr
- \enddisplay^^{fake actions}^^|parser one, parser two, parser action|
- (|##TheSame| is a fake action.)
- ^^|TheSame|
- The implementation of the
- ^{`Spellbreaker cubes'} in the ^{`Balances'} game
- is an example of such a routine (so that if
- the player writes the same name on several of the cubes, they become
- grouped together). Note that this whole set-up is such that if the
- author of the |parse_name| routine has never read this paragraph, it doesn't
- matter and the usual rules take their course.^^|parse name|
-
- \ddanger You may even want to provide a |parse_name| routine just to speed
- up the process of telling two objects apart - if there were 30 gold coins
- the parser will be doing a lot of work comparing all their names, but you
- can make the decision much faster.
- \bigskip
-
- Secondly, the player talking to the computer. This goes a little further
- than just copies of the same object: 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:
- \begintt
- > drop all of the crowns except green
- > drop the three other crowns
- \endtt
- even though the ^{crowns} are not identical. The simple way to do this is just
- to put |"crowns"| in their name fields, and this works perfectly well most of
- the time.
-
- \ddanger But it isn't ideal, because then the parser will think
- \begintt
- > drop crowns
- \endtt
- refers to a single object, and won't deduce that the player wants to pick
- up all the sensibly available crowns.
- So the complicated (but better way) is to make
- the |parse_name| routine tell the parser that yes, there was a match, but
- that it was a plural. The way to do this is to set |parser_action| to
- |##PluralFound| (another fake action). So, for example:
- \beginstt
- Class crown_class
- with parse_name
- [ i j;
- for (::)
- { j=NextWord();
- if (j=='crown' or j==self.name) i++;
- else
- { if (j=='crowns')
- { parser_action=##PluralFound; i++; }
- else return i;
- }
- ];
- \endtt
-
- \exercise Write a `cherub' class so that if the player tries to call them
- ``cherubs", a message like ``I'll let this go by for now, but the plural of
- cherub is cherubim" appears.^^{cherubim}
-
- \answer {\beginlines
- |Global c_warned = 0;|
- |Class cherub_class|
- | with parse_name|
- | [ i j flag;|
- | for (flag=1:flag==1:flag=0)|
- | { j=NextWord();|
- | if (j=='cherub' or j==self.name) flag=1;|
- | if (j=='cherubs' && c_warned==0)|
- | { c_warned=1;|
- | parser_action=##PluralFound; flag=1;|
- | print "(I'll let this go once, but the plural of cherub is cherubim.)^";|
- | }|
- | if (j=='cherubim')|
- | { parser_action=##PluralFound; flag=1; }|
- | i++;|
- | }|
- | return i-1;|
- | ];|
- \endlines
- Then again, Shakespeare even writes ``cherubins'' in {\sl Twelfth Night},
- so who are we to censure?^^{cherubim}^^{William Shakespeare}}
-
-
- \section{21}{Miscellaneous constants and scoring}
-
- Some game rules can be altered by defining `constants' at the start of
- the program, before the library files are included. Two constants
- it {\it must} provide are the strings |Story| and |Headline|:
- \beginstt
- Constant Story "ZORK II";
- Constant Headline "^An Interactive Plagiarism^\
- Copyright (c) 1993 by Ivan O. Ideas.^";
- \endtt^^{plagiarism}^^{Ivan O. Ideas}
- All the rest are optional.
-
- \medskip
- 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. (In fact you can change this `live',
- in that it is actually |player.capacity| which is consulted; the
- only use of |MAX_CARRIED| is to set this up to an initial
- value.)^^|MAX CARRIED|
-
- 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, provided it is being carried. This is a feature which
- endears the designer greatly to players.^^|SACK OBJECT|
-
- \medskip
- 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. You can
- use this to roll closing credits, or tell the player various strange
- things about the game, now that there's no surprise left to spoil.
- ^^|AMUSING PROVIDED|^^{closing credits}
-
- \medskip
- The other constants you are allowed to define help the score routines
- along. There are two ^{scoring systems} provided by the library, side by
- side: you can use both or neither. (You can always do what you like to
- the |score| variable in any case.) One scores points for getting certain
- items or reaching certain places; the other for completing certain
- actions. The constants are:
- \smallskip
- \settabs 8 \columns
- \+ &|MAX_SCORE| && The maximum game score (by default 0)\cr
- \+ &|NUMBER_TASKS| && Number of individual ``tasks" to perform (1)\cr
- \+ &|OBJECT_SCORE| && Bonus for first picking up a |scored| object (4)\cr
- \+ &|ROOM_SCORE| && Bonus for first entering a |scored| room (5)\cr
- \smallskip
- \noindent and then the individual tasks have scores, as follows:
- \begintt
- Global task_scores initial t1 t2 ... tn;
- \endtt^^|task scores|^^|MAX SCORES|^^|NUMBER TASKS|^^|OBJECT SCORE|^^|ROOM SCORE|
- 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|.^^|TASKS PROVIDED|
-
- A routine called ^|PrintRank|, which you can provide if you want, gets the
- chance to print something additional to the score, such as rankings. For
- instance:
- \beginstt
- [ PrintRank;
- print ", earning you the rank of ";
- if (score >= 348) "Grandmaster Adventurer!";
- if (score >= 330) "Master, first class.";
- if (score >= 300) "Master, second class.";
- if (score >= 200) "Junior Master.";
- if (score >= 130) "Seasoned Adventurer.";
- if (score >= 100) "Experienced Adventurer.";
- if (score >= 35) "Adventurer.";
- if (score >= 10) "Novice.";
- "Amateur.";
- ];
- \endtt
-
- |PrintTaskName| prints the name of a game task (such as ``driving the car").
- Of course, this is only ever called in a game with |TASKS_PROVIDED| defined.
- For instance,
- \beginstt
- [ PrintTaskName ach;
- if (ach==0) "eating a sweet";
- if (ach==1) "driving the car";
- if (ach==2) "shutting out the draught";
- if (ach==3) "building a tower of four";
- if (ach==4) "seeing which way the mantelpiece leans";
- ];
- \endtt
-
- \medskip
-
- Normally, an Inform game will print messages like
- \begindisplay
- [Your score has gone up by three points.]
- \enddisplay^^{score notification}
- when the score changes (by whatever means). The player can turn this on and
- off with the ^{``notify'' verb}; by default it is on. You can alter the flag
- |notify_mode| yourself to control this.^^|notify mode|
- \bigskip
-
- \medskip
- Sometimes you want to ask the player a yes/no question. If so, call
- ^|YesOrNo()|, a library routine: it returns true/false accordingly (and
- doesn't print any question, which is up to you). This saves a lot of
- bother programming the parser.^^{questions (yes or no)}
-
- \ddanger 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:
- for example, if the directive
- \beginstt
- REPLACE BurnSub;
- \endtt^^|Replace|
- is placed in your file {\it before the library files are included},
- Inform ignores the definition of |BurnSub| in the library files.
- (You then have to define a routine called |BurnSub| yourself, or Inform
- will complain that the program refers to a routine which isn't there.)
- And this is the ^{very last resort}, and so the end of the manual proper.
-
-
- \section{22}{Debugging verbs and tracing}
-
- \quote
- If builders built buildings the way programmers write programs,
- the first ^{woodpecker} that came along would destroy civilisation.
- \quoteby{old computing adage}
-
- The two problems with debugging a game are working out exactly what it's
- doing, and making things happen which wouldn't normally be allowed (such
- as giving yourself the trident now rather than playing for two hours to
- find it).
-
- Inform provides a small suite of ^{debugging verbs} to help with this, but
- only if the game defines the constant ^|DEBUG| before including the library
- files. (Just in case you forget to take this out again, the letter D
- appears in the game banner to indicate this.)
-
- You then get the following verbs, which can be used at any time in play:
- \begintt
- purloin <anything>
- abstract <anything> to <anything>
- tree tree <thing>
- goto <number>
- actions actions on actions off
- routines routines on routines off
- timers timers on timers off
- trace trace on trace off trace <1 to 5>
- \endtt
- You can ``purloin" any item or items in your game at any time, wherever
- you are. You can likewise ``abstract" any item to any other item (meaning:
- move it to the other item). To get a listing of the objects in the game
- and how they contain each other, use ``tree", and to see the possessions of
- one of them alone, use ``tree \<that>". Finally, you can go to any object:
- but since rooms don't have names understood by the parser, you have to give
- the object number of the place you want to go to. (The ``tree" listing will
- tell you these numbers.)
- ^^{``actions'' verb}^^{``tree'' verb}^^{``purloin'' verb}^^{``routines'' verb}
- ^^{``trace'' verb}^^{``abstract'' verb}^^{``goto'' verb}
- Turning on ``actions" gives a trace of all the actions which take place in
- the game (the parser's, the library's or yours); turning on ``routines"
- traces every object routine (such as |before| or |life|) that is ever
- called, except for |short_name| (as this would look chaotic, especially on
- the status line). Turning on ``timers'' shows the state of all active timers
- and daemons each turn.^^{``timers'' verb}
- ^^{tracing routines, actions, daemons and timers}
-
- \medskip
- ^{Infix}, Dilip Sequeira's ^{source-level debugger} for Inform, is currently
- in an advanced state of preparation: it is an enhanced form of Mark Howell's
- ^{Zip} interpreter providing for breakpoints, tracing and so forth. It
- should fairly soon be publically archived with the rest of the Inform project.
-
- \danger For Infix's benefit, Inform (if compiling with the option set) produces
- a file of ``debugging information'' (cross-references of the game file with
- the source code), and anyone interested in writing an Inform utility program
- may want to know the format of this file: see the short C program ^{Infact}
- which prints out the debugging information file in English.
-
- On most interpreters, though, ^{run-time crashes} are mysterious (because they
- were written on the assumption that all existing Infocom game files were free
- from error). ^{Zip} is rather more generous and will usually tell you why and
- where the problem is; given a game file address you can work back to the
- problem point in the source either with Mark Howell's ^{txd (disassembler)}
- or by running Inform with the assembler trace option on.
-
- Here are all the ways I know to crash an interpreter at run-time (with
- high-level Inform code, that is; if you insist on using
- assembly language or the ^|indirect| function you're raising the stakes),
- arranged in decreasing order of likelihood:
- ^^{crashing the interpreter}
- \item{$\bullet$} Writing to a property of an object which it hasn't got;
- \item{$\bullet$} Dividing by zero, possibly by calling |random(0)|;^^|random|
- \item{$\bullet$} Giving a string or numerical value for a property which can
- only legally hold a routine, such as |before|, |after| or |life|;
- \item{$\bullet$} Applying ^|parent|, ^|child| or ^|children| to the ^|nothing|
- object;
- \item{$\bullet$} Using ^|print object| on the |nothing| object, or for some
- object which doesn't exist (always use the routines |DefArt|, |CDefArt| or
- |PrintShortName| as appropriate, which are safeguarded and anyway
- implement higher-level features);
- \item{$\bullet$} Using |print_addr| or |print_paddr| to print from an address
- outside the memory map of the game file, or an address at which no string
- is present (this will result in random text appearing, possibly including
- unprintable characters, which may conceivably crash your terminal);
- ^^|print addr|^^|print paddr|
- \item{$\bullet$} Setting the |location| variable to zero, or some non-existent
- object, since the interpreter prints the name of this object on the
- ^{status line};
- in any case it is safer to use ^|PlayerTo| than to meddle directly with this;
- \item{$\bullet$} Running out of stack space in a recursive loop (though this
- has never actually happened to anyone I know of).
-
- \danger^^{parser tracing and levels}
- There are times when it's hard to work out what the parser is up to and why
- (actually, most times are like this). The parser is written in levels, the
- lower levels of which are murky indeed. Most of the interesting things
- happen in the middle levels, and these are the ones for which tracing is
- available. The levels which can be traced are:
- \smallskip\ninepoint
- \settabs 8\columns
- \+& Level 1 && Grammar lines\cr
- \+& Level 2 && Individual tokens\cr
- \+& Level 3 && Object list parsing\cr
- \+& Level 4 && Resolving ambiguities and making choices of object(s)\cr
- \+& Level 5 && Comparing text against an individual object\cr
- \smallskip\noindent
- ``trace" or ``trace on" give only level 1 tracing. Be warned: ``trace five"
- can produce reams of text when you try anything at all complicated: but you
- do sometimes want to see it, to get a list of exactly everything that is in
- scope and when. There are two levels lower than that but they're too busy
- doing dull spade-work to waste time on looking at |parser_trace|. (There's
- also a level 0, but it consists mostly of making arrangements for level 1,
- and isn't very interesting.)^^{tracing the parser}\tenpoint
-
- \ddanger
- Finally, though this is a drastic measure, you can always compile your game
- |-g| (^{`debugging code'}) which gives a listing of every routine ever
- called and their parameters. This produces an enormous mel\'ee of output.
- (In Inform 5.3, though not earlier versions, you can declare a routine with
- an asterisk ^|*| as its first local variable, which produces such tracing only
- for that one routine.)^^{tracing a routine}^^{routine tracing}
-
-
- \section{23}{Limitations on the run-time format}
-
- \poem
- How wide the limits stand
- Between a splendid and an happy land.
- \poemby{^{Oliver Goldsmith} (1728-1774)}{The Deserted Village}
-
- ^^{limitations}
- The Infocom ^{run-time format} is well-designed, and has three major
- advantages: it is compact, widely portable and can be quickly executed.
- Nevertheless, like any rigidly defined
- format (which it clearly must be), it imposes limitations. These are not
- by any means pressing. Inform itself has a flexible enough memory-management
- system not to impose artificial limits on numbers of objects and the like.
-
- There are two sizes of game available: Standard (or version 3) and Advanced
- (or version 5). Always use the latter if you can; it is very much to be
- preferred. (There are very slight risks associated with exotic
- assembly-language coding in Advanced games: but unless you deviate far
- from normal Inform practice, and code on a very low level, these will never
- trouble you.) There are still 8-bit computers in use which are too small
- for ^{Advanced games}, but most people should have no problem.^^{Standard games}
- \medskip
-
- {\it Memory.}\quad The total size of a Standard game is at most 128K; of an
- Advanced game, 256K. Because games are encoded in a very compressed form,
- and because the centralised library of Inform makes the compiler fairly
- efficient in terms of not duplicating code, even 128K allows for a game
- at least half as large again as a typical old-style Infocom game. No game
- yet written under Inform has reached the 256K mark, not even the final
- version of `Curses' (at 224K, already substantially bigger and denser than
- any Infocom game).^^{memory size}
- \medskip
-
- {\it Vocabulary.}\quad There is no theoretical limit, and vocabularies
- in excess of 2000 are quite sensibly possible. (A typical large game will
- muster 1000.)^^{vocabulary size}
- \medskip
-
- {\it Dictionary resolution.}\quad In Standard games, dictionary words are
- truncated to their first 6 letters, which can be a nuisance; in Advanced,
- 9 letters, which never is.^^{dictionary resolution}
- \medskip
-
- {\it Attributes, properties, names.}\quad Standard games only provide
- 32 attributes, 30 properties and at most 8 bytes of data per property:
- the library consumes most of this ration, and the 8 bytes restriction
- means that an object can only have four words in its |name|. This is
- perfectly manageable, if unsatisfactory. Advanced games, which provide 48
- attributes, 62 properties and 64 bytes of data (hence 32 names), effectively
- make none of these restrictions serious.
- \medskip
-
- {\it Special effects.}\quad Standard games cannot have special effects such
- as bold face and underlining. (See the next two sections.)
- \medskip
-
- {\it Objects.}\quad Standard games can have at most 255 objects, enough for
- a large Infocom-size game but not much more. Advanced games have no such
- restriction, the number being in principle unlimited. Objects cannot
- dynamically be created or destroyed, but this is imitated easily enough.
- \medskip
-
- {\it Global variables.}\quad There can only be 240 of these, and the Inform
- compiler uses 5 as scratch space, while the library uses slightly over 100;
- but since a typical game uses only a dozen of its own, code being almost
- always object-oriented, the restriction is never even nearly felt. (Recall
- that arrays take only one global each.)
- \medskip
-
- {\it ``Undo''.}\quad Standard games do not provide an ^{``undo'' verb},
- but Advanced ones (or rather, the Inform library when compiled on such)
- do.
-
- \bigskip
-
- \danger There is a yet larger Infocom format, ^{version 6}, which lifts even the mild
- restrictions of version 5 games, with memory maps of up to
- 600K or so: version 6 has only recently been fully deciphered, but Inform is
- already capable of producing such files, and Mark Howell's ``Zip''
- interpreter is (at time of writing) making good progress in running them.
- A 600K Inform game would be gargantuan: by the time one comes along, there
- should be no problem in running it.
-
- \ddanger Having said all this, if memory does become short, there is a
- standard mechanism for saving about 8-10\% of the memory. Inform does
- not usually trouble to, since there's very seldom the need, and it makes
- the compiler run about 10\% slower. What you need to do is define
- ^{abbreviations}. For instance, the directive
- \beginstt
- Abbreviate " the ";
- \endtt
- (placed before any text appears) will cause the string `` the '' to be
- internally stored as a single `letter', saving memory every time it occurs
- (about 2500 times in `Curses', for instance). You can have up to 64
- abbreviations. A good list of abbreviations can be found in the
- {\sl Technical Manual}: basically, avoid proper nouns and instead pick on short
- combinations of a space and common two- or three-letter blocks. You can
- even get Inform to work out by itself what a good stock of abbreviations
- would be: but be warned, this makes the compiler run about 29000\% slower.
-
-
- \section{24}{A very few, not very special effects}
-
- \quote
- Yes, all right, I won't do the menu... I don't think you realise
- how long it takes to do the menu, but no, it doesn't matter, I'll
- hang the picture now. If the menus are late for lunch it doesn't
- matter, the guests can all come and look at the picture till they
- are ready, right?
- \poemby{^{John Cleese} and ^{Connie Booth}}{Fawlty Towers}
-
- As the previous section suggested, some ^{special effects} are not to be
- encouraged: they reduce portability a little, and anyway Inform is for
- text games.
-
- 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.
- Usually, the game automatically prints the current game location, and either
- the time or the score and number of turns taken. It has the score/turns
- format unless the directive
- \begintt
- Statusline time;
- \endtt
- is present, in which case it shows the game's 24-hour clock.
-
- \ddanger If you {\it really} want to change this, then |Replace| the parser's
- private |DrawStatusLine| routine. But be sure to test the result on more
- than one interpreter, in case you've made a mistake which doesn't show up on
- one quirky implementation. (In any case, you can only change it at all on
- Advanced games.)
-
- \ddangerexercise Alter the ^{`Advent'} example game to display the number
- of treasures found instead of the score and turns on the status line.
-
- \answer{First put the directive |Replace DrawStatusLine;| before including
- the library. Then add the following routine anywhere after |treasures_found|,
- an `Advent' variable, is defined:
- \beginlines
- |[ DrawStatusLine;|
- | @split_window 1; @set_window 1; @set_cursor 1 1; style reverse;|
- | spaces (0->33)-1;|
- | @set_cursor 1 2; PrintShortName(location);|
- | if (treasures_found > 0)|
- | { @set_cursor 1 50; print "Treasure: ", treasures_found;|
- | }|
- | @set_cursor 1 1; style roman; @set_window 0;|
- |];|
- \endlines}
-
- 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 that for example an `i' will be narrower than an
- `m'). If you want to display a diagram made up of letters, such as a map,
- you will have to turn this off, for which the ^|font| command is provided.
- Write |font off| before printing character graphics, and remember to
- write |font on| again afterwards.
-
- \warning Don't turn the |font| on and off in the middle of a line; this
- doesn't look right on some machines.
-
- A distinctive feature of later Infocom games was their use of ^{epigrams}.
- Inform can do this, too, but only for Advanced games. The
- assembly language required is easy but a nuisance, so there is a command
- to do it, ^|box|. For example,
- \beginstt
- box "Beware of the Dog";
- \endtt
- or
- \beginstt
- 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";
- \endtt^^{Dorothy Parker}^^{quotations beautiful}
- 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). Also, some people might be running
- your game on a laptop with a vertically challenged screen, so it is
- polite to provide a ^{``quotes off'' verb}.
- \medskip
-
- Sometimes one would like to provide a ^{menu of text options} (for instance,
- when producing instructions which have several topics, or when giving
- ^{clues}). This can be done with the ^|DoMenu| routine, which imitates
- the traditional ^{``Invisiclues''} style. However, it only looks good
- for Advanced games; for Standard games, it's simply textual. (In an
- Advanced game, by setting |pretty_flag=0| you can get this simple text
- version instead; which is a good idea for machines with very small
- screens.)
-
- Here is a typical call to |DoMenu|:
- \beginstt
- DoMenu("There is information provided on the following:^\
- ^ Instructions for playing\
- ^ The history of this game\
- ^ Credits^",
- #r$HelpMenu, #r$HelpInfo);
- \endtt
- Note the layout, and especially the carriage returns. The second and
- third arguments are themselves routines: the notation |#r$|, seldom
- seen in high-level Inform, allows routine names to become ordinary
- numerical values. The first routine, in this case called |HelpMenu|,
- is supposed to look at the variable |menu_item|. In the case when this
- is zero, it should return the number of entries in the menu (3 in the
- example). In any case it should set |item_name| to the title for the
- page of information for that item; and |item_width| to half its length
- in characters (this is used to centre titles on the screen: it is
- unfortunately tricky for the game to compute the length of a static
- string, so you have to tell it).
- In the case of item 0, the title should be that for the whole menu.
-
- The second routine, |HelpInfo| above, should simply look at |menu_item|
- (1 to 3 above) and print the text for that selection. After this returns,
- normally the game prints ``Press [Space] to return to menu'' but if
- the value 2 is returned it doesn't wait.
-
- Menu items can safely launch whole new menus, and it is easy to make
- a tree of these (which will be needed when it comes to providing hints
- across any size of game).
-
- \exercise Code an ``Invisiclues''-style sequence of hints for a puzzle,
- revealed one at a time, as a menu item.
-
- \answer{Note the magic line of assembly code here, which only works for
- Advanced games:
- \beginlines^^{``Invisiclues''}
- |[ GiveHint hint keypress;|
- | print_paddr hint; new_line; new_line;|
- | @read_char 1 0 0 keypress;|
- | if (keypress == 'H' or 'h') rfalse;|
- | rtrue;|
- |];|
- \endlines
- And a typical menu item using it:
- \beginlines
- | if (menu_item==1)|
- | { print "(Press ENTER to return to menu, or H for another hint.)^^";|
- | if (GiveHint("(1/3) What kind of bird is it, exactly?")==1) return 2;|
- | if (GiveHint("(2/3) Magpies are attracted by shiny items.")==1) return 2;|
- | "(3/3) Wave at the magpie with the kitchen foil.";|
- | }|
- \endlines}
-
- \bigskip
- Finally, though it should only be used sparingly (and again is restricted
- to ^{Advanced games}), one can change the ^{text style}. The command for
- this is ^|style| and its effects are loosely modelled on the ^{VT100}
- (design of terminal). The style can be |style roman|, |style bold|,
- |style reverse| or |style underline|. Again, remember that poor terminals
- may not be able to display these, so you shouldn't hide crucial information
- in them.^^{boldface}^^{roman text}^^{reverse video}^^{underlining}
-
-
- \section{25}{Dirty tricks}
-
-
- \ddanger The dirtiest tricks of all are those which bypass Inform's higher
- levels and program the Z-machine directly. There is an element of danger in
- ^{assembly language} programming, in that some combinations of unusual opcodes
- can look ugly on some incomplete or wrongly-written ^{interpreters}: so if you're
- doing anything complicated, test it as widely as possible.
- Note that none of the interesting effects work at all on ^{Standard games},
- only ^{Advanced games}.^^{dirty tricks}
-
- \ninepoint
-
- The best-researched and most reliable interpreter available by far is Mark
- Howell's ^{Zip}; as it's also the fastest, it will hopefully `take over' entirely.
- Next comes the ^{InfoTaskForce}, which is thorough and should give no serious
- trouble, but was written when the format was a little less well understood,
- and so (in some ports) gets some (rare) screen effects wrong. (It also lacks
- an ``undo'' feature, so the ^{``undo'' verb} automatically provided by the library
- routines won't work under ITF.) The other two publically-available
- interpreters are ^{pinfocom} and ^{zterp}, but these are unable to run Advanced
- games. In the last resort, sometimes it's possible to use one of Infocom's
- own supplied interpreters with a different game from that it came with; but only
- sometimes, as they may have inconvenient filenames `wired into them'. The
- author recommends that anyone using assembly-language features get hold of
- both ITF and Zip, and test on both.
-
- This all sounds rather unportable, though actually the core described below
- is pretty reliable. But remember that the unportability does have some genuine
- cause. Your game may be running on a screen which is anything from a 64 by 9
- pocket organiser up to a 132 by 48 X-window.
-
- Anyone wanting to really push the outer limits (say, by implementing
- ^{Space Invaders} or ^{NetHack}) will need to refer to {\sl The Specification
- of the Z-Machine}, which also documents Inform assembly language format.
- \bigskip
-
- Screen tricks are the commonest. An upper-level screen (which usually holds
- the status line) can be split off from the main screen:^^{screen tricks}
- \beginstt
- split_window n;
- \endtt^^|split window|
- creates one which is $n$ lines tall. (This doesn't change the display, and
- it can be resized at any time: but it needs to be tall enough to include all
- the lines you want to write to, as otherwise the interpreter may flounder:
- some will scroll the upper window, others won't.) The
- main screen is numbered 0, and the upper one 1; text output is switched between
- them by
- \beginstt
- set_window n;
- \endtt^^|set window|
- The lower window is just a text stream whose 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, the cursor can be moved by
- \beginstt
- set_cursor line column;
- \endtt^^|set cursor|
- where $(1,1)$ is the top left character. Printing on the upper window
- overlies printing on the lower, is always done in a fixed-space font
- and does not appear in a printed ^{transcript} of the game.
- However, before printing to the upper window, it is essential to
- change the printing format - that is, the |buffer_mode| opcode. Before
- printing, execute
- \beginstt
- buffer_mode 0;
- \endtt^^|buffer mode|
- and when returning to the normal screen,
- \beginstt
- buffer_mode 1;
- \endtt
- Otherwise, dodgy interpreters (like ITF) may continue trying to split
- lines at word breaks, and make a horrid mess.
- \medskip
-
- A convenient way to clear the screen is
- \beginstt
- erase_window $ffff;
- \endtt^^{clearing the screen}^^|erase window|
- but don't chance this in reverse video mode! (And don't assume that |erase_window|
- can erase individual windows - it should, but may not on bad interpreters.)
- \medskip
-
- Players can be gratuitously annoyed (on most machines, anyway) by the |beep| opcode.
- This is the only remotely portable ^{sound effect}.^^|beep|
- \medskip
-
- The ^{keyboard} can be read in remarkably flexible ways, using the |aread| and
- |read_char| opcodes.^^|read char|^^|aread|
- \beginstt
- aread text parse time function;
- \endtt
- will read from the keyboard, putting text into the |text| buffer, tokenising
- it onto the end of the |parse| buffer (unless this is zero), and calling
- \beginstt
- function(time);
- \endtt
- every |time| seconds that the user is thinking: the process ends if ever this
- function returns true. Thus (by |Replace|ing the |Keyboard| routine in the
- library files) you could, say, move around all the characters every ten seconds
- of ^{real time}.^^{timed input}
- \beginstt
- read_char 1 time function <result>;
- \endtt
- where |<result>| is a variable, will store in that variable the ASCII value
- of a single keypress. Once again, the |function| is called every |time| seconds
- and may stop this process early. Function keys return special values from 129
- onwards, in the order: cursor up, down, left, right, function key f1, ..., f12,
- keypad digit 0, ..., 9.^^{function keys}^^{cursor keys}
- \medskip
-
- Leafing through the dictionary of opcodes will reveal a few other interesting
- features. It's possible to change the input and ^{output streams} which, although
- only Zip gets this right, may be convenient for debugging purposes (creating
- scripts of all typed commands, for example). Finally, there are opcodes which
- tokenise (that is, simply compare dictionary entries against) arbitrary
- strings from arbitrary dictionaries, and which translate small doses of ASCII
- to internal Z-machine string format. Actually, one can avoid the need for this
- in many cases, by programming the parser correctly: see, for instance,
- the `Balances' game which manages without these features.
- \tenpoint
- \vfill\eject
- % ---------------------------------------------------------------------------
- % Appendices to the Inform Designer's Manual
- % ---------------------------------------------------------------------------
-
- \section{A1}{The Inform language}
-
- This is going to be a long appendix, full of lists and tables: but it has
- to appear somewhere, if only for reference. (Some technical commands
- for internal use only are skipped over: see the {\sl Technical Manual} for
- details of these.)
- \ninepoint
-
- \subsection{File format}
- When Inform reads in a file, it treats a few characters in special ways.
- The character |!| means the rest of the line (up to the next new-line) is
- a comment, and Inform throws it away. Tab characters are treated as
- spaces. Backslashes |\| fold strings together, so that the new-line and
- all subsequent spaces are ignored. New-lines have no significance;
- statements (and directives) are separated by semicolons |;|.^^{comments}
- ^^{backslash}^^{file format}
-
- \subsection{Directives}
- These are commands directly to the Inform compiler, like |Object|. They
- can, but need not, be prefaced by a hash character, |#|. The directives
- which Inform understands are:^^{directives}^^{hash character}
- \smallskip{\ninepoint
- \settabs 8 \columns
- \+ &|Abbreviate| \<string>&&& Declare an abbreviation\cr
- \+ &|Attribute| \<name>&&& Make a new attribute\cr
- \+ &|Class| ...&&& Define a new class\cr
- \+ &|Constant| \<name> \<value> &&& Define a named constant\cr
- \+ &|End| &&& End compilation here\cr
- \+ &|Endif| &&& End of conditional compilation\cr
- \+ &|Extend| ... &&& Extend the grammar for an existing verb\cr
- \+ &|Fake_action| \<name> &&& Make a new ``fake action''\cr
- \+ &|Global| \<name> ... &&& Declare a global variable\cr
- \+ &|Ifdef| \<name> &&& Compile only if constant is defined\cr
- \+ &|Ifndef| \<name> &&& Compile only if constant is undefined\cr
- \+ &|Ifnot| &&& Compile only if previous |If...| failed\cr
- \+ &|Ifv3| &&& Compile only for Standard games\cr
- \+ &|Ifv5| &&& Compile only for Advanced games\cr
- \+ &|Include| \<filename> &&& Include that file here\cr
- \+ &|Nearby| &&& Make an object inside the last |Object|\cr
- \+ &|Object| &&& Make an object\cr
- \+ &|Property| \<name> ... &&& Make a new property\cr
- \+ &|Replace| \<routine> &&& Don't compile this library routine\cr
- \+ &|Release| \<number> &&& Set the game's Release Number\cr
- \+ &|Serial| \<string> &&& Set the game's Serial Number\cr
- \+ &|Statusline| ... &&& Make the status line show score or time\cr
- \+ &|Switches| \<switches> &&& Set default compilation switches\cr
- \+ &|Verb| ... &&& Declare the grammar for a new verb\cr
- \smallskip}\noindent
-
- The ^{release number} of a game (by default 1) is generally an edition
- number; the ^{serial number} is the compilation date in the form
- 940924, that is, yymmdd. Inform sets this automatically on machines
- where the date is accessible, so the |Serial| directive is provided
- only for use on machines without such an internal clock.
-
- \danger Conditional compilation allows code for routines which need only
- exist in some ``versions" of your games. For instance,
- ^^{conditional compilation}
- \begintt
- print "Welcome to the ";
- #IFV3; print "Standard"; #IFNOT; print "Advanced"; #ENDIF;
- print " version of Zork LVI.";
- \endtt
- (The |#IFNOT| clause is optional.) 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 {\it part} of a
- statement. Thus, for instance,
- \begintt
- print #IFV3; "Standard"; #IFNOT; "Advanced"; #ENDIF;
- \endtt
- is {\sl not} legal.
-
- \ddanger The following directives are recondite and not for public use:
- \begintt
- Default Dictionary Listsymbols Listdict Listverbs Lowstring Stub System_file
- Trace Btrace Etrace Ltrace Notrace Nobtrace Noetrace Noltrace
- \endtt
-
- \subsection{Variables and arrays}
- 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 (e.g. in asking whether one is positive or not) but
- not when it doesn't (e.g. when it is used as an address).
- Global variables must be declared before use, by the ^|Global| directive:
- ^^{arrays}^^{variables}
- \begindisplay
- |Global| \<varname> = \<initial-value>\cr
- \phantom{|Global| \<varname>} |data| \<size>\cr
- \phantom{|Global| \<varname>} |string| \<size>\cr
- \phantom{|Global| \<varname>} |initial| \<value-1> ... \<value-$n$>\cr
- \phantom{|Global| \<varname>} |initstr| \<text>\cr
- \enddisplay
- For instance:
- \begintt
- Global turns = 1;
- Global buffer string 120; ! text buffer holding 120 characters
- Global task_scores initial 4 5 9 1 2 3 0; ! a 7-byte array
- Global players_name initstr "Graham"; ! an array of 6 chars
- \endtt
- When you declare a variable as an array (by |data|, |string|, ^|initial|
- or ^|initstr|)
- what actually happens is that Inform allocates as much space as you ask
- for, somewhere inside the machine, and stores the address of this array
- in the variable. You can get at entries of the array by^^|->|^^|-->|
- \begintt
- buffer->entry buffer-->entry
- \endtt
- which read (or write to) the |entry|-th byte (in the case of |->|) or
- word (for |-->|). A |data| array is initially full of zeros, while an
- |initial| array contains the given (byte) values, which all have to be
- constants for obvious reasons. A ^|string| array is a special kind of
- ^|data| array: the first byte contains its length (in bytes), and the
- rest are initially zero. ^|initstr| is the same but initialised to
- the given string. The text here is plain ASCII, and is not encrypted
- as constant strings tend to be. (This string format is used by the
- parser.)
-
- In addition, a routine can have from none up to 15 ^{local variables}.
-
- \warning There is also a stack, but it should be tampered with only
- carefully in times of dire need. Never call a variable ^|sp|, as this is the
- ^{stack pointer}, and if you must use the stack at all, be careful not to
- leave values on it: or your game may crash 1000 turns later, serving you
- right.
-
- \subsection{Constants}
- Inform ^{constants} can take many forms. The obvious ones are numbers,
- \begintt
- 123 $ee05 $$11011001
- \endtt
- being examples in decimal, hexadecimal and ^{binary} respectively. There
- are also
- \smallskip
- \settabs 8 \columns
- \+ &|##Action| && (The number of) the given action\cr
- \+ &|"some text"| && (The packed address of) the given string\cr
- \+ &|'c'| && (The ASCII code for) the given character\cr
- \+ &|'word'| && (The byte address of) its dictionary entry\cr
- \smallskip\par\noindent
- There is slight potential for confusion here: |'A'| evaluates to 65,
- but |'an'| to the dictionary address of the word `an'. Note that
- the construction |'sponge'| actually enters the word `sponge' into
- the dictionary if it wasn't already there. These are all legal
- constants:
- \begintt
- 31415 -1 $ff $$1001001 'lantern' ##Look 'X'
- "an emerald the size of a plover's egg"
- "~Hello,~ said Peter.^~Hello, Peter,~ said Jane.^"
- \endtt^^{Peter and Jane}
-
- \subsection{Quoted strings}
- Inside the text of a string, the character |^| is replaced by a new-line
- character, and the character |~| by a double-quote mark: these both make
- strings much easier to type.
-
- Inside a string (under Inform 5.3 or later) ^|@@|\<number> produces the
- character whose ASCII value is $n$, and you can use this to get untypeable
- characters from ^{foreign character sets}. (Or, for example, a literal
- ^{backslash}, by |@@92|.)
-
- For the |@| string escape and other obscure constant forms such as
- |#r$|, see the {\sl Technical Manual}.
-
- \subsection{Routines}
- Routines start with a |[| and end with a |]|. That is, they open with
- \begindisplay
- |[| \<Routine-name> \<local-var-1> ... \<local-var-$n$>|;|
- \enddisplay
- giving the names of local variables for the routine ($0\leq n\leq 15$).
- The routine ends with just |];|. (Routines embedded in object definitions
- are the same, except that no routine-name is given, and they may end in
- |],| if the object definition continues.)^^{routines}^^{embedded routines}
-
- The first few local variables also hold the arguments passed to the
- routine when the function is called. That is, if you have a routine
- \begintt
- [ Look from i j; ...some code...; ];
- \endtt
- ^^{function arguments}
- and it is called by |Look(attic);| then the local variable |from| will
- initially have the value |attic|. The rest all start out at zero.
-
- From Inform 5.3, if the first variable is given as ^|*| then
- tracing code is compiled to print details each time the routine
- is called.
-
- Function calls (that is, calls to routines) are legal with between 0
- and 3 arguments, and every routine always returns a value. If execution
- runs into the |];| at the bottom, that value is `true' (or 1) for an
- ordinary routine, or `false' (or 0) for an embedded one.
-
- \subsection{Labels}
- ^^{labels}
- In case you want to ^|jump| around inside a routine, you can define labels
- with a statement starting with a full stop, like |.labelname;|. It is
- legal, though ill-advised, to jump out of one routine and into another.
- Label names are global, so the same label name can't be used in two
- different routines.
-
- \subsection{Operators}
- Arithmetic (and other) ^{expressions} can contain the following:
- ^^{arithmetic operators}
- \smallskip
- \settabs 8 \columns
- \+ &|+ -| & plus, minus\cr
- \+ &|* / % & |{\tt\char`\|}
- & times, divide, remainder, bitwise and, bitwise or\cr
- \+ &|-> -->| & byte array, word array entry\cr
- \+ &|. .& .#| & property, property address, property length\cr
- \+ &|-| & unary minus\cr
- \+ &|++ --| & incrementing and decrementing variables (as in C)\cr
- \smallskip\par\noindent
- 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.
- Expressions are not allowed to contain conditions, nor assignments:
- |2+(i=3/j)| is not a legal expression. Some legal examples:
- \begintt
- 4*(x+3/y) Fish(x)+Fowl(y) lamp.time buffer->5
- \endtt
- Note that |++| and |--| can only be applied to variables, not to
- properties or array entries.
-
- \subsection{Assignments}
- There are four forms allowed are:^^{assignments}
- \begindisplay
- \<variable> |=| \<value>|;|\cr
- \<byte-array>|->|\<entry> |=| \<value>|;|\cr
- \<word-array>|-->|\<entry> |=| \<value>|;|\cr
- \<object>|.|\<property> |=| \<value>|;|\cr
- \enddisplay
- For example:
- \begintt
- i=-15-j; i=j-->1; albatross.weight = albatross.weight + 1;
- (paintpot.&roomlist)-->i = location; turns++;
- \endtt
- One can also |inc| or |dec| (increment or decrement) a variable,
- with |inc score;| being equivalent to the more modern |score++;|
-
- Although these look logical, they are not allowed:
- \begintt
- paintpot.#roomlist = 5;
- paintpot.&roomlist = array;
- \endtt
- because one cannot change the size or address of a property in play.
-
- \warning A ^{division by zero} error (such as $n$|/0| or $n$|%0|)
- may crash the game at run time.
-
- \warning Attempting to write to a property which an object does not
- have may crash the game at run time.
-
- \subsection{Conditions}
- A simple condition is
- \begindisplay
- \<a>\quad\<relation>\quad\<b>
- \enddisplay
- where the relation is one of^^{conditions}
- \smallskip
- \settabs 8 \columns
- \+ &|==| && |a| equals |b|\cr
- \+ &|~=| && |a| doesn't equal |b|\cr
- \+ &|< > >= <=| && numeric (signed) comparisons\cr
- \+ &|has| && object |a| has attribute |b|\cr
- \+ &|hasnt| && object |a| hasnt attribute |b|\cr
- \+ &|in| && object |a| is currently held by object |b|\cr
- \+ &|notin| && ...is not...\cr
- \smallskip
- With |==| (and |~=|) only, one may also write the useful construction
- \begindisplay
- \<something> |==| \<v1> |[or| \<v2> |[or| \<v3>|]]|
- \enddisplay^^|or|
- which is true if the first something is any of the values given. (An
- idiosyncracy of Inform, for `hardware reasons', is that you can only have
- three). Conditions can be combined by the |&&| and
- \orsign~ operators:
- \begindisplay
- \<condition1> |&&| \<condition2>\cr
- \<condition1>~\orsign~ \<condition2>\cr
- \enddisplay
- true if both, or either (respectively) are true. These are always tested
- left to right until the outcome is known. So, for instance,
- \begindisplay
- |i==1 | \orsign | Explode(2)==2|
- \enddisplay
- does not call |Explode| if |i| is 2. Examples of legal conditions are:
- \begindisplay
- |i==1 or 2 or 3|\cr
- |door has open |\orsign| (door has locked && key in player)|\cr
- \enddisplay
-
- \subsection{Built-in functions}
- A very few functions are built into the language of Inform itself
- (rather than written out longhand in the library files), but they
- behave like any other routines. They are:^^{built-in functions}
- \smallskip
- \settabs 8 \columns
- \+ &|parent(obj)| && parent of object\cr
- \+ &|sibling(obj)| && sibling of object\cr
- \+ &|child(obj)| && eldest child of object\cr
- \+ &|children(obj)| && number of (direct) children of object\cr
- \+ &|eldest(obj)| && same as |child|\cr
- \+ &|youngest(obj)| && youngest child of object\cr
- \+ &|elder(obj)| && elder sibling of object\cr
- \+ &|younger(obj)| && same as |sibling|\cr
- \+ &|random(x)| && uniformly random number between 1 and $x$\cr
- \+ &|indirect(addr)| && call routine with address |addr|\cr
- \smallskip\par\noindent
-
- \warning |random(0)| may cause a division by zero error.
-
- \subsection{Printing commands}
- A string on its own, such as^^{printing commands}
- \begintt
- "The world explodes in a puff of garlic.";
- \endtt^^{puff of garlic}
- is printed, with a new-line, and the current routine is returned from with
- return value `true', i.e., 1. In addition:
- \smallskip
- \settabs 8 \columns
- \+ &|new_line| && prints a new-line\cr
- \+ &|print ...| && prints the given things\cr
- \+ &|print_ret ...| && prints, new-lines and returns 1\cr
- \+ &|spaces n| && prints $n$ spaces\cr
- \+ &|print_addr a| && print string at byte address |a|\cr
- \+ &|print_paddr a| && print string at packed address |a|\cr
- \+ &|font on/off| && turns proportional fonts on/off\cr
- \+ &|style ...| && in Advanced games, sets text style\cr
- \+ &|box "s1" ... "sn"| && in Advanced games, puts up quotation box\cr
- \+ &|inversion| && prints out the current Inform version number\cr
- \smallskip\par\noindent
- |print| and |print_ret| take a comma-separated list of things to print out,
- which can be: |"strings"|, |char n| (print the character with this ASCII
- value) or |variable| (print out the variable as a signed number). The
- text |style| can be any of
- \begintt
- roman reverse bold underline
- \endtt
-
- \subsection{Manipulating objects}
- \smallskip
- \settabs 8 \columns
- \+ &|remove obj| && removes object from the tree\cr
- \+ &|move o1 to o2| && moves |o1| to become youngest child of |o2|\cr
- \+ &|give obj a1 ... an| && gives attributes to |obj|\cr
- \smallskip\par\noindent
- Attributes beginning with a |~| are taken away rather than given.
-
- \subsection{Returning from routines}
- \smallskip
- \settabs 8 \columns
- \+ &|return| && Return true, i.e. 1\cr
- \+ &|return x| && Return value $x$\cr
- \+ &|rtrue| && Return true, i.e. 1\cr
- \+ &|rfalse| && Return false, i.e. 0\cr
- \smallskip^^{returning from routines}
-
- \subsection{Blocks of code}
- 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
- \begintt
- if (i==1) print "The water rises!";
- if (i==2) { print "The water rises further...";
- water++;
- }
- \endtt^^{blocks of code}^^{braces}
- 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,
- \begintt
- if (i>1) if (water<10) "The water is beginning to worry you.";
- \endtt
- is legal. (One small exception: an |if| followed by an |else|
- counts as two statements, and this means Inform handles ^{hanging elses}
- rather poorly: so it's wise to brace so that |else| is clearly unambiguous.)
-
- \subsection{Control constructs} Inform provides:^^{control constructs}
- \begindisplay
- |if| \<condition> \<block1> |[else| \<block2>|]|\cr
- |while| \<condition> \<block>\cr
- |do| \<block> |until| \<condition>\cr
- |for (|\<initialise>|:|\<test>|:|\<each time>|)|\cr
- |objectloop (|\<variable> |in| \<object>|)|\cr
- |objectloop (|\<variable> |from| \<object>|)|\cr
- |objectloop (|\<variable> |near| \<object>|)|\cr
- |break|\cr
- |jump| \<label>\cr
- \enddisplay
- Some of these will be familiar to most. The ^|for| construct is essentially
- the same as that in C, except for the colons |:| (which in C would be
- semicolons). Its carries out the initial assignment(s), then executes the
- code for as long as the condition holds, executing the end assignment after
- each pass through the code. For instance,
- \begintt
- for (i=1:i<=10:i++) print i, " ";
- \endtt
- counts to 10. All three clauses are optional, and the empty condition is
- always true; multiple assignments can be made. For instance:
- \begintt
- for (i=0,j=10:i<10:i++,j--) print i, " + ", j, " = ", i+j, "^";
- for (::) print "Ha!^";
- \endtt
- the latter laughing maniacally forever.
-
- ^|break| breaks out of the current loop (not quite the same as breaking out
- the current block of code: |if| statements don't count as loops in this
- regard).
-
- ^|objectloop| goes through the object tree, and is extremely useful. |from|
- means from the given object through its siblings; |in| means through all
- children of the given object, and |near| means through all children of the
- parent of the object. For instance, the following do the same thing:
- \begintt
- objectloop (x in lamp) { ... }
- for (x=child(lamp): x~=0: x=sibling(x)) { ... }
- \endtt
- Note that the library creates a variable called |top_object| holding the
- highest existing object number: so a way to ^{loop over every object}
- defined in your own code is
- \begintt
- for (i=player+1: i<=top_object: i++) ...
- \endtt^^|top object|
- since |player| is always set to ^|selfobj|, which is the last object created
- by the library.
-
- \warning When looping through the object tree, be careful if you are altering
- it at the same time. For instance,
- \begintt
- objectloop (x in rucksack) remove x;
- \endtt
- is likely to go horribly wrong - it's safer not to cut down a tree
- while actually climbing it. The safe way is to keep lopping branches off,
- \begintt
- while (child(x)~=0) remove child(x);
- \endtt
-
- \exercise Write a routine to print out ^{prime factorisations} of numbers from
- 2 to 100.
-
- \answer{|Primes(100)|, where:\beginlines
- |[ 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;|
- | }|
- |];|
- \endlines^^{prime factorisations}
- (which was the first algorithm ever compiled by Inform).}
-
- \subsection{Actions}
- The commands
- \begindisplay
- |<| \<Action> |[|\<first-object> |[|\<second-object>|]]| |>|\cr
- |<<| \<Action> |[|\<first-object> |[|\<second-object>|]]| |>>|\cr
- \enddisplay
- cause the given ^{actions} to take place. In the latter case, the current
- routine then returns 1, or true.
- \vfill\eject
-
- \section{A2}{Library objects, properties and attributes}
-
- \quote
- A Model must be built which will get everything in without
- a clash; and it can do this only by becoming intricate,
- by mediating its unity through a great, and finely ordered,
- multiplicity.
- \widepoemby{^{C. S. Lewis} (1898-1963)}{The Discarded Image}
-
- The library defines the following
- ^{special objects}:^^{objects in library}
- \medskip\ninepoint
- \noindent |compass|\inpar To contain the directions. A direction
- object provides a |door_dir| property, and should have the
- |direction| attribute. A compass direction with |enterable|, if
- there is one (which there usually isn't), will have an
- |Enter| action converted to |Go|.
-
- \noindent |n_obj|\inpar Both the object signifying the
- abstract concept of `northness', and the `north wall' of
- the current room. (Thus, if a player types ``examine the north wall''
- then the action |Examine n_obj| will be generated.) Its
- |door_dir| property holds the direction property it corresponds
- to (|n_to|).^^{walls}^^{direction objects}
-
-
- \noindent |s_obj|, |e_obj|, |w_obj|, |ne_obj|, |nw_obj|, |se_obj|,
- |sw_obj|\inpar Similar.
-
- \noindent |u_obj|, |d_obj|, |in_obj|, |out_obj| \inpar Similar:
- the parser uses these if the player refers to ^{``ceiling''},
- ^{``floor''}. (|in_obj| and |out_obj| differ slightly, because
- ``in'' and ``out'' are verbs with other effects in some cases.)
-
- \noindent ^|thedark|\inpar A pseudo-room representing `being in
- darkness'. |location| is then set to this room, but the player
- object is not moved to it. Its |description| can be changed to
- whatever ``It is dark here'' message is desired.
-
- \noindent ^|selfobj|\inpar The player object. However, do not
- refer to |selfobj| directly: always refer to |player|, a variable
- whose value is usually indeed |selfobj| but which might become
- |green_frog| if the player is transformed into one.
-
- \medskip\tenpoint
- Here is a concise account of all the ^{normal rules} concerning
- all the library's attributes. (Except that: rules about how
- the parser sorts out ambiguities are far too complicated to
- include here, but should not concern designers anyway; and the
- definitions of ``scope'' and ``darkness'' are given in the
- main text.) Of course these rules are all modifiable using
- suitable |before| and |after| rules. But a good deal of
- pragmatism has gone into their design, or rather evolution.
- ^^{attributes in library}
- \medskip\ninepoint
-
- \noindent ^|absent|\inpar A ^{`floating object'} (one with a
- |found_in| property, which can appear in many different rooms)
- which is |absent| will no longer appear in the game.
-
- \noindent ^|animate|\inpar `Is alive (human or animal)'. Can be
- spoken to in ``richard, hello'' style; matches the |creature|
- token in grammar; picks up ``him'' or ``her'' (according to
- gender) rather than ``it'', likewise ``his''; an object the
- player is changed into becomes |animate|; some messages read
- ``on whom'', etc., instead of ``on which''; can't be taken;
- its subobjects ``belong to'' it rather than ``are part of'' it;
- messages don't assume it can be ``touched'' or ``squeezed'' as
- an ordinary object can; the actions |Attack|, |ThrowAt| are
- diverted to |life| rather than rejected as being `futile
- violence'.
-
- \noindent ^|clothing|\inpar Can be worn.
-
- \noindent ^|concealed|\inpar `Concealed from view but present'.
- The player's object has this; an object which was the player until
- |ChangePlayer| happened, loses this property; a |concealed|
- |door| can't be entered; does not appear in room descriptions.
-
- \noindent ^|container|\inpar Affects scope and light (see definitions
- in the main text); object lists recurse through it if |open| (or
- |transparent|); may be described as closed, open, locked, empty;
- a possession will give it a |LetGo| action if the player tries to
- remove it, or a |Receive| if something is put in;
- things can be taken or removed from it, or inserted into it,
- but only if it is |open|; likewise for ``transfer'' and ``empty'';
- room descriptions describe using |when_open| or |when_closed| if
- given; if there is no defined |description|, an |Examine| causes the
- contents to be searched (i.e. written out) rather than a message
- ``You see nothing special about...''; |Search| only reveals the
- contents of |container|s, otherwise saying ``You find nothing''.
-
- \noindent ^|direction|\inpar If the player tries to walk this way
- or enter it, a |Go| rather than |Enter| action is generated.
- (Used only in one line of grammar, but a crucial one.)
-
- \noindent ^|door|\inpar `Is a door or bridge'. Room descriptions
- describe using |when_open| or |when_closed| if given; and an |Enter|
- action becomes a |Go| action. If a |Go| has to go through this
- object, then: if |concealed|, the player `can't go that way';
- if not |open|, then the player is told either that this cannot
- be ascended or descended (if the player tried ``up'' or ``down''
- which went through it), or that it is in the way (otherwise);
- but if neither, then its |door_to| property is consulted to
- see where it leads; finally, if this is zero, then it is said
- to `lead nowhere' (a safety precaution) and otherwise the player
- actually moves to the location.
-
- \noindent ^|edible|\inpar Can be eaten (and thus removed from game).
-
- \noindent ^|enterable|\inpar Affects scope and light (see definitions
- in the main text); only an |enterable| on the floor can be entered.
-
- \noindent ^|female|\inpar Only applies to |animate|s (and cannot have
- a |found_in| list for arcane reasons), and only affects the parser's
- use of pronouns: it says ``her'' is appropriate but ``him'' and ``his''
- are not.
-
- \noindent ^|general|\inpar A general-purpose attribute, defined by
- the library but never looked at or altered by it. This is left
- free to mean something different for each object: often used by
- programmers for something like ``the puzzle for this object has been
- solved''.
-
- \noindent ^|light|\inpar `Is giving off light.' (See definition of
- `when there is light' in main text.) Also: the parser understands
- ``lit'', ``lighted'', ``unlit'' using this; inventories will
- say ``(providing light)'' of it, and so will room descriptions if the
- current |location| is ordinarily dark; it will never be automatically
- put away into the player's |SACK_OBJECT| (as it might plausibly be
- inflammable or the main light source).
-
- \noindent ^|lockable|\inpar Can be locked or unlocked by a player
- holding its key object, which is in the property |with_key|;
- if a |container| and also |locked|, may be called ``locked'' in
- inventories.
-
- \noindent ^|locked|\inpar Can't be opened. If a |container|
- and also |locked|, may be called ``locked'' in inventories.
-
- \noindent ^|moved|\inpar `Has once been held by the player'. Objects
- (immediately) owned by the player after |Initialise| has run are given
- it; at the end of each turn, if an item is newly held by the player
- and is |scored|, it is given |moved| and |OBJECT_SCORE| points are
- awarded; an object's |initial| message only appears in room
- descriptions if it is unmoved.
-
- \noindent |on |\inpar `Switched on.' A |switchable| object with this
- is described by |with_on| in room descriptions; it will be called
- ``switched on'' by |Examine|.^^|on|
-
-
- \noindent ^|open|\inpar `Open door or container'. Affects scope and
- light (see definitions in the main text), and: lists (such as inventories)
- recurse through an |open| |container|; if a |container|, called open by some
- descriptions; things can be taken or removed from an |open| |container|;
- similarly inserted, transferred or emptied. An |open| |door| can be
- entered. Described by |when_open| in room descriptions.
-
- \noindent ^|openable|\inpar Can be opened or closed, unless |locked|.
-
- \noindent ^|proper|\inpar Its short name is a proper noun, and never preceded
- by ``the'' or ``The''. The player's object must have this (so something
- changed into will be given it).
-
- \noindent ^|scenery|\inpar Not listed (by the library) in room descriptions,
- ``not portable'' to be taken; ``you are unable to'' pull, push, or turn it.
-
- \noindent ^|scored|\inpar The player gets |OBJECT_SCORE| points for picking
- it up for the first time; or, if a room, |ROOM_SCORE| points for visiting
- it for the first time.
-
- \noindent ^|static|\inpar ``Fixed in place'' if player tries to take, remove,
- pull, push or turn.
-
- \noindent ^|supporter|\inpar `Things can be put on top of it'.
- Affects scope and light (see definitions in the main text);
- object lists recurse through it; a possession will give it a
- |LetGo| action if the player tries to remove it, or a |Receive|
- if something is put in; things can be taken or removed from it,
- or put on it; likewise for transfers; a player inside it is said
- to be ``on'' rather than ``in'' it; room descriptions list
- its contents in separate paragraphs if it is itself listed.
-
- \noindent ^|switchable|\inpar Can be switched on or off; listed
- as such by |Examine|; described using |when_on| or |when_off|
- in room descriptions.
-
- \noindent ^|talkable|\inpar Player can talk to this object in
- ``thing, do this'' style. (This is useful for microphones and
- the like.)
-
- \noindent ^|transparent|\inpar Affects scope and light
- (see definitions in the main text: it roughly means `contents
- always visible'). A |transparent| container is treated as if
- it were |open| for printing of contents.
-
- \noindent ^|visited|\inpar Given to a room when a |Look| first
- happens there: if this room is |scored| then |ROOM_SCORE| points
- are awarded. Affects whether room descriptions are abbreviated
- or not.
-
- \noindent ^|workflag|\inpar Temporary flag used by Inform internals,
- also available to outside routines; can be used to select items
- for some lists printed by |WriteListFrom|.
-
- \noindent ^|worn|\inpar `Item of clothing being worn'. Should
- only be held by an object being immediately carried by player.
- Affects inventories; doesn't count towards the limit of
- |MAX_CARRIED|; won't be automatically put away into the
- |SACK_OBJECT|; a |Drop| action will cause a |Disrobe| action first;
- so will |PutOn| or |Insert|; you can't insert or remove something
- from a |worn| container.
-
- \tenpoint\bigskip
- Note that very few attributes sensibly apply to rooms: only really
- |light|, |scored| and |visited|, together with |general| if you
- choose to use it. Note also that an object cannot be both a
- |container| and a |supporter|; and that the old attribute ^|autosearch|,
- which was in earlier releases, has been withdrawn as obselete.
- \bigskip
-
- Next, definitions of properties which sensibly apply to ``objects''
- (meaning, things which are not rooms):^^{properties in library}
- \ninepoint
-
- \noindent ^|after|\inpar List of rule routines to be applied in sequence
- after an action takes place. (For a room, receives all actions in that
- room; for a player-object, all actions by the player as that object.)
-
- \noindent ^|article|\inpar Indefinite article for object (defaults to `a').
-
- \noindent ^|before|\inpar List of rule routines to be applied in sequence
- before an action takes place. (For a room, receives all actions in that
- room; for a player-object, all actions by the player as that object.)
-
- \noindent |cant_go|\inpar Message to print (or routine to print one) when
- a player tries to go in an impossible direction from this room (defaults to
- ``You can't go that way.")^^|cant go|
-
-
- \noindent ^|capacity|\inpar Number of objects a |container| or |supporter|
- can hold (defaults to 100); number of things the player can carry (when
- the player is this object), initially set to |MAX_CARRIED| for the standard
- player object.
-
- \noindent ^|daemon|\inpar Routine to run each turn (once activated by a
- |StartDaemon| and until stopped by a |StopDaemon|). Note: the same object
- cannot have both a |daemon| and a |time_out|.
-
- \noindent ^|describe|\inpar Routine (only) to describe object: over-rides a
- room's |description| to give main room description, if set; over-rides an
- object's usual listing when it appears in a room description.
-
- \noindent ^|description|\inpar |Examine| message, or routine to print one out,
- for an object; main room description, or routine to print one, for a room.
-
- \noindent |door_dir|\inpar Direction (that is, direction property, such as
- |n_to|, not direction object) that a |door| goes via, or a routine
- which returns this information; also used for direction objects, see
- the |compass| notes above.^^|door dir|
-
-
- \noindent |door_to|\inpar Room that a |door| connects to, or routine
- returning this; a value of 0 means `leads nowhere' (but this is not the
- ideal way to implement such a door).^^|door to|
-
-
- \noindent |each_turn|\inpar String to print, or list of routines to
- run, each turn that the object is in scope, after all timers and daemons
- have run.^^|each turn|
-
-
- \noindent |found_in|\inpar List of rooms in which a ``floating object''
- (that is, one present in multiple rooms) is found, unless it has |absent|,
- in which case it is nowhere to be found.^^|found in|
-
-
- \noindent ^|initial|\inpar Initial description of object not yet picked up,
- or routine to print one.
-
- \noindent ^|invent|\inpar Routine to change its inventory listing: see
- main text.
-
- \noindent ^|life|\inpar List of rule routines to be applied in sequence
- after an action making sense for an |animate| object takes place.
-
- \noindent ^|name|\inpar List of ^{dictionary words} referring to an object
- (note: uniquely, these dictionary words are given in double quotes |"thus"|,
- whereas in all other circumstances they would be |'thus'|; part tradition,
- part defence against |'a'| single-letter ambiguity). For
- a room, lists dictionary words which ``do not need to be referred to in
- this game''.
-
- \noindent ^|number|\inpar A general purpose property left free: conventionally
- holding a number like ``number of turns' battery power left''. (Except:
- an object to be used as a player-object must provide one, and it isn't left
- free.)
-
- \noindent |parse_name|\inpar Routine (only) to parse object's name
- (this overrides the |name| and is also used in determining if two objects
- are describably identical): see main text.^^|parse name|
-
-
- \noindent ^|plural|\inpar The plural name of an object (when in the presence
- of others like it), or routine to print it.
-
- \noindent |short_name|\inpar The short name of an object (like ``brass lamp"),
- or routine to print it.^^|short name|
-
-
- \noindent |time_left|\inpar Number of turns left until timer (if set,
- which must be done using |StartTimer|) goes off.^^|time left|
-
-
- \noindent |time_out|\inpar Routine to run when timer goes off (having been
- set by |StartTimer| and not in the mean time stopped by |StopTimer|). Note:
- the same object cannot have both a |daemon| and a |time_out|.^^|time out|
-
-
- \noindent |when_closed|\inpar |Look| description of something closed
- (|door| or |container|), or routine to print one.^^|when closed|
-
-
- \noindent |when_open|\inpar |Look| description of something open
- (|door| or |container|), or routine to print one.^^|when open|
-
-
- \noindent |when_off|\inpar |Look| description of a |switchable| which isn't
- |on|, or routine to print one.^^|when off|
-
- \noindent |when_on|\inpar |Look| description of a |switchable| which is |on|,
- or routine to print one.^^|when on|
-
- \noindent |with_key|\inpar Key object needed to lock/unlock a |lockable| object;
- player must explicitly name it as the key being used and be holding it at the
- time to use it. May be 0, in which case no key fits.^^|with key|
-
- \medskip\noindent together with the properties^^{direction properties}
- \begintt
- n_to s_to ne_to se_to u_to d_to
- e_to w_to nw_to sw_to in_to out_to
- \endtt
- each of which can be map connections to other routines, or strings
- (in which case they are printed if the player tries to go that way,
- but the move is not allowed and no further action is taken),
- or routines (in which case they are called to decide whether the
- map connection exists or not, and if so where it leads).
-
- \warning Do not confuse |n_to| and so on with the 12 direction
- objects, |n_obj| et al.^^{direction objects}
-
- \tenpoint
- \section{A3}{All the entry points, library routines and constants}
-
- Entry points are routines which you can provide, if you choose to,
- and which are called by the library routines to give you the option of
- changing the rules. All games {\bf must} define an ^|Initialise|
- routine, which is obliged to set the |location| variable to a room;
- the rest are optional.^^{entry points}
- \ninepoint
-
- \noindent ^|AfterLife|\inpar When the player has died (a condition signalled
- by the variable |deadflag| being set to a non-zero value other than
- 2, which indicates winning), this routine is called: by setting
- |deadflag=0| again it can resurrect the player.
-
- \noindent ^|Amusing|\inpar Called to provide an ``afterword" for players who
- have 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.)
-
- \noindent ^|DarkToDark|\inpar Called when a player goes from one dark room
- into another one; a good excuse to kill the player off in anyone's book.
-
- \noindent ^|DeathMessage|\inpar Prints up ``You have died" style messages, for
- |deadflag| values of 3 or more. (If you choose ever to set |deadflag|
- to such.)
-
- \noindent ^|GamePostRoutine|\inpar A kind of super-|after| rule, which
- applies to all actions in the game, whatever they are:
- use only in the last resort.
-
- \noindent ^|GamePreRoutine|\inpar A kind of super-|before| rule, which
- applies to all actions in the game, whatever they are: use only in the last
- resort.
-
- \noindent ^|Initialise|\inpar A compulsory routine, which must set |location|
- and is convenient for miscellaneous initialising, perhaps for random settings.
-
- \noindent ^|InScope|\inpar An opportunity to place extra items in scope during
- parsing, or to change the scope altogether. (If |et_flag| is 1 when this is
- called, the scope is being worked out for |each_turn| reasons; otherwise for
- everyday parsing.)
-
- \noindent ^|LookRoutine|\inpar Called at the end of every |Look| description.
-
- \noindent ^|NewRoom|\inpar Called when the room changes, before any
- description of it is printed.
- (This happens no matter how the change of room occurred.)
-
- \noindent ^|ParseNumber|\inpar An opportunity to parse numbers in a different
- (or additional) way.
-
- \noindent ^|ParserError|\inpar The chance to print different parser error
- messages (like ``I don't understand that sentence'').
-
- \noindent ^|PrintRank|\inpar 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.)
-
- \noindent ^|PrintVerb|\inpar A chance to change the verb printed out in a
- parser question (like ``What do you want to (whatever)?'') in case an unusual
- verb via |UnknownVerb| has been constructed. Returns true (or 1) if it has
- printed something.
-
- \noindent ^|PrintTaskName|\inpar Prints the name of a game task
- (such as ``driving the car").
-
- \noindent ^|TimePasses|\inpar 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.
-
- \noindent ^|UnknownVerb|\inpar
- Called by the parser when it hits an unknown verb,
- so that you can transform it into a known one.
-
- \tenpoint\bigskip
-
- Library routines which are ``open to the public":^^{library routines}
-
- \bigskip\ninepoint
-
- \noindent |Achieved(task)|\inpar Indicate the |task| is achieved (which only
- awards score the first time).
-
- \noindent |AllowPushDir()|\inpar Signal that an attempt to push an object from
- one place to another should be allowed.
-
- \noindent |CDefArt(object)|\inpar Print the capitalised definite article and
- short name of |object|.
-
- \noindent |ChangePlayer(object, flag)|\inpar Cause the player at the keyboard to
- play as the given object, which must have a |number| property supplied. If
- the |flag| is set to 1, then subsequently print messages like ``(as Ford
- Prefect)'' in room description headers. This routine, however, prints nothing
- itself.
-
- \noindent |DefArt(object)|\inpar Print the definite article and short name of
- |object|.
-
- \noindent |DoMenu(text,routine,routine)|\inpar Produce a menu.
-
- \noindent ^|EnglishNumber(x)|\inpar Prints out |x| in English (e.g.,
- ``two hundred and seventy-seven").
-
- \noindent |HasLightSource(object)|\inpar Returns true if |object| ``has light''.
-
- \noindent |InDefArt(object)|\inpar Print the indefinite article and short name
- of |object|.
-
- \noindent |NextWord()|\inpar Returns the next dictionary word in the player's
- input, moving the word number |wn| on by one. Returns -1 if the player's input
- has run out, and 0 if the word is not in the dictionary.
-
- \noindent |OffersLight(object)|\inpar Returns true if |object| ``offers light''.
-
- \noindent |PlaceInScope(object)|\inpar Puts |object| into scope for the parser.
-
- \noindent |PlayerTo(place, flag)|\inpar Move the player to |place|. Unless
- |flag| is given and is 1, describe the player's surroundings.
-
- \noindent |PrintShortName(object)|\inpar Print the short name of |object|.
- (This is protected against |object| having a meaningless value.)
-
- \noindent |ScopeWithin(object)|\inpar Puts the contents of |object| into scope,
- recursing downward according to the usual scope rules.
-
- \noindent |SetTime(time,rate)|\inpar Set the game clock (a 24-hour clock) to the
- given |time| (in seconds since the start of the day), to run at the given |rate|
- $r$: $r=0$ means it does not run, if $r>0$ then $r$ seconds pass every turn,
- if $r<0$ then $-r$ turns pass every second.
-
- \noindent |ScopeWithin(object)|\inpar Puts the contents of |object|, recursing
- downward according to the usual scope rules.
-
- \noindent |StartDaemon(object)|\inpar Makes the daemon of |object| active, so
- that its |daemon| routine will be called every turn.
-
- \noindent |StartTimer(object, time)|\inpar Starts the timer of |object|, set
- to go off in |time| turns, at which time its |time_out| routine will be called
- (it must provide a |time_left| property).
-
- \noindent |StopDaemon(object)|\inpar Makes the daemon of |object| inactive, so
- that its |daemon| routine is no longer called.
-
- \noindent |StopTimer(object)|\inpar Stops the timer of |object|, so that
- it won't go off after all.
-
- \noindent |TryNumber(wordnum)|\inpar Tries to parse the word at |wordnum| as a
- number (recognising decimal numbers and English ones from ``one'' to
- ``twenty''), returning -1000 if it fails altogether, or the number.
- Values exceeding 10000 are rounded down to 10000.^^|TryNumber|
-
- \noindent |WriteListFrom(object, style)|\inpar Write a list of |object| and its
- siblings, with |style| a bitmap of options.
-
- \noindent |YesOrNo()|\inpar Assuming that a question has already been printed,
- wait for the player to type ``yes'' or ``no'', returning true or false
- accordingly.
-
- \tenpoint\bigskip
-
- And, finally, the constants:
-
- \bigskip\ninepoint
-
- \noindent |AMUSING_PROVIDED|\inpar To indicate that an |Amusing| routine
- is provided.
-
- \noindent |DEBUG|\inpar To include the special ``debugging" verbs.
-
- \noindent ^|Headline|\inpar Style of game and copyright message.
-
- \noindent |MAX_CARRIED|\inpar Maximum number of (direct) possessions
- the player can carry.
-
- \noindent |MAX_SCORE|\inpar Maximum game score.
-
- \noindent |MAX_TIMERS|\inpar Maximum number of timers or daemons active
- at any one time (defaults to 32).
-
- \noindent |NUMBER_TASKS|\inpar Number of ``tasks'' to perform.
-
- \noindent |OBJECT_SCORE|\inpar Score for picking up a |scored| object
- for the first time.
-
- \noindent |ROOM_SCORE|\inpar Score for visiting up a |scored| room
- for the first time.
-
- \noindent |SACK_OBJECT|\inpar Object which acts as a ``rucksack'',
- into which the game automatically tidies away things for the player.
-
- \noindent ^|Story|\inpar Story name, conventionally in CAPITAL LETTERS.
-
- \noindent |TASKS_PROVIDED|\inpar To indicate that ``tasks'' are provided.
-
- \vfill\eject
-
- \section{A4}{All the Inform error messages}
-
- \ninepoint
- Inform can produce about 230 different ^{error messages}. The error messages
- were tidied-up and made more consistent in Inform 5.4, which the text here
- comes from, but earlier editions were similar. Since interpreters can in
- some cases crash horribly when given incorrect files, Inform never writes a
- file which caused an error, though it will permit files which incurred only
- warnings.
-
- \subsection{Fatal errors}\medskip\noindent
- To begin with, ^{fatal errors} (which stop Inform in its tracks) come in three
- kinds, the first containing only this one:
- \beginlines
- |Too many errors: giving up|
- \endlines
- After 100 errors, Inform stops (in case it has been given the wrong source file
- altogether). Secondly, file input/output can go wrong. Most commonly, Inform
- has the wrong filename:
- \beginlines
- |Couldn't open input file <filename>|
- |Couldn't open output file <filename>|
- |Couldn't open transcript file <filename>|
- |Couldn't open debugging information file <filename>|
- |Couldn't open temporary file 1 <filename>|
- |Couldn't open temporary file 2 <filename>|
- |Too many files have included each other: increase #define MAX_INCLUSION_DEPTH|
- \endlines
- (Temporary files are used (on most machines) for temporary storage space
- during compilation. They are removed afterwards.)
- The last error only occurs if 5 files all include each other. Increasing this
- |#define| means re-compiling Inform from its C source, a drastic measure.
- The remaining file-handling errors usually mean that the disc is full:
- something has gone wrong with an already-open file.
- \beginlines
- |I/O failure: couldn't read from source file|
- |I/O failure: couldn't write to temporary file 1|
- |I/O failure: couldn't reopen temporary file 1|
- |I/O failure: couldn't read from temporary file 1|
- |I/O failure: couldn't write to temporary file 2|
- |I/O failure: couldn't reopen temporary file 2|
- |I/O failure: couldn't read from temporary file 2|
- |I/O failure: couldn't write to story file|
- |I/O failure: couldn't write to transcript file|
- |I/O failure: can't write to debugging information file|
- \endlines
- The third class of fatal error is Inform ^{running out of memory}. It might
- fail drastically, having not enough memory to get started, as follows...
- \beginlines
- |Couldn't allocate memory|
- |Couldn't allocate memory for an array|
- \endlines
- (There are four similar |hallocate| errors unique to the PC `Quick C' port.)
- More often it will run out in the course of compilation, like so:
- \beginlines
- |The memory setting <setting> (which is <value> at present) has been exceeded.|
- |Try running Inform again with $<setting>=<some-larger-number> on the command line.|
- \endlines
- For details of the ^{memory settings}, see the next section.
-
- \subsection{Errors}\medskip\noindent
- There are a few conventions. Anything in double-quotes is a quotation from
- your source code; other strings are in single-quotes. A message like
- \beginstt
- Expected ... but found "..."
- \endtt
- means that Inform expected something different from what it found; if it
- doesn't say what it found, this usually means it found nothing (i.e. the
- statement was incomplete). Messages in the form
- \beginstt
- No such ... as "..."
- Not a ...: "..."
- \endtt
- mean that a name is unrecognised in the former case (say, a typing error
- might produce this), or is recognised but means something else in the latter
- case (an attempt to use a routine where a property is expected would give
- such an error).
-
- To begin with, the source-code format may go awry:
- \beginlines
- |Too many tokens on line (note: to increase the maximum, set|
- | $MAX_TOKENS=some-bigger-number on the Inform command line)|
- |Line too long (note: to increase the maximum length, set|
- | $BUFFER_LENGTH=some-bigger-number on the Inform command line)|
- |Too much text for one pair of "s to hold|
- |Too much text for one pair of 's to hold|
- |Open quotes " expected for text but found <text>|
- |Close quotes " expected for text but found <text>|
- \endlines
- (Usually |BUFFER_LENGTH| allows about 2000 characters per line.)
- When giving something (such as an object) an internal name, there are
- rules to be obeyed; for instance, you can't give an object the same name
- as a property already declared:
- \beginlines
- |Symbol name expected|
- |Symbol names are not permitted to start with an '_'|
- |Symbol name is too long: <text>|
- |Duplicated symbol name: <text>|
- \endlines^^{symbol names}
- At the top level, the most common ``no such command'' error is
- \beginlines
- |Expected an assignment, command, directive or opcode but found <text>|
- \endlines
- which means Inform didn't even understand the first word of the command.
- Directives to Inform can produce the following errors:
- \beginlines
- |All 32 attributes already declared (compile as Advanced game to get an extra 16)|
- |All 48 attributes already declared|
- |All 30 properties already declared (compile as Advanced game to get an extra 32)|
- |All 62 properties already declared|
- |Expected an attribute name after 'alias'|
- |Expected a property name after 'alias'|
- |'alias' incompatible with 'long'|
- |'alias' incompatible with 'additive'|
- |'alias' refers to undefined attribute <text>|
- |'alias' refers to undefined property <text>|
- |All 235 global variables already declared|
- |Expected 'string', 'data', 'initial', 'initstr' or '=' but found <text>|
- \endlines^^|alias|^^{global variables}
- Use of |alias| is rare (except inside the library files). The last of these
- errors means that a global variable has been wrongly initialised, and a
- common cause of this is typing, say, |global trolls 5;| instead of
- |global trolls = 5;|.
- \beginlines
- |'*' divider expected, but found <text>|
- |No such token as <text>|
- |Expected '=' after 'scope' but found <text>|
- |Expected routine after 'scope=' but found <text>|
- |Expected routine after 'noun=' but found <text>|
- |'=' is only legal here as 'noun=Routine'|
- |'->' clause missing|
- |No such action routine as <text>|
- |Not an action: <text>|
- |Too many lines of grammar for verb: increase #define MAX_LINES_PER_VERB|
- |There is no previous grammar for the verb <text>|
- |Two different verb definitions refer to <text>|
- |Expected 'replace', 'last' or 'first' but found <text>|
- \endlines^^{parser speed}
- These are the ^{grammatical errors}, the last three concerning |extend|ed
- verb definitions.
- Normally one gets 16 grammar lines per verb. It's probably better to write
- grammar more carefully (using routines to parse adjectives more carefully,
- for instance) than to exceed this, as the game parser will otherwise slow
- down. The object/class definition errors are largely self-explanatory:
- \beginlines
- |Object/class definition finishes with ','|
- |Two commas ',' in a row in object/class definition|
- |No such attribute as <text>|
- |No such class as <text>|
- |Expected 'with', 'has' or 'class' in object/class definition but found <text>|
- |Expected an (internal) name for object but found the string <text>|
- |An object must be defined after the one which contains it: (so far)|
- | there is no such object as <text>|
- |Not an object: <text>|
- |No such property as <text>|
- |Not a property: <text>|
- \endlines^^{object errors}^^{class errors}
- Miscellaneous errors complete the list produced by mostly-uncommon directives:
- \beginlines
- |Expected ';' after 'include <file>' but found <text>|
- |A 'switches' directive must come before constant definitions|
- |Expected 'score' or 'time' after 'statusline' but found <text>|
- |The serial number must be a 6-digit date in double-quotes|
- |The version number must be 3 to 6: 3 for Standard games and 5 for Advanced|
- |Expected 'on' or 'off' after 'font' but found <text>|
- |Defaulted constants can't be strings|
- |Must specify 0 to 3 variables in 'stub' routine|
- |Expected 'full' or nothing after 'etrace' but found <text>|
- |Too many abbreviations declared|
- |All abbreviations must be declared together|
- |It's not worth abbreviating <text>|
- |Expected a 'string' value|
- |No such directive as <text>|
- \endlines
- Conditional compilation happens as a result of one of |#IFDEF|, |#IFV3| or
- |#IFV5|. (The former tests whether a constant is defined; the latter test
- for version-3 (Standard) games or version-5 (Advanced) games.) An |#IFNOT|
- section is optional but the closing |#ENDIF| is compulsory. In these error
- messages |#IF...| means any of the three opening clauses.
- \beginlines
- |'#IF...' nested too deeply: increase #define MAX_IFDEF_DEPTH|
- |'#ENDIF' without matching '#IF...'|
- |'#IFNOT' without matching '#IF...'|
- |Two '#IFNOT's in the same '#IF...'|
- |End of file reached inside '#IF...'|
- \endlines^^{conditional compilation}
- Routines begin with a |[| and some local variables and end with |]|:
- \beginlines
- |Routine has more than 15 local variables|
- |The earliest-defined routine is not allowed to have local variables|
- |Expected local variable but found ',' or ':' (probably the ';' after the|
- | '[ ...' line was forgotten)|
- |Misplaced ']'|
- |Comma ',' after ']' can only be used inside object/class definitions|
- |Expected ',' or ';' after ']' but found <text>|
- |Expected ';' after ']' but found <text>|
- \endlines^^{routine errors}
- The error messages for expressions are fairly simple. Note, however, that
- one is not allowed to type, say, |lamp.number++;| but must instead write
- |lamp.number = lamp.number + 1;| (the ^|++| and ^|--| operators
- can only be applied to variables, not properties).
- \beginlines
- |Expected condition but found expression|
- |Unexpected condition|
- |Expected an assignment but found <text>|
- |Expected an assignment but found an expression|
- |Attempt to use void as a value|
- |Attempt to use an assignment as a value|
- |Attempt to use a condition as a value|
- |Operator has too few arguments|
- |Operator has too many arguments|
- |'++' and '--' can only apply directly to variables|
- |At most three values can be separated by 'or'|
- |'or' can only be used with the conditions '==' and '~='|
- |Too many brackets '(' in expression|
- |Brackets '(' too deeply nested|
- |Missing bracket ')' in function call|
- |Spurious comma ','|
- |Misplaced comma ','|
- |Wrong number of arguments to system function|
- |'children' takes a single argument|
- |'youngest' takes a single argument|
- |'elder' takes a single argument|
- |'indirect' takes at least one argument|
- |Type mismatch in argument <text>|
- |A function may be called with at most 3 arguments|
- |Malformed statement 'Function(...);'|
- |Spurious terms after function call|
- |Spurious terms after assignment|
- |Spurious terms after expression|
- \endlines^^{expression errors}
- Next, constants. Note that dictionary words cannot start with a
- non-alphabetic character, which means that Infocom-style ``debugging verbs''
- which traditionally begin with a |#| are not allowed.
- \beginlines
- |No such variable as <text>|
- |No such constant as <text>|
- |Not a constant: <text>|
- |Reserved word as constant: <text>|
- |No such routine as <text>|
- |Dictionary words must begin with a letter of the alphabet|
- |Dictionary word not found for constant <text>|
- \endlines^^{dictionary errors}
- Loop constructs: note that `old-style' |for| loops are a rather obselete
- form (e.g. |for i 1 to 10|), and the more flexible style |for (i=1:i<=10:i++)|
- is now preferred.
- \beginlines
- |'if' statement with more than one 'else'|
- |'else' attached to a loop block|
- |'for' loops too deeply nested|
- |':' expected in 'for' loop|
- |Second ':' expected in 'for' loop|
- |Concluding ')' expected in 'for' loop|
- |'to' missing in old-style 'for' loop|
- |'to' expected in old-style 'for' loop|
- |Final value missing in old-style 'for' loop|
- |'{' required after an old-style 'for' loop|
- |Old-style 'for' loops must have simple final values|
- |Open bracket '(' expected in 'objectloop'|
- |'objectloop' must be 'from', 'near' or 'in' something|
- |Close bracket ')' expected in 'objectloop'|
- |Braces '{' are compulsory unless the condition is bracketed|
- |Unmatched '}' found|
- |Brace mismatch in previous routine|
- \endlines^^{brace mismatch}
- Inform checks the level of braces when a routine closes so that it can
- recover as quickly as possible from a mismatch; this last error means at
- least one brace is still open when the routine finishes.
- \beginlines
- |The object to 'give' to must be a variable or constant|
- |Expected some attributes to 'give'|
- |Expected 'to <object>' in 'move'|
- |Expected 'to' in 'move' but found <text>|
- |Expected ',' in 'print' list but found <text>|
- |Expected 'style' to be 'roman', 'bold', 'underline' or 'reverse' but found <text>|
- |Expected a parse buffer for 'read'|
- |Expected some properties to 'write'|
- |The object to 'write' must be a variable or constant|
- |Expected property value to 'write'|
- |Expected 'byte' or 'word' in 'put'|
- |Expected 'byte' or 'word' in 'put' but found <text>|
- \endlines
- These are miscellaneous commands and |put| and |write| are quite obselete.
- Only action commands like |<Take brass_lantern>| remain:
- \beginlines
- |Action name too long or a string: perhaps a statement accidentally ended|
- | with a comma?|
- |Action commands must take the form '< Action ... >'|
- |The longest action command allowed is '<Action noun second>'|
- |Angle brackets do not match|
- |Action given in constant does not exist|
- |Action name over 60 characters long: <text>|
- |Expected ':' (after action) but found <text>|
- \endlines
- The first of these may be caused by something like:
- \beginstt
- "You load the crossbow bolt.",
- Drop: "The bolt falls to the floor with a thump.";
- \endtt
- where a comma has been typed instead of a semicolon after the first string,
- so that Inform thinks you are giving a rule for two actions, one being |Drop|
- and the other apparently called |"You load the crossbow bolt."|.
-
- \subsection{Internal and assembler errors}\medskip\noindent
- By now we have descended to the ninth circle of Inform: the assembler.
- These errors are fairly unmysterious (if only because they seldom happen),
- but sometimes one is told something odd like
- \beginstt
- No such label as _f456
- \endtt
- which is caused by Inform failing to recover properly from a previous
- brace mismatch error. Just ignore this and fix the earlier error (which will
- also have been reported). The ``no such variable'' error is occasionally
- seen when an unknown variable is first referred to by being written to.
- \beginlines
- |No such assembly opcode as <text>|
- |Too many arguments|
- |Can't store to that (no such variable)|
- |Branch too far forward: use '?'|
- |No such return condition for branch|
- |Can't branch to a routine, only to a label|
- |No such label as <text>|
- |Not a label: <text>|
- \endlines^^{assembler errors}
- To conclude with, there are a few internal error messages:
- \beginlines
- |A label has moved between passes because of a low-level error just before|
- | (perhaps an improper use of a routine address as a constant)|
- |Object has altered in memory usage between passes: perhaps an attempt to|
- | use a routine name as value of a small property|
- |Duplicated system symbol name <text>|
- |Internal error - unknown directive code|
- |Internal error - unknown compiler code|
- \endlines^^{internal errors}
- The last three should not happen. The first two occasionally do, and cause
- some confusion. Inform performs two tests regularly as a safeguard to make
- sure that code has not come out substantially different in its two passes.
- The first failure occurs in code, the second for object/class definitions.
- Whatever caused this should be something unusual, low-level and just
- before the error occurred: if you get these errors with innocent high-level
- code, then probably Inform should provide a suitable error message, so
- please email the author with a sample of offending code.
-
- \subsection{Warnings}\medskip\noindent
- Inform can produce any number of warnings without shutting down. Note
- that Inform tries to give only warnings when it hits Advanced-game features
- in what is to be a Standard game, for the sake of portability. Nevertheless
- it is probably better to use |#IFV3| and |#IFV5| clauses around any pieces
- of code which are to be different in these two versions (if, indeed, you
- want two different versions).
- \beginlines
- |Local variable unused: <text>|
- |Since it is defined before inclusion of the library, game-play will begin|
- | not at 'Main' but at the routine <text>|
- |Ignoring Advanced-game status routine|
- |Ignoring this Advanced-game command|
- |Missing ','? Property data seems to contain the property name <text>|
- |Standard-game limit of 8 bytes per property exceeded (use Advanced to get|
- | 64), so truncating property <text>|
- |Ignoring Advanced-game opcode <text>|
- |Ignoring Standard-game opcode <text>|
- \endlines^^{warnings}^^{Advanced games}^^{Standard games}
- \tenpoint
-
- \section{A5}{Compiler options and memory settings}
-
- \widepoem
- I was promised a horse, but what I got instead
- was a tail, with a horse hung from it almost dead.
- \quoteby{Palladas of Alexandria, translated by Tony Harrison}
-
- \ninepoint
- \noindent {\it
- The reader is warned that some details in this section are slightly
- different on different machines.}
- \medskip
- \noindent
- On most machines, Inform is run from the command line, by a command like
- \beginstt
- inform -xv5 balances
- \endtt
- and simply typing |inform| will produce a good deal of help information
- about the command line options available. The ^{command line syntax} is
- \begindisplay
- |inform| \<switches> \<settings> \<source file> \<output file>
- \enddisplay
- where only the \<source file> is mandatory. (By default, the full names to
- give the source and output files are derived in a way suitable for the machine
- Inform is running on: on a PC, for instance, |advent| may be understood as
- asking to compile |advent.inf| to |advent.z5|.)
- \medskip
- The switches are given in one or more groups, preceded by a minus sign |-|
- in the usual Unix command-line style. The current list of legal switches is:
- \beginlines
- | 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|
- | k output Infix debugging information to "Game_Debug"|
- | 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 compile to version-3 (Standard) story file|
- | v4 compile to version-4 (Plus) story file|
- | v5 compile to version-5 (Advanced) story file|
- | v6 compile to 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|
- | T enable throwback of errors in the DDE|
- \endlines^^{compiler switches}^^{switches (on command line)}
- (Thus, as long as your name doesn't have a `q' or `y' in it, you can
- amuse yourself typing your name in as a switch and see what it does.)
- Note that these switches can also be selected by putting a |switches|
- directive into the source code before anything else, such as
- \beginstt
- Switches xdv5s;
- \endtt
- The most useful switches are |v3| and |v5|, which choose between Standard
- and ^{Advanced games}^^{Standard games}. For example, the above line is
- from the example game ^{`Advent'}, which is consequently compiled to an
- Advanced game. (If no choice is stated, a Standard game results.) The
- options |v4| and |v6| are provided for completeness but their use is not
- recommended.
-
- Many of the remaining switches make Inform produce extra output, but do
- not affect its compilation:
- \medskip
-
- \noindent |a b l m n t|\quad are tracing options to help with maintaining
- Inform, or for debugging assembly language programs
-
- \noindent |o p s z|\quad will print out information about the final game file,
- the |s| (^{statistics}) option being particularly useful to keep track of how
- large the game is growing
-
- \noindent |c w T|\quad in |c| mode, Inform does not quote whole source lines
- together with error messages; in |w| mode it suppresses warnings; in |T|
- mode, which is only present on the Acorn Archimedes, error throwback
- will occur in the `Desktop Development Environment'
-
- \noindent |f|\quad indicates roughly how many bytes the abbreviations saved
-
- \noindent |h|\quad prints out the help information (and is equivalent to
- just typing |inform|)
-
- \noindent |j x|\quad make Inform print out steady text to prove that it's
- still awake: on very slow machines this may be a convenience
-
- \noindent |k|\quad writes a ^{``debugging information'' file} for the use of
- the ^{Infix} debugger (similarly, the filename is something suitable for
- the machine)
-
- \noindent |r|\quad is intended to help with proof-reading the text of a game,
- and transcribes all of the text in double-quotes to the given file (whose
- name is something suitable for the machine)
-
- \noindent |u|\quad will try to work out a good set of abbreviations to
- declare for your game, but {\it extremely slowly} (a matter of hours) and
- {\it consuming very much memory} (perhaps a megabyte)
- \medskip
- This leaves three more switches which actually alter the game file which
- Inform would compile:
- \medskip
- \noindent |d|\quad converts text like
- \beginstt
- "...with a mango. You applaud..."
- \endtt
- into the same with only a single space after the full stop, which will
- prevent an interpreter from displaying a spurious space at the beginning
- of a line when a line break happens to occur exactly after the full stop;
- this is to help typists who habitually double-space
- ^^{double spacing}
-
- \noindent |e|\quad only in ^{`economy' mode} does Inform actually process
- abbreviations, because this is seldom needed and slows the compiler by
- 10\% or so; the game file should not play any differently if compiled
- this way, but will probably be shorter, if your choice of ^{abbreviations}
- was sensible
-
- \noindent |g|\quad will make Inform automatically compile trace-printing
- code on every function call; in play this will produce reams of text (several
- pages between each chance to type commands) but is sometimes useful. Note
- that in Inform 5.3 or later, this can be set on an individual command by
- writing |*| as its first local variable, without use of the |g| switch
-
- \noindent |i|\quad overrides any switches set by |switches| directives in
- the source code; so that the game can be compiled with different options
- without having to alter that source code.
- \bigskip
-
- Inform's ^{memory management} is about as flexible as it can be given that it
- has to run in some quite hostile environments. In particular, it is unable
- to increase the size of any stretch of memory once allocated, so if it runs
- out of anything it has to give up. If it does run out, it will produce an
- error message saying what it has run out of and how to provide more.
-
- 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, a draft 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
- \beginstt
- inform $list
- \endtt^^{memory settings}^^{small memory}^^{large memory}
- will list the various settings which can be changed, and their current
- values. Thus one can compare small and large with:
- \beginstt
- inform $small $list
- inform $large $list
- \endtt
- If Inform runs out of allocation for something, it will generally print an
- error message like:
- \beginstt
- "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.
- \endtt
- and indeed
- \beginstt
- inform $MAX_OBJECTS=250 game
- \endtt
- (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
- \beginstt
- inform $small $MAX_ACTIONS=200 ...
- \endtt
- will work, but
- \beginstt
- inform $MAX_ACTIONS=200 $small ...
- \endtt
- will not because the |$small| changes |MAX_ACTIONS| again.
-
- Changing some settings has hardly any effect on memory usage, whereas others
- are expensive to increase. To find out about, say, |MAX_VERBS|, run
- \beginstt
- inform $?MAX_VERBS
- \endtt
- (note the question mark) which will print some very brief comments.
- \ninepoint
-
- \immediate\closeout\ans
- \vfill\eject
- \section{A6}{Answers to all the exercises}
- \outer\def\ansno #1:{\medbreak
- \noindent\llap{$\bullet$\rm\kern.15em}%
- {\ninebf \bf #1}\quad}
-
- \ansno1:
- {\beginlines
- |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;|
- \endlines
- 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.}
-
- \ansno2:
- {You may be surprised how many actions take place: often more than one
- per turn.}
-
- \ansno3:
- {|if (obj.&door_to == 0) { ... }|}
-
- \ansno4:
- {Define four objects along the lines of:
- \beginlines
- |Object white_obj "white wall" compass|
- | with name "white" "sac" "wall", article "the", door_dir n_to|
- | has direction scenery;|
- \endlines^^{world colours}^^{Mayan directions}^^{direction objects}
- and add the following line to |Initialise|:
- \beginlines
- |remove n_obj; remove e_obj; remove w_obj; remove s_obj;|
- \endlines
- (We could even |alias| a new property |white_to| to be |n_to|, and then
- enter map directions in the source code using Mayan property names.)
- As a fine point of style, turquoise ({\it yax}) is the world colour for
- `here', so add a grammar line to make this cause a ``look'':
- \beginlines
- |Verb "turquoise" "yax" * -> Look;|
- \endlines}
-
- \ansno5:
- {^^{reflecting the map}\beginlines
- |[ SwapDirs o1 o2 x;|
- | x=o1.door_dir; o1.door_dir=o2.door_dir; o2.door_dir=x; ];|
- |[ ReflectWorld;|
- | SwapDirs(e_obj,w_obj); SwapDirs(ne_obj,nw_obj); SwapDirs(se_obj,sw_obj);|
- |];|
- \endlines}
-
- \ansno6:
- {This is a prime candidate for using ^{variable strings}
- ^|@nn|, a topic properly covered in the {\sl Inform Technical Manual},
- but briefly: at the head of the source, define
- \beginlines
- |Lowstring east_str "east"; Lowstring west_str "west";|
- \endlines^^|Lowstring|^^|String|
- and then add two more routines to the game,
- \beginlines
- |[ NormalWorld; String 0 #east_str; String 1 #west_str; ];|
- |[ ReversedWorld; String 0 #west_str; String 1 #east_str; ];|
- \endlines
- where |NormalWorld| is called in |Initialise| or to go back to
- normal, and |ReversedWorld| when the reflection happens. Write
- |@00| in place of |east| in any double-quoted printable string,
- and similarly |@01| for |west|. It will be printed as whichever
- is currently set. (Inform provides up to 32 such variable strings.)}
-
- \ansno7:
- {Declare a fake action called, say, |OpenUp|. Then:
- \beginlines
- |Object medicine "guaranteed child-proof medicine bottle" cupboard|
- | with name "medicine" "bottle",|
- | description "~Antidote only: no preventative effect.~",|
- | before|
- | [; Open, Unlock: "It's adult-proof too.";|
- | Openup: give self open ~locked; "The bottle cracks open!";|
- | ],|
- | has container openable locked;|
- \endlines
- Any other code in the game can execute |<OpenUp medicine>| to crack open
- the bottle.}
-
- \ansno8:
- {\beginlines
- |Nearby glass_box "glass box with a lid"|
- | with name "glass" "box" "with" "lid"|
- | has container transparent openable open;|
- |Nearby steel_box "steel box with a lid"|
- | with name "steel" "box" "with" "lid"|
- | has container openable open;|
- \endlines}
-
- \ansno9:
- {^^{toothed bag}
- \beginlines
- |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;|
- \endlines}
-
- \ansno10:
- {\beginlines^^{television set}
- |Object television "portable television set" lounge|
- | with name "tv" "television" "set" "portable",|
- | before|
- | [; SwitchOn: <<SwitchOn power_button>>;|
- | SwitchOff: <<SwitchOff power_button>>;|
- | Examine: <<Examine screen>>;|
- | ],|
- | has transparent;|
- |Nearby power_button "power button"|
- | with name "power" "button" "switch",|
- | after|
- | [; SwitchOn, SwitchOff: <<Examine screen>>;|
- | ],|
- | has switchable;|
- |Nearby screen "television screen"|
- | with name "screen",|
- | before|
- | [; Examine: if (power_button hasnt on) "The screen is black.";|
- | "The screen writhes with a strange Japanese cartoon.";|
- | ];|
- \endlines}
-
- \ansno11:
- {Change the car's |before| to\beginlines
- | before|
- | [; Go: if (noun==d_obj or u_obj)|
- | { print "(The car will never get over those stairs.)^";|
- | rfalse;|
- | }|
- | if (car has on) "Brmm! Brmm!";|
- | print "(The ignition is off at the moment.)^";|
- | ],|
- \endlines^^{little red car}}
-
- \ansno12:
- {The common man's {\it wayhel} was a lowly mouse. Since we think
- much more highly of the player:
- \beginlines
- |Object hog "Warthog" Caldera|
- | with name "wart" "hog" "warthog", description "Muddy and grunting.",|
- | number 0,|
- | initial "A warthog snuffles and grunts about in the ash.",|
- | before|
- | [; if (player==self && action~=##Go or ##Look or ##Examine)|
- | "Warthogs can't do anything as tricky as that!";|
- | ],|
- | has animate proper;|
- \endlines^^{warthog}^^{nagual}
- and we just |ChangePlayer(warthog);|. Note that this |before| rule is
- carefully written only to affect actions of the player-as-warthog.
- If the player-as-human should find and try to ``take warthog'', this
- |before| routine won't interfere.}
-
- \ansno13:
- {Because |CDefArt(obj)| is a function call which, as it happens,
- returns the value true, or 1 (not that this signifies anything), and
- |print| thinks it is printing out a number.}
-
- \ansno14:
- {This is a crude implementation, for brevity (the real Zork I
- thief has an enormous stock of attached messages).^^{thief in `Zork I'}
- \beginlines
- |Object thief "thief" Danger_Zone|
- | with name "thief",|
- | each_turn "^The thief growls menacingly.",|
- | daemon|
- | [ i p j n k;|
- | if (random(3)~=1) rfalse;|
- | p=parent(thief);|
- | objectloop (i in compass)|
- | { j=p.(i.door_dir);|
- | if (j>player && j<=top_object && j hasnt door) n++;|
- | }|
- | if (n==0) rfalse;|
- | k=random(n); n=0;|
- | objectloop (i in compass)|
- | { j=p.(i.door_dir);|
- | if (j>player && j<=top_object && j hasnt door) n++;|
- | if (n==k)|
- | { move self to j;|
- | if (p==location) "^The thief stalks away!";|
- | if (j==location) "^The thief stalks in!";|
- | rfalse;|
- | }|
- | }|
- | ];|
- \endlines
- This thief walks at random and cannot pass through doors, bridges and the like
- (because these may be locked or have rules attached); it's only a first
- approximation, and in a good game one should occasionally see the thief do
- something surprising, such as open a secret door.}
-
- \ansno15:
- {First define a new property for object weight:^^{weights}
- \beginlines
- |Property weight 10;|
- \endlines
- (10 being an average sort of weight). Containers weigh more when
- they hold things, so we will need:
- \beginlines
- |[ WeightOf obj t i;|
- | t = obj.weight;|
- | objectloop (i in obj) t=t+WeightOf(i);|
- | return t;|
- |];|
- \endlines
- Now for the daemon which monitors the player's fatigue:^^{fatigue daemon}
- \beginlines
- |Object weigher "weigher"|
- | with number 500,|
- | time_left 5,|
- | daemon|
- | [ w s b bw;|
- | w=WeightOf(player)-100-player.weight;|
- | s=self.number; s=s-w; if (s<0) s=0; if (s>500) s=500;|
- | self.number = s;|
- | if (s==0)|
- | { bw=-1;|
- | objectloop(b in player)|
- | if (WeightOf(b)>bw) { bw=WeightOf(b); w=b; }|
- | print "^Exhausted with carrying so much, you decide \|
- | to discard "; DefArt(w); print ": "; <<Drop w>>;|
- | }|
- | w=s/100; if (w==self.time_left) rfalse;|
- | if (w==3) print "^You are feeling a little tired.^";|
- | if (w==2) print "^You possessions are weighing you down.^";|
- | if (w==1) print "^Carrying so much weight is wearing you out.^";|
- | self.time_left = w;|
- | ];|
- \endlines
- Notice that items are actually dropped with |Drop| actions: one of them
- might be, say, a wild boar, which would bolt away into the forest when
- released. The daemon tries to drop the heaviest item. (Obviously a little
- improvement would be needed if the game contained, say, an un-droppable
- but very heavy ball and chain.) Now the daemon is going to run every turn
- forever, but needs to be started: so put |StartDaemon(weigher);| into the
- game's |Initialise| routine.}
- \medskip
-
- \ansno16:
- {Either set a daemon to watch for |the_time| suddenly dropping, or
- put such a watch in the game's |TimePasses| routine.}
-
- \ansno17:
- {Because you don't know what order daemons will run in. A
- `fatigue' daemon which makes the player drop something might come
- after the `mid-air' daemon has run for this turn. Whereas |each_turn|
- happens after daemons and timers have run their course, and can fairly
- assume no further movements will take place this
- turn.^^{daemon running order}}
-
- \ansno18:
- {It would have to provide its own code to keep track of time,
- and it can do this by providing a |TimePasses()| routine. Providing
- ``time'' or even ``date'' verbs to tell the player would also be a
- good idea.}
-
- \ansno19:
- {^^{footnotes}
- \beginlines
- |Constant MAX_FOOTNOTES 10;|
- |global footnotes_seen data MAX_FOOTNOTES;|
- |global footnote_count;|
- |[ Note n i pn;|
- | for (i=0:i<footnote_count:i++)|
- | if (n==footnotes_seen->i) pn=i;|
- | if (footnote_count==MAX_FOOTNOTES) "** MAX_FOOTNOTES exceeded! **";|
- | if (pn==0) { pn=footnote_count++; footnotes_seen->pn=n; }|
- | print " [",pn+1,"]";|
- |];|
- |[ FootnoteSub n;|
- | if (noun>footnote_count)|
- | { print "No footnote [",noun,"] has been mentioned.^"; rtrue; }|
- | if (noun==0) "Footnotes count upward from 1.";|
- | n=footnotes_seen->(noun-1);|
- | print "[",noun,"] ";|
- | if (n==0) "This is a footnote.";|
- | if (n==1) "D.G.REG.F.D is inscribed around English coins.";|
- | if (n==2) "~Jackdaws love my big sphinx of quartz~, for example.";|
- |];|
- ||
- |Verb "footnote" "note" * number -> Footnote;|
- \endlines
- And then call, for instance, |Note(1);| to refer in the game to
- the ``English coins'' footnote.}
-
- \ansno20:
- {Because the parser might go on to reject the line it's working on:
- for instance, if the player typed ``inventory splurge'' then the message
- ``Shazam!'' followed by a parser complaint will be somewhat unedifying.}
-
- \ansno21:
- {Here goes: we could implement the buttons 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.^^{spaceship control panel}
- \beginlines
- |[ 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;|
- \endlines}
-
- \ansno22:
- {^^{parsing quoted strings}
- The ^{blackboard} code in ^{`Toyshop'} contains just such a routine:
- \beginlines
- |Global from_char; Global to_char;|
- |[ QuotedText i j f;|
- | i = parse->((++wn)*4-3);|
- | if (buffer->i=='"')|
- | { for (j=i+1:j<=(buffer->1)+1:j++)|
- | if (buffer->j=='"') f=j;|
- | if (f==0) return -1;|
- | from_char = i+1; to_char=f-1;|
- | if (from_char>to_char) return -1;|
- | while (f> (parse->(wn*4-3))) wn++; wn++;|
- | return 1;|
- | }|
- | return -1;|
- |];|
- \endlines^^{quoted text}
- Note that in the case of success, the word marker |wn| is moved beyond the
- last word accepted (since the Z-machine automatically tokenises
- a double-quote as a single word). The routine then tells the parser it
- has parsed a number, which is a white lie. What it actually does is to
- record the byte positions where the quoted text starts and finishes in
- the raw text |buffer| so that an action routine can easily extract the
- text and use it later. (Note that |""| with no text inside is not
- matched by this routine but only because the last |if| statement throws
- out that one case.)^^{double-quote}^^{tokenisation}}
-
- \ansno23:
- {^^{named rooms}
- Define two properties:
- \beginlines
- |Property place_name;|
- |Property long to_places;|
- \endlines
- The scheme will work like this: a named room should have the |place_name|
- property set to a single dictionary word; say, the Bedquilt cave could
- be called |'bedquilt'|. Then in any room, a list of those other rooms
- which can be moved to in this way should appear in the |to_places| entry.
- For instance,
- \beginlines
- |to_places Bedquilt Slab_Room Twopit_Room;|
- \endlines
- Now the code: see if a not-understood verb is a place name of a nearby room,
- and if so store that room's object number in |goto_room|, converting
- the verb to a dummy.
- \beginlines
- |Global goto_room = 0;|
- |[ UnknownVerb word p i;|
- | p = location.&to_places; if (p==0) rfalse;|
- | for (i=0:(2*i)<location.#to_places:i++)|
- | if (word==(p-->i).place_name)|
- | { goto_room = p-->i; return 'go#room';|
- | }|
- | rfalse;|
- |];|
- |[ PrintVerb word;|
- | if (word=='go#room')|
- | { print "go to "; PrintShortName(goto_room); rtrue; }|
- | rfalse;|
- |];|
- \endlines
- (The supplied |PrintVerb| is icing on the cake: so the parser can
- say something like ``I only understood you as far as wanting to go to
- Bedquilt.'' if need be.) It remains only to put in code
- and grammar for the ^{dummy verb}:
- \beginlines
- |[ GoRoomSub;|
- | if (goto_room hasnt visited) "But you have never been there.";|
- | PlayerTo(goto_room);|
- |];|
- |Verb "go#room" * -> GoRoom;|
- \endlines
- Note that if you don't know the way, you can't go there! A purist might
- prefer instead to not recognise the name of an unvisited room, back at
- the |UnknownVerb| stage, to avoid the player being able to deduce names
- of nearby rooms from this `error message'.}
-
- \ansno24:
- {A slight refinement of such a ^{``purloin'' verb} is already defined
- in the library (if the constant |DEBUG| is defined), so there's no need.
- Here's how it could be done:
- \beginlines
- |[ Anything i;|
- | if (scope_stage==1) rfalse;|
- | if (scope_stage==2)|
- | { for (i=1:i<=top_object:i++) PlaceInScope(i); rtrue; }|
- | "No such in game.";|
- |];|
- \endlines^^{token for `any object'}
- (This disallows multiple matches for efficiency reasons - the parser has
- enough work to do with such a huge scope definition as it is.) Now
- the token |scope=Anything| will match anything at all, even things like
- the abstract concept of `east'.}
-
- \ansno25:
- {For good measure, we'll combine this with the previous rule
- about |moved| objects being in scope in the dark. The following
- can be inserted into the `Shell' game:^^{light switch}
- \beginlines
- |Object coal "dull coal" Blank_Room|
- | with name "dull" "coal";|
- ||
- |Object Dark_Room "Dark Room"|
- | with description "An empty room with a west exit.",|
- | each_turn|
- | [; if (self has general) self.each_turn=0;|
- | else "^You hear the breathing of a dwarf.";|
- | ],|
- | w_to Blank_Room;|
- ||
- |Nearby light_switch "light switch"|
- | with name "light" "switch",|
- | initial "On one wall is the light switch.",|
- | after|
- | [; SwitchOn: give Dark_Room light;|
- | SwitchOff: give Dark_Room ~light;|
- | ],|
- | has switchable static;|
- ||
- |Nearby diamond "shiny diamond"|
- | with name "shiny" "diamond"|
- | has scored;|
- ||
- |Nearby dwarf "dwarf"|
- | with name "voice" "dwarf",|
- | life|
- | [; Order: if (action==##SwitchOn && noun==light_switch)|
- | { give Dark_Room light general;|
- | give light_switch on; "~Right you are, squire.~";|
- | }|
- | ],|
- | has animate; |
- ||
- |[ InScope person i;|
- | if (parent(person)==Dark_Room)|
- | { if (person==dwarf || Dark_Room has general)|
- | PlaceInScope(light_switch);|
- | }|
- | if (person==player && location==thedark)|
- | objectloop (i near player)|
- | if (i has moved || i==dwarf)|
- | PlaceInScope(i);|
- | rfalse;|
- |];|
- \endlines
- Note that the routine puts the light switch in scope for the dwarf -
- if it didn't, the dwarf would not be able to understand
- ``dwarf, turn light on", and that was the whole point.}
-
- \ansno26:
- {Just test if |HasLightSource(gift)==1|.}
-
- \ansno27:
- {\beginlines
- |[ DoubleInvSub i count1 count2;|
- | print "You are carrying ";|
- | objectloop (i in player)|
- | { if (i hasnt worn) { give i workflag; count1++; }|
- | else { give i ~workflag; count2++; }|
- | }|
- | if (count1==0) print "nothing.";|
- | else|
- | WriteListFrom(child(player),|
- | FULLINV_BIT + ENGLISH_BIT + RECURSE_BIT + WORKFLAG_BIT);|
- ||
- | if (count2==0) ".";|
- | print ". In addition, you are wearing ";|
- | objectloop (i in player)|
- | { if (i hasnt worn) give i ~workflag; else give i workflag;|
- | }|
- | WriteListFrom(child(player),|
- | ENGLISH_BIT + RECURSE_BIT + WORKFLAG_BIT);|
- | ".";|
- |];|
- \endlines^^{double inventory}}
-
- \ansno28:
- {\beginlines
- |Global c_warned = 0;|
- |Class cherub_class|
- | with parse_name|
- | [ i j flag;|
- | for (flag=1:flag==1:flag=0)|
- | { j=NextWord();|
- | if (j=='cherub' or j==self.name) flag=1;|
- | if (j=='cherubs' && c_warned==0)|
- | { c_warned=1;|
- | parser_action=##PluralFound; flag=1;|
- | print "(I'll let this go once, but the plural of cherub is cherubim.)^";|
- | }|
- | if (j=='cherubim')|
- | { parser_action=##PluralFound; flag=1; }|
- | i++;|
- | }|
- | return i-1;|
- | ];|
- \endlines
- Then again, Shakespeare even writes ``cherubins'' in {\sl Twelfth Night},
- so who are we to censure?^^{cherubim}^^{William Shakespeare}}
-
- \ansno29:
- {First put the directive |Replace DrawStatusLine;| before including
- the library. Then add the following routine anywhere after |treasures_found|,
- an `Advent' variable, is defined:
- \beginlines
- |[ DrawStatusLine;|
- | @split_window 1; @set_window 1; @set_cursor 1 1; style reverse;|
- | spaces (0->33)-1;|
- | @set_cursor 1 2; PrintShortName(location);|
- | if (treasures_found > 0)|
- | { @set_cursor 1 50; print "Treasure: ", treasures_found;|
- | }|
- | @set_cursor 1 1; style roman; @set_window 0;|
- |];|
- \endlines}
-
- \ansno30:
- {Note the magic line of assembly code here, which only works for
- Advanced games:
- \beginlines^^{``Invisiclues''}
- |[ GiveHint hint keypress;|
- | print_paddr hint; new_line; new_line;|
- | @read_char 1 0 0 keypress;|
- | if (keypress == 'H' or 'h') rfalse;|
- | rtrue;|
- |];|
- \endlines
- And a typical menu item using it:
- \beginlines
- | if (menu_item==1)|
- | { print "(Press ENTER to return to menu, or H for another hint.)^^";|
- | if (GiveHint("(1/3) What kind of bird is it, exactly?")==1) return 2;|
- | if (GiveHint("(2/3) Magpies are attracted by shiny items.")==1) return 2;|
- | "(3/3) Wave at the magpie with the kitchen foil.";|
- | }|
- \endlines}
-
- \ansno31:
- {|Primes(100)|, where:\beginlines
- |[ 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;|
- | }|
- |];|
- \endlines^^{prime factorisations}
- (which was the first algorithm ever compiled by Inform).}
- \tenpoint
- \vfill\eject
- \section{A7}{Index}\bigskip\ninepoint
- \beginindex
- |*|, 61, 69.
- |++|, 84.
- |--|, 84.
- |-->|, 68.
- |->|, 38, 68.
- |@@|, 69.
-
- abbreviations, 62, 89.
- |absent|, 74.
- ``abstract'' verb, 60.
- `Acheton', 3.
- |Achieved(task)|, 58.
- action groups, 19.
- action numbers, 19.
- actions, 7, 19, 73.
- ``actions'' verb, 8, 60.
- |actor|, 47.
- |additive|, 11, 33.
- addresses, 8.
- Advanced games, 8, 12, 14, 61, 65, 65, 87, 89.
- `Advent', 31, 33, 34, 43, 63, 89, 90.
- |after|, 5, 17, 20, 76.
- |AfterLife|, 31, 78.
- |alias|, 10, 11, 83.
- |AllowPushDir()|, 27.
- almond poisoning, 6.
- |Amusing|, 78.
- |AMUSING PROVIDED|, 58.
- |animate|, 74.
- |Answer|, 28.
- appallingly convenient verb, 40.
- archaeological dig, 36.
- ``Area 400", 54.
- |aread|, 66.
- Aristotle, 9.
- arithmetic operators, 70.
- arrays, 68.
- |article|, 31, 76.
- |Ask|, 28.
- asking questions, 45.
- assembler errors, 87.
- assembly language, 65.
- assignments, 70.
- |Attack|, 27.
- |Attribute|, 10.
- attributes, 5, 10.
- attributes in library, 74.
- audibility, 35.
- |autosearch|, 76.
-
- background daemon, 34.
- backslash, 67, 69.
- bag of six coins, 55.
- `Balances', 42, 56.
- banana, 39.
- batteries, 25.
- Bedquilt Room, 21.
- |beep|, 66.
- |before|, 6, 76.
- binary, 69.
- blackboard, 97.
- blocks of code, 72.
- |Blorple|, 20.
- boldface, 65.
- bolted cupboard, 23.
- |box|, 63.
- brace mismatch, 85.
- braces, 72.
- brain transference machine, 30.
- brass lantern, 25.
- |break|, 73.
- |buffer mode|, 66.
- built-in functions, 71.
- byte address, 8.
-
- C. P. Snow, 48.
- C. S. Lewis, 34, 74.
- Cambridge University, 3.
- |cant go|, 16, 76.
- |capacity|, 22, 30, 77.
- |CDefArt(obj)|, 31.
- ``ceiling'', 74.
- chair, 29.
- |ChangePlayer|, 30.
- changing scope, 47.
- changing the player, 30.
- character graphic, 63.
- cherubim, 57, 100.
- |child|, 9, 60.
- |children|, 60.
- |class|, 14, 14, 33.
- class errors, 83.
- classes, 32.
- clearing the screen, 66.
- closing credits, 58.
- |clothing|, 74.
- clues, 64.
- `Colossal Cave', 43.
- command line syntax, 88.
- comments, 67.
- `companion volumes', 2.
- compiler switches, 88.
- |concealed|, 45, 74.
- conditional compilation, 67, 84.
- conditions, 70.
- Connie Booth, 63.
- constants, 69.
- |container|, 22, 75.
- control constructs, 72.
- copyright, 3.
- crashing the interpreter, 60.
- creature token, 39.
- crowns, 56.
- crystal chandelier, 15.
- `Curses', 12, 90.
- cursor keys, 66.
-
- |daemon|, 34, 77.
- daemon running order, 95.
- daemons, 34.
- darkness, 45.
- |DarkToDark|, 50, 78.
- |data|, 68.
- David M. Baggett, 31, 40.
- David Seal, 3.
- |deadflag|, 6, 31.
- |DeathMessage|, 31, 78.
- |DEBUG|, 8, 59.
- `debugging code', 61.
- ``debugging information'' file, 89.
- debugging verbs, 59.
- |DefArt(obj)|, 31.
- default value of properties, 11.
- definite article, 32.
- definition of darkness, 48.
- dentist's chair, 26.
- depressed philosophers, 29.
- |describe|, 13, 77.
- |description|, 77.
- dictionary errors, 85.
- dictionary resolution, 62.
- dictionary words, 77.
- |direction|, 75.
- direction objects, 17, 74, 78, 91.
- direction properties, 78.
- directions, 16, 45.
- directive, 10.
- directives, 67.
- dirty tricks, 65.
- division by zero, 70.
- |DoMenu|, 64.
- Don Woods, 3.
- Donna Tartt, 18.
- |door|, 23, 75.
- |door dir|, 23, 24, 77.
- |door to|, 23, 77.
- Dorothy Parker, 64.
- double inventory, 52, 100.
- double spacing, 89.
- double-quote, 97.
- dramatic effects, 48.
- drawings, 63.
- `drunk player object', 30.
- dummy verb, 98.
-
- |each turn|, 35, 77.
- earshot, 35.
- `economy' mode, 89.
- |edible|, 75.
- |elder|, 10.
- |eldest|, 10.
- embedded routines, 13, 69.
- `Enchanter', 23.
- |EnglishNumber(x)|, 79.
- |Enter|, 24.
- |enterable|, 26, 75.
- entry points, 78.
- epigrams, 63.
- |erase window|, 66.
- error messages, 81.
- |et flag|, 35.
- exotic forms of death, 31.
- expression errors, 85.
- expressions, 70.
- |Extend|, 42.
-
- |Fake Action|, 21.
- fake actions, 19, 22, 29, 56.
- fatal errors, 81.
- fatigue daemon, 95.
- |female|, 75.
- file format, 67.
- |first|, 42.
- flags, 10.
- flexible verbs, 43.
- `floating object', 74.
- ``floor'', 74.
- fluorescent jellyfish, 50.
- `focus' of game, 30.
- |font|, 63.
- footnotes, 40, 96.
- |for|, 73.
- foreign character sets, 69.
- |found in|, 12, 18, 77.
- Frankenstein, 30.
- ``free'' verb, 40.
- function arguments, 69.
- function keys, 66.
- fuses, 35.
-
- G. K. Chesterton, 31.
- |GamePostRoutine|, 21, 78.
- |GamePreRoutine|, 21, 78.
- |general|, 75.
- George Bernard Shaw, 44.
- |give|, 10, 28.
- glass box, 22.
- |Global|, 68.
- global variables, 83.
- |Go|, 17, 26.
- ``goto'' verb, 60.
- Graham Nelson, 3.
- Grammar, 7.
- |Grammar|, 4.
- grammar lines, 37.
- grammar tokens, 38.
- grammatical errors, 83.
- green cone, 4.
- grues, 45.
-
- hacker and urchin, 29.
- hanging elses, 72.
- hangover, 14.
- |has|, 10, 12.
- `has light', 49.
- hash character, 67.
- |HasLightSource(object)|, 49.
- |Headline|, 80.
- held token, 39.
- `Hello Cruel World', 4.
- hexadecimal, 11.
-
- |if|, 72.
- in scope, 44.
- |InDefArt(obj)|, 31.
- indefinite article, 31.
- |indirect|, 60.
- `indistinguishable', 55.
- Infact, 60.
- Infix, 60, 89.
- Infocom, Inc., 3.
- Inform 5.2, 3.
- InfoTaskForce, 65.
- inheritance, 14, 33.
- |initial|, 5, 68, 77.
- initial possessions, 29.
- |Initialise|, 4, 29, 29, 36, 78, 78.
- |initstr|, 68, 68.
- |InScope|, 78.
- |Insert|, 22.
- internal errors, 87.
- interpreter, 8.
- interpreters, 65.
- |invent|, 52, 77.
- inventories, 52.
- |inventory stage|, 52.
- ``Invisiclues'', 64, 101.
- Ivan O. Ideas, 57.
-
- James Shirley, 18.
- Jean de la Bruy{\accent 18 e}re, 29.
- John Christopher, 15.
- John Cleese, 63.
- John Donne, 15.
- Jonathan Thackray, 3.
- |jump|, 69.
- ``junior astronaut", 79.
-
- keyboard, 66.
- |Kiss|, 27.
-
- labels, 69.
- large memory, 90.
- |last|, 42.
- |LetGo|, 22.
- lexicon, 7.
- library, 7.
- library routines, 79.
- |life|, 27, 77.
- |light|, 10, 75.
- light and dark, 48.
- light switch, 47, 99.
- limitations, 61.
- line of sight, 35.
- listing objects, 50.
- little red car, 26, 94.
- local variables, 68.
- |location|, 30.
- |lockable|, 75.
- |locked|, 22, 75.
- |long|, 11.
- Long Count, 46.
- |LookRoutine|, 78.
- loop over every object, 73.
- Louis MacNeice, 2.
- low mist, 18.
- low numbers in French, 41.
- |Lowstring|, 92.
- Ludwig Wittgenstein, 27, 37.
-
- making actions, 21.
- making attributes, 10.
- making grammar, 21, 37.
- making properties, 11.
- map, 16, 23.
- Marc Blank, 23, 26.
- ``master catburglar", 79.
- matchbook, 52.
- Max Beerbohm, 44.
- |MAX CARRIED|, 57.
- |MAX SCORES|, 58.
- |MAX TIMERS|, 35.
- Mayan directions, 17, 91.
- ``me'', 30.
- medicine bottle, 21.
- memory consumption, 90.
- memory management, 89.
- memory map, 8.
- memory settings, 82, 90.
- memory size, 62.
- menu of text options, 64.
- |meta|, 20, 43.
- Michel de Montaigne, 27.
- mid-air location, 36.
- Moli{\accent 18 e}re, 37.
- |move|, 9.
- |moved|, 47, 75.
- moving the player, 30.
- multiexcept token, 39.
- multiheld token, 39.
- ``myself'', 30.
-
- nagual, 31, 94.
- |name|, 14, 14, 54, 77.
- named rooms, 44, 98.
- narrow inventory, 51.
- |Nearby|, 13.
- NetHack, 65.
- |NewRoom|, 78.
- |NextWord|, 41.
- |@nn|, 92.
- normal rules, 19, 74.
- |nothing|, 10, 60.
- |notify mode|, 59.
- ``notify'' verb, 59.
- noun token, 39.
- |number|, 77.
- |NUMBER TASKS|, 58.
- number token, 39.
- number-parsing, 41.
- numbers, 8.
-
- |Object|, 12.
- object definitions, 12.
- object errors, 83.
- |OBJECT SCORE|, 58.
- Object syntax, 14.
- |objectloop|, 73.
- objects, 9.
- objects in library, 74.
- `offers light', 49.
- |OffersLight(object)|, 49.
- ogre with limited patience, 35.
- Oliver Goldsmith, 61.
- |on|, 25, 75.
- |open|, 22, 75.
- |openable|, 22, 76.
- |or|, 71.
- |Order|, 28.
- ``out'' verb, 26.
- output streams, 66.
- oyster, 21.
-
- P. David Lebling, 22, 23, 26.
- packed address, 8.
- |parent|, 9, 60.
- |parse name|, 54, 56, 77.
- |parsed number|, 41.
- |ParseNumber|, 41, 78.
- parser, 37.
- |Parser|, 4.
- |parser one, parser two, parser action|, 56.
- parser questions, 43.
- parser speed, 83.
- parser tracing and levels, 61.
- |ParserError|, 48, 78.
- parsing quoted strings, 44, 97.
- passing messages, 21.
- Pepper Room, 18.
- perfectly sensible, 11.
- Peter and Jane, 69.
- pinfocom, 65.
- |PlaceInScope|, 46.
- plagiarism, 57.
- plaster of paris, 27.
- player's origin, 29.
- |PlayerTo|, 30, 60.
- |plural|, 55, 77.
- plural objects, 55.
- precedence, 33.
- prime factorisations, 73, 101.
- |print|, 17.
- |print addr|, 60.
- |print object|, 31, 60.
- |print paddr|, 60.
- printing commands, 71.
- |PrintRank|, 58, 79.
- |PrintShortName(obj)|, 31.
- |PrintTaskName|, 79.
- |PrintVerb|, 43, 79.
- |proper|, 32, 76.
- proper noun, 32.
- properties, 5, 11.
- properties in library, 76.
- |Property|, 11.
- proportional font, 63.
- puff of garlic, 71.
- ``purloin'' verb, 47, 60, 98.
- |PushDir|, 27.
-
- questions, 45.
- questions (yes or no), 59.
- quotations beautiful, 64.
- quoted text, 97.
- ``quotes off'' verb, 64.
-
- radio, 35.
- rainbows, 16.
- |random|, 60.
- |read char|, 66.
- real time, 66.
- |Receive|, 22.
- reflecting the map, 17, 92.
- release number, 67.
- |Remove|, 22.
- |replace|, 42, 59.
- replacing grammar, 42.
- resurrection, 31.
- returning from routines, 72.
- reusing attributes, 10.
- reverse video, 65.
- roman text, 65.
- |ROOM SCORE|, 58.
- routine errors, 84.
- routine tracing, 61.
- routines, 69.
- ``routines'' verb, 60.
- rucksack, 39.
- run-time crashes, 60.
- run-time format, 61.
- running out of memory, 81.
- rusty door, 23.
-
- S\o ren Kierkegaard, 29.
- |SACK OBJECT|, 57.
- |scenery|, 16, 76.
- scope, 44.
- |scope stage|, 46.
- score notification, 59.
- ``score'' verb, 43.
- |scored|, 76.
- scoring systems, 58.
- screen tricks, 65.
- |Search|, 20.
- searchlight, 25.
- `see-through', 44.
- |self|, 19.
- |selfobj|, 73, 74.
- serial number, 67.
- |set cursor|, 66.
- |set window|, 66.
- |SetTime|, 36.
- ``shazam'' verb, 43.
- `Shell', 4.
- |short name|, 53, 77.
- |Show|, 28.
- |sibling|, 9.
- silver bars, 33.
- Sloping Corridor, 16.
- small array, 12.
- small memory, 90.
- ``snavig'' spell, 30.
- sound effect, 66.
- source-level debugger, 60.
- |sp|, 68.
- Space Invaders, 65.
- spaceship control panel, 43, 96.
- special effects, 63.
- |special number|, 28.
- special objects, 74.
- special token, 39.
- |special word|, 28.
- `Spellbreaker cubes', 56.
- `Spellbreaker', 20, 30.
- |split window|, 65.
- Square Room, 15.
- stack pointer, 68.
- Standard games, 8, 10, 12, 14, 61, 65, 87, 89.
- |StartDaemon|, 34.
- |StartTimer|, 35.
- |static|, 24, 76.
- statistics, 89.
- status line, 60, 63.
- |Statusline|, 36.
- steel box, 22.
- steel grate, 24.
- |StopDaemon|, 34.
- |StopTimer|, 35.
- |Story|, 80.
- story files, 2.
- stream, 35.
- |string|, 68, 92.
- |style|, 65.
- style of list, 50.
- sullen snake, 28.
- |supporter|, 22, 26, 76.
- |sw var|, 13.
- |switchable|, 25, 76.
- switches (on command line), 88.
- sword, 35.
- symbol names, 82.
- synonyms, 37.
-
- T. S. Eliot, 53.
- ``take'' verb, 37.
- |talkable|, 76.
- |task scores|, 58.
- |TASKS PROVIDED|, 58.
- tasty food, 13.
- team of four adventurers, 30.
- teleportation, 30.
- television set, 23, 93.
- Tera, 3.
- text style, 65.
- `The Legend Lives', 40.
- The Prisoner, 26.
- |the time|, 36.
- |thedark|, 30, 74.
- |TheSame|, 56.
- thief in `Zork I', 34, 35, 94.
- |ThrowAt|, 28, 29.
- tidying-up operations, 34.
- |time left|, 77.
- time of day, 36.
- |time out|, 35, 77.
- time sequence, 36.
- timed input, 66.
- |TimePasses|, 79.
- timers, 35.
- ``timers'' verb, 60.
- Timothy Anderson, 26.
- toffee apple, 18.
- token for `any object', 99.
- tokenisation, 97.
- tokens, 38.
- toothed bag, 22, 93.
- |top object|, 73.
- `Toyshop', 34, 53, 97.
- ``trace'' verb, 60.
- tracing a routine, 61.
- tracing routines, actions, daemons and timers, 60.
- tracing the parser, 61.
- transcript, 66.
- |transparent|, 22, 23, 29, 76.
- treasure class, 33.
- tree of objects, 9.
- ``tree'' verb, 60.
- `Trinity', 17.
- troll, 50.
- |TryNumber|, 80.
- two-way door, 24.
- txd (disassembler), 60.
- types (lack of), 11.
-
- underlining, 65.
- ``undo'' verb, 62, 65.
- |UnknownVerb|, 43, 79.
- urchin and hacker, 29.
-
- valuable cake, 33.
- variable strings, 92.
- variables, 68.
- vehicles, 26.
- |Verb|, 37.
- |VerbLib|, 4.
- version 6, 62.
- very last resort, 59.
- |visited|, 76.
- vocabulary size, 62.
- VT100, 65.
-
- W. H. Auden, 23.
- W. S. Gilbert, 50.
- walls, 74.
- `wandering monsters', 34.
- warnings, 87.
- warthog, 94.
- weights, 34, 95.
- weird thing, 54.
- ``what is a grue'', 45.
- |when closed|, 24, 77.
- |when off|, 77.
- |when on|, 77.
- |when open|, 24, 77.
- wide inventory, 51.
- William Shakespeare, 44, 100.
- Willie Crowther, 3.
- |with|, 12.
- |with key|, 22, 77.
- |wn|, 41.
- woodpecker, 59.
- |workflag|, 76.
- world colours, 17, 91.
- |worn|, 76.
- |WriteListFrom|, 50.
-
- ``xyzzy'' verb, 38.
-
- |YesOrNo()|, 59.
- |younger|, 10.
- |youngest|, 10.
-
- Z-machine, 8.
- ``zero'', 41.
- Zip, 60, 60, 65.
- `Zork I', 34, 35.
- `Zork', 8.
- zterp, 65.
- \endindex
- \end
- % End of TeX source for the Inform Designer's Manual
-
-