% --------------------------------------------------------------------------
% TeX source for the Inform Designer's Manual
%
% Third edition (updated and revised)
% (c) Graham Nelson 1993, 1994, 1995, 1996, 1997
% --------------------------------------------------------------------------
% The file begins with TeX hackery defining styles and so on, but
% subsequently becomes marked-up text
% --------------------------------------------------------------------------
\newif\iffiles\filestrue
%
% Manual macros
%
% Page layout
%
\newif\ifshutup\shutupfalse
\newif\iflexicon\lexiconfalse
\newif\ifanswers\answersfalse
\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{{\rhrm\topmark}} % 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{\mark{}\vskip 1 true in\goodbreak
\noindent{\sectfont #1\quad #2}\bigskip\newsection{#1}{#2}\noindent\mark{#1\quad #2}}
\def\sectionx#1{\mark{}\vskip 1 true in\goodbreak
\noindent{\sectfont #1}\bigskip\newsection{}{#1}\noindent\mark{\quad #1}}
%
\def\newpage{\mark{}\vfill\eject}
%
% Headers and footers
%
\newif\iftitle
\headline={\iftitle\hfil\global\titlefalse%
\else{\iflexicon{\bf\firstmark}\hfil{\bf\botmark}\else%
\ifanswers{\hfil\ifnum\firstmark=\botmark%
{\rhit Answer to exercise \rhrm\firstmark}%
\else{\rhit Answers to exercises \rhrm\firstmark-\botmark}%
\fi}\else%
\hfil{\rhit \rhead}\fi\fi}%
\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=-1 % -2
\hbox to0pt{\hskip-\hangindent\dbend\hfill}\ninepoint}
\def\refd@nger{\par\nobreak\noindent\begingroup\clubpenalty=10000
\def\par{\endgraf\endgroup\medbreak}\ninepoint}
\outer\def\danger{\d@nger}
\def\dd@nger{\medskip\begingroup\clubpenalty=10000
\def\par{\endgraf\endgroup\medbreak} \noindent\hang\hangafter=-1 % -2
\hbox to0pt{\hskip-\hangindent\dbend\kern 1pt\dbend\hfill}\ninepoint}
\outer\def\ddanger{\dd@nger}
\def\ddd@nger{\medskip\begingroup\clubpenalty=10000
\def\par{\endgraf\endgroup\medbreak} \noindent\hang\hangafter=-1 % -2
\hbox to0pt{\hskip-\hangindent\dbend\kern 1pt\dbend\kern 1pt\dbend\hfill}\ninepoint}
\outer\def\dddanger{\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}
\def\rstok#1{\leavevmode\thinspace\hbox{\vrule\vtop{\vbox{\hrule\kern1pt
\hbox{\vphantom{\rm!}\thinspace{\rm#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\refs{\medbreak
\noindent\llap{$\bullet$\rm\kern.15em}%
{\eightbf REFERENCES}\refd@nger}
\outer\def\nextref{\quad$\bullet$\quad}%
\outer\def\exercise{\medbreak \global\advance\exno by 1
\noindent\llap{$\bullet$\rm\kern.15em}%
{\eightbf EXERCISE \bf\the\exno}\refd@nger}
%\par\noindent
\def\dexercise#1{\global\advance\exno by 1
\medbreak\noindent\llap{$\bullet$\rm\kern.15em}%
#1{\eightbf ~EXERCISE \bf\the\exno}\refd@nger}
% \hfil\break}
\outer\def\dangerexercise{\xd@nger \dexercise{\dbend}}
\outer\def\ddangerexercise{\xd@nger \dexercise{\dbend\dbend}}
\newwrite\ans%
\newwrite\conts%
\iffiles
\immediate\openout\conts=$.Adventure.mandir.dmanual.conts
\fi
\iffiles\else\outer\def\answer#1{\par\medbreak}\shutuptrue\fi
\newwrite\inx
\ifshutup\else
\immediate\openout\inx=$.Adventure.mandir.dmanual.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\widequote{\medskip\begingroup\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\tlwidequoteby#1#2{\par\smallskip\qquad
-- #1\par\smallskip\qquad\qquad\qquad
-- #2\tenpoint\endgroup\bigskip}
\def\tvquoteby#1#2{\par\smallskip\qquad
-- #1\par\qquad\qquad\quad
\phantom{--} #2\tenpoint\endgroup\bigskip}
\def\endquote{\par\tenpoint\endgroup\medskip}
%
% End of macros
% --------------------------------------------------------------------------
\iffiles%
\immediate\openout\ans=$.Adventure.mandir.dmanual.answers%
\immediate\openout\conts=$.Adventure.mandir.dmanual.conts%
\outer\def\answer{\par\medbreak
\immediate\write\ans{}
\immediate\write\ans{\string\ansno\the\exno:}
\copytoblankline}
\def\copytoblankline{\begingroup\setupcopy\copyans}
\def\setupcopy{\def\do##1{\catcode`##1=\other}\dospecials
\catcode`\|=\other \obeylines}
{\obeylines \gdef\copyans#1
{\def\next{#1}%
\ifx\next\empty\let\next=\endgroup %
\else\immediate\write\ans{\next} \let\next=\copyans\fi\next}}
\fi
\def\ruleon{\smallskip\ninepoint}
\def\ruleson{\ruleon}
\def\ruleoff{\tenpoint\smallskip\par\noindent}
\def\rulesoff{\ruleoff}
\def\chapter#1{\newpage\global\titletrue\centerline{\bigfont #1}}
\newdimen\stepin
\newdimen\tstepin
\stepin=60pt
\def\block#1{\par%\rlap{{\tt #1}}
\hangindent\stepin\hangafter0\noindent\strut\llap{\hbox to\stepin{{\tt #1}\hfill}}%
\noindent}
\def\bblock#1{\par\tstepin=\stepin\multiply\tstepin by2%
\hangindent\stepin\hangafter0\noindent\hbox to\stepin{\hfil}%
\llap{\hbox to\tstepin{{\tt #1}\hfill}}%
\noindent}
\def\banner#1{%
\medbreak\hrule
\smallskip\tenpoint
\hbox to \hsize{#1}
\smallskip\ninepoint
\hrule
\smallskip\noindent}
\def\prop#1#2{\banner{{\tt #1}\hfill{#2}}}
\def\propd#1#2#3{\banner{{\tt #1}\hfill{#2}\quad{\tt #3}}}
\def\cprop#1#2{\banner{{\tt #1}\hfill{#2}\quad$\oplus$}}
\def\cpropd#1#2#3{\banner{{\tt #1}\hfill{#2}\quad{\tt #3}\quad$\oplus$}}
\def\fr{\noindent{\sl For rooms}\quad}
\def\fo{\noindent{\sl For objects}\quad}
\def\fpo{\noindent{\sl For the player-object}\quad}
\def\fco{\noindent{\sl For compass objects}\quad}
\def\fato{\noindent{\sl For |animate| or |talkable| objects}\quad}
\def\rr{\noindent{\sl Routine returns}\quad}
\def\nrr{\noindent{\sl No return value}\quad}
\def\warn{\noindent{\sl Warning}\quad}
\def\BAR{{\tt\char`\|}}
% --------------------------------------------------------------------------
\centerline{\bigfont The Inform Designer's Manual}
\vskip 0.5in
\centerline{by Graham Nelson}
\vskip 0.25in
\centerline{\sl Third edition}
\smallskip
\centerline{4 September 1996}
\smallskip
\centerline{as updated 16 May 1997}
\vskip 0.5in
\sli{}{Detailed contents}{2}
\sli{}{Introduction}{7}
\bigskip
\centerline{{\bf Book One: Programming}}
\bigskip
\sli{I}{The Inform Programming Language}{10}
\sli{II}{Using the Compiler}{64}
\bigskip
\centerline{{\bf Book Two: Designing}}
\bigskip
\sli{III}{Fundamentals}{83}
\sli{IV}{The Model World}{98}
\sli{V}{Describing and Parsing}{137}
\sli{VI}{Testing and Hacking}{170}
\bigskip
\centerline{{\bf Appendices}}
\bigskip
\sli{}{Tables and summaries}{182}
\sli{}{Answers to all the exercises}{214}
\sli{}{Index}{256}
\newpage
\def\mli#1{\endgroup\bigbreak\noindent{\bf #1}\medskip\begingroup}
\def\partli#1{\endgroup\bigbreak\noindent{\sl #1}\medskip\begingroup}
\def\with#1{\par\noindent{\sl #1}\smallbreak}
\def\ssli#1#2#3{\endgroup\par\smallbreak\noindent\hbox to\hsize%
{\tenpoint#1\quad#2\dotfill #3}\par%
\begingroup\noindent\narrower\ninepoint}
\def\sslix#1#2{\medbreak\par\noindent\hbox to\hsize%
{\tenpoint{\bf #1}\dotfill #2}\par\hangindent=1in\ninepoint}
\def\sssli#1#2{\par\noindent\hbox to 4in%
{\quad\ninepoint{#1. #2\hfill}}}
\sectionx{Contents}
\titletrue
\sslix{Introduction}{7}%
\begingroup%
\partli{\bf BOOK ONE: PROGRAMMING}
\mli{Chapter I: The Inform Programming Language}
\ssli{1}{The language of routines}{10}%
\sssli{1}{First principles}
\sssli{2}{Example 1: Hello World}
\sssli{3}{Example 2: Elsinore}
\sssli{4}{Numbers and variables}
\sssli{5}{Arithmetic expressions}
\sssli{6}{Arguments and return values}
\sssli{7}{Example 3: Cubes}
\sssli{8}{Conditions: |if|, |true| and |false|}
\sssli{9}{Example 4: Factorials}
\sssli{10}{Code blocks, |else| and |switch|}
\sssli{11}{|while|, |do|... |until|, |for|, |break|, |continue|}
\sssli{12}{Example 5: A number puzzle}
\sssli{13}{|quit| and |jump|; saving the program state}
\sssli{14}{Printing output}
\sssli{15}{Example 6: Printing in hexadecimal}
\sssli{16}{Built-in functions 1: |random| and |indirect|}
\sssli{17}{{\sl Accepting input}}
\ssli{2}{The language of data}{36}%
\sssli{1}{Directives and constants}
\sssli{2}{Global variables}
\sssli{3}{Arrays}
\sssli{4}{Example 7: Shuffling a pack of cards}
\sssli{5}{{\sl Seven special data structures}}
\ssli{3}{The language of objects}{44}%
\sssli{1}{Objects and communication}
\sssli{2}{Built-in functions 2: the object tree}
\sssli{3}{Creating objects 1: setting up the object tree}
\sssli{4}{Statements for objects: |move|, |remove|, |objectloop|}
\sssli{5}{Creating objects 2: |with| properties}
\sssli{6}{|private| properties and encapsulation}
\sssli{7}{Attributes, |give| and |has|}
\sssli{8}{Classes and inheritance}
\sssli{9}{Messages}
\sssli{10}{{\sl Access to superclass values}}
\sssli{11}{{\sl Philosophy}}
\sssli{12}{{\sl Sending messages to routines, strings or classes}}
\sssli{13}{{\sl Creating and deleting objects}}
\sssli{14}{{\sl Footnote on common vs. individual properties}}
\mli{Chapter II: Using the Compiler}
\ssli{4}{The language of Inform}{64}%
ICL (Inform Control Language); |Include|; conditional compilation: |If...|,
|Ifnot|, |Endif|; |Message|; linking in the library; writing new modules
to link in.
\ssli{5}{Compiler options and memory settings}{70}%
Switches; memory sizes; typical memory usage; raising memory settings.
\ssli{6}{All the Inform error messages}{74}%
Fatal errors; errors, including linker and assembler errors; warnings,
including obsolete usage warnings.
\bigskip
\partli{\bf BOOK TWO: DESIGNING}
\mli{Chapter III: Fundamentals}
\ssli{7}{Getting started}{83}%
Beginning to lay `Ruins'; including the library files; the |Initialise|
routine; some properties of mushrooms; |name|, |description| and |initial|;
|edible| foodstuffs; introducing |before| and |after| rules; the stone
steps; self-destructing rules.
\ssli{8}{Introducing messages and classes}{88}%
Recap of message-sending: a parrot; classes for treasure artifacts:
the pygmy statuette, the honeycomb; how clashes are sorted out in class
inheritance, additivity.
\ssli{9}{Actions and reactions}{92}%
Actions are attempts; generating them with |<|, |<<|; the |action|,
|noun| and |second| variables (and |inp1|, |inp2|); the |##| notation;
the standard actions, in Groups 1 to 3; creating new actions, the
|Blorple| example; fake actions like |ThrownAt|; how actions are processed,
over `Before', `During' and `After' stages.
\mli{Chapter IV: The Model World}
\ssli{10}{Places, scenery, directions and the map}{98}%
Giving `Ruins' a small map; |n_to|, |d_to|, etc.; when you |cant_go|;
scenery objects; |default| rules; rooms have |before| and |after| too; a
mist object, present in many rooms, using |found_in|; the five senses
and reaction rules; direction objects in the |compass|.
\ssli{11}{Containers, supporters and sub-objects}{103}%
Containers: |container|, |supporter|, |capacity|, |open|, |openable|; locks
and keys: |locked|, |lockable|, |with_key|; |LetGo| and |Receive| to trap
use of a container: a horrifying chasm; the |Search| action; |transparent|
objects have visible sub-objects; a television set with buttons.
\ssli{12}{Doors}{105}%
How to create a |door|; |door_to|, |door_dir|; |when_open|, |when_closed|;
a stone door for `Ruins'; a two-way door, the `Advent' grate; why
|door_dir| is needed and how to trap every attempt to go through.
\ssli{13}{Switchable objects}{107}%
|switchable| and |on|: |when_on|, |when_off|; the Gotham City searchlight;
a sodium lamp; |describe| taking precedence.
\ssli{14}{Things to enter, travel in and push around}{109}%
|enterable| objects: a slab altar; vehicles: KAR 1; special rule about
the |Go| action when inside something |enterable|; the |PushDir| action:
a huge pumice-stone ball; pushing up and down.
\ssli{15}{Reading matter and consultation}{111}%
The |Consult| action, ``look up''; |consult_from| and |consult_words|:
a dictionary of glyphs, Tyndale's Bible; making ``read'' and ``examine''
different.
\ssli{16}{Living creatures and conversation}{113}%
|animate| objects and the |life| rule; a mummified priest, Blofeld,
a coiled snake; some people are |transparent|; orders: actions for other
people; |talkable| objects; parsing conversation: Zen and Charlotte;
untypeable verbs; fake fake actions; several voice-activated machines;
applications of scope: telepathy and phone calls.
\ssli{17}{The light and the dark}{121}%
Light and darkness is automatically managed; the definition of `when there
is light'; |OffersLight| and |HasLightSource|; going from darkness to
darkness and the |DarkToDark| entry point; modifying the darkness object.
\ssli{18}{Daemons and the passing of time}{123}%
Daemons and the |daemon| property; starting and stopping them; background
daemons; timers (fuses); |time_left| and |time_out|; |each_turn| events for
places and nearby objects; the time of day; changing it with |SetTime|; on
the status line; midnight, sunrise, sunset; the exact sequence of events
at end-of-turn.
\ssli{19}{Starting, moving, changing and killing the player}{126}%
What |Initialise| should do; the |location|; initial restoration;
teleportation and the |PlayerTo| routine; what happens when the room
changes: |NewRoom|, |initial| for a room, |visited|; giving the player his
own |before| rule; using |ChangePlayer| to transform him into any object;
multi-character games; life and |deadflag|; the |DeathMessage| routine;
resurrection and the |AfterLife| routine.
\ssli{20}{Miscellaneous constants and scoring}{130}%
|Story| and |Headline|; |MAX_CARRIED|; the automatic rucksack |SACK_OBJECT|;
`amusing' rewards for the victorious; two scoring systems: |MAX_SCORE|,
|OBJECT_SCORE|, |ROOM_SCORE|; tasks: |TASKS_PROVIDED|, |NUMBER_TASKS|,
|task_scores|, |PrintTaskName|; rankings and |PrintRank|; automatic score
notification and |notify_mode|; ``objects'' and ``places'' verbs, removable
with |NO_PLACES|.
\ssli{21}{Extending and redefining the Library}{132}%
Enriching the model; amulets and their spells; making a new library file;
new common properties; changing default values of these; the
|LibraryMessages| system for changing messages like ``Dropped.''; changing
the prompt; the last resort, using |Replace| directives; even on `hardware'
functions like |random|.
\vfill\eject
\mli{Chapter V: Describing and Parsing}
\ssli{22}{Describing objects and rooms}{137}%
|print (The) obj|, |... (the) obj| and so on; indefinite and
definite |article|; |proper| nouns; the |short_name| of an object;
|invent| strings and routines; exactly how inventory lines are
printed; a matchbook; |describe| routines; exactly how rooms
are described; |Locale|.
\ssli{23}{Listing and grouping objects}{142}%
The list-maker |WriteListFrom|; its style bitmap; examples: tall and
wide inventories; grouping similar items together in lists: foodstuffs,
Scrabble pieces and denominations of coin.
\ssli{24}{How nouns are parsed}{145}%
How |name| is used; a fried green tomato turning red; the parser breaks
text into a stream of words; |wn| and |NextWord|; reading words as
numbers or from their raw text; a |parse_name| routine is much more
flexible than |name|; the |ParseNoun| entry point; distinguishing
adjectives from nouns.
\ssli{25}{Plural names for duplicated objects}{149}%
Collections of indistinguishable objects; a bag of six coins; the |plural|
property for printing out plurals; definition of `indistinguishable';
writing |parse_name| routines to allow plurals to be understood; class of
crowns.
\ssli{26}{How verbs are parsed}{151}%
The parser's fundamental method; |BeforeParsing| entry point; the actor and
verb word; synonyms for verbs; definitions of grammar, line and token;
|action_to_be|; |Verb| directive: a simplified ``take'' grammar; |meta|
verbs; grammar creates actions; creating an ``xyzzy'' verb; how to |Extend|
grammar for an existing verb: pushing numbered buttons; priority: |replace|,
|first|, |last|; splitting synonymous verbs apart with |Extend| |only|; the
|UnknownVerb| and |PrintVerb| entry points.
\ssli{27}{Tokens of grammar}{156}%
Full list of grammar tokens; prepositions; |noun| and |held|; implicit
taking; tokens allowing multiple objects like ``all''; filtering out nouns
by attribute: ``use'' verb; and by general routine: ``free'' verb; parsing
numbers: ``type'' verb, |ParseNumber|; general parsing routines; reading
from the parser's raw text |buffer| and |parse| table; exercises, including
French, telephone and floating-point numbers, times of day, adding a
|third| parameter to a grammar line.
\ssli{28}{Scope and what you can see}{162}%
The definition of `in scope'; touchability is stricter than scope;
answering questions: ``what is a grue''; |scope=...| tokens with
programmable scope; |scope_stage|, |ScopeWithin| and |PlaceInScope|;
changing the global definition of `in scope' using |InScope|;
|scope_reason|; looping over and testing scope; making the rules more
sensitive to darkness; a long room divided by a glass wall; the
|add_to_scope| property for component parts of containers.
\ssli{29}{Helping the parser out of trouble}{168}%
Parser error messages and |ParserError|; ambiguity-resolution and
influencing it with |ChooseObjects|; making ``eat'' prefer |edible|
objects; redefining ``all''.
\vfill\eject
\mli{Chapter VI: Testing and Hacking}
\ssli{30}{Debugging verbs and tracing}{170}%
Suite of debugging verbs: ``purloin'', ``abstract'', ``tree'', ``scope'',
``goto'', ``gonear'', ``actions'', ``routines'', ``timers'', ``trace'',
``recording'', ``replay'', ``random''; transcriptions; the random-number
generator; Infix-format debugging files; how to crash the game interpreter
at run-time; the levels of parser tracing; compiling with debugging code.
\ssli{31}{Limitations on the run-time format}{173}%
Formats of the Z-machine; restrictions: memory, vocabulary, dictionary
resolution, attributes, properties, names, special effects, objects, memory
management, global variables, ``undo'' verb, function arguments; using
|Abbreviate| to save run-time memory.
\ssli{32}{Boxes, menus and drawings}{175}%
Asking yes/no questions with |YesOrNo|; the status line; character graphics,
escape characters; proportional- and fixed-pitch fonts, |font|; epigrams in
boxes and |box|; menus of text options, |DoMenu|, |pretty_flag|,
|menu_item|; an example menu; submenus are allowed; changing the text
|style| to bold-face, underlining, reverse video.
\ssli{33}{Descending into assembly language}{177}%
Assembly language |@|; reliability of interpreters; table of opcodes worth
knowing about; upper and lower windows: splitting, setting the window, moving
the cursor, clearing the screen, word-breaking; the colour scheme; a bell
sound; keyboard reading in real-time; function and cursor keys; tokenising
with dictionaries; encoding dictionary entries; input/output streams; the
stack frame: throw and catch; examples: a title page, drawing status lines,
formatting and centering text.
\bigskip
\mli{APPENDIX: Tables and summaries}
\ssli{A1}{Inform operators}{182}%
\ssli{A2}{Inform statements}{184}%
\ssli{A3}{Inform directives}{185}%
\ssli{A4}{Grammar}{186}%
\ssli{A5}{Library attributes}{187}%
\ssli{A6}{Library properties}{190}%
\ssli{A7}{Library-defined objects and routines}{196}%
\ssli{A8}{Library actions}{198}%
\ssli{A9}{Library message numbers}{199}%
\ssli{A10}{Entry points and meaningful constants}{203}%
\ssli{A11}{What order the program should be in}{205}%
\ssli{A12}{A short Inform lexicon}{206}%
\endgroup
\sslix{Answers to all the exercises}{214}%
\sslix{Index}{256}%
\tenpoint
\newpage
\sectionx{Introduction}
\titletrue
\poem
I will build myself a copper tower
With four ways out and no way in
But mine the glory, mine the power$\ldots$
\poemby{^{Louis MacNeice} ({\oldstyle1907}--{\oldstyle1963})}{Flight of the Heart}
\noindent
Inform is a system for creating adventure games, and this is the book to
read about it.
Infocom format `^{story files}' (adventure games, that is) can be played on
almost any computer, from personal organisers to mainframes, with the aid of
`interpreter' programs. The task of the Inform `compiler' is to translate a
textual description of a game into a story file. The result will play
identically on any machine of any model.
Inform is a suite of software, called the `library', as well as a compiler.
Without the library, it would be a major undertaking to write a description
of even the smallest game. The library has two ingredients: the parser, a
program for translating written English inputs into a form games can more
easily understand, and the ``world model'', a complex web of rules common
to all adventure games. Given these, the designer only needs to describe
things and give any exceptional rules that apply. (``There is a bird here,
which is a normal item except that you can't pick it up.'')
The library is rich in detail. The parser recognises over 80 distinct verbs
and a vocabulary of about 300 words even before any rooms or objects are
created, and is programmable and highly flexible. It can handle ambiguities,
clarify its input by asking questions (``Which key do you mean...?'') and can
cope properly with plurals, vagueness, conversation, pronouns and the player
becoming someone else in mid-game. It can be configured to languages other
than English. The world-model includes rooms, items, vehicles, duplicates,
containers, doors, things on top of other things, light and darkness,
switching things on and off, opening, closing and locking things, looking
up information in books, entering things, scoring and so forth.
\bigskip
Just as Inform has two strands -- compiler and library -- so this manual has
two parts: Programming and Designing. In Book One, small computer programs
are written to perform simple calculations, never using the library. Subsections
listed {\sl in slanted text} on the detailed contents page become technical
but the rest is pitched at newcomers and can be skim-read by anyone with
prior experience of a programming language such as C or Pascal. Book Two
is entirely about making games.
Newcomers are invited to work through \S 1 and \S 7, the ``getting started''
sections in Books One and Two, before reading much more of either.
\bigskip
In trying to be both a tutorial and reference work, this book aims itself
in style halfway between the two extremes of manual, Tedium and Gnawfinger's
{\sl Elements of Batch Processing in COBOL-66}, third edition, and Mr Blobby's
{\sl Blobby Book of Computer Fun}. (This makes some sections both leaden
{\sl and} patronising.) Passages which divert the main story, usually to
tell an unexpurgated truth which may confuse or bore a newcomer, are marked
with a warning triangle $\triangle$ or two, and set in smaller type. Examples
of program are set in |typewriter| font. Mundane or irrelevant passages in
longer examples are sometimes replaced with a line reading just ``|...|''
To keep Book Two from clogging up with examples, many are set as
``^{exercises}'', with ``answers'' given in full at the back of the book.
Harder exercises are marked with triangles and some are very hard indeed.
I emphasize that the exercises are often intended as a way of presenting answers
to deliberately difficult questions, to assist experts: the curse of Adventure
design-languages is the feature which is ideal for the simple but too inflexible
to cope with the complicated. For a list of exercises with page references to
question and answer, see under ``exercises'' in the Index.
A better tutorial than attempting the exercises, then, is probably to make
a simple game, as demonstrated in Chapter III, and then add an example of each
new feature as you work through Chapters IV and V.
Many sections end with a `References' paragraph referring to yet
more examples which can be found in Inform's demonstration games. All of these
have publically available source code (see the Inform home page): those most
frequently referred to are ^{`Advent'} (a full version of the original
^{mainframe `Adventure'}, which contains a good deal of ``everyday Inform''),
^{`Adventureland'} (a version of ^{Scott Adams}'s primitive classic),
^{`Alice Through The Looking-Glass'} (a heavily annotated game, developed in
the course of Gareth Rees's WWW tutorial for Inform), ^{`Balances'} (a short
story consisting of puzzles which stretch the parser's abilities) and
^{`Toyshop'} (hardly a game: more an incoherent collection of unusual
objects). In addition, the little game ^{`Ruins'} is developed
in the course of Chapters III and IV of this manual.
Finally, the ``game'' called ^{`Museum of Inform'} simulates a museum whose
exhibits are solutions to the exercises in this manual.
\bigskip
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 the author under the Copyrights,
Designs and Patents Act 1988. 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. (Exceptions to these rules must be negotiated directly with the
author.) 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.
The Internet source for Inform material (executables of the compiler for
different machines, source code, the library files and example games)
is the German National Research Centre for Computer Science, where Volker
Blasius maintains an archive at the anonymous FTP site |ftp.gmd.de|.
Inform can be found at:
\beginstt
ftp://ftp.gmd.de/if-archive/infocom/compilers/inform6
\endtt^^{ftp site}^^{home page}^^{Inform home page}
Another useful resource is the Inform 6 home page on the `^{World Wide Web}',
which includes ^{Gareth Rees}'s ^{`Alice'} tutorial, located at:
\beginstt
http://www.gnelson.demon.co.uk/inform.html
\endtt
This manual describes Inform release 6.13 (or later), using
library release 6/5 (or later). Earlier Inform 6 compilers and
libraries are very similar but Inform 5.5 and 5/12 are very different.
\bigskip
This manual has evolved from seven earlier publications, once rather makeshift
and sometimes defensive (``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 four ^{`companion volumes'}. {\sl The Craft of Adventure} is
an essay on the design of adventure games; {\sl The Z-Machine Standards
Document} minutely covers the run-time format and Inform assembly
language, its lowest level; and {\sl The Inform Technical Manual} documents
Inform's internal working in great detail, and includes a formal context-free
grammar for the Inform language. The {\sl Inform Translator's Manual}
describes how to write a language definition file for games which speak
languages other than English.
\bigskip
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 close of the 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 and Gareth Rees, among others.
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, the ever avuncular Bob Newell, Robert
Pelak, Gareth Rees, J\o rund Rian, Dilip Sequeira, Richard Tucker,
Christopher Wichura and John Wood.
One final word. I should like to dedicate this book, impertinently perhaps,
to our illustrious predecessors: ^{Will Crowther}, ^{Don Woods} and
the authors of ^{Infocom, Inc.}
\medskip
%$ Graham Nelson
%$ Oxford
%$ May 1997
%$-3
\hbox to\hsize{\hfill\it Graham Nelson}
\hbox to\hsize{\hfill\it Oxford}
\hbox to\hsize{\hfill\it April 1993 -- May 1997}
\bigskip\medskip
\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} ({\oldstyle1571}?--{\oldstyle1631})}{The Canonization}
\newpage
\chapter{Chapter I: The Inform programming language}
\vskip 0.5in
\quote
Language is a cracked kettle on which we beat out tunes
for bears to dance to, while all the time we long to move
the stars to pity.
\quoteby{^{Gustave Flaubert} ({\oldstyle1821}--{\oldstyle1880})}
\section{1}{The language of routines}
\def\asection#1#2{\bigbreak\noindent{\bf \S 1.#1\quad #2}\medskip\noindent}
\asection{1}{First principles}%
This chapter aims to introduce beginners to Inform as though it were a
general-purpose programming language (rather than a tool for designing
adventure games). The examples given will be short programs performing
simple calculations (rather than games). To begin with, the Inform language
is:
\item{1.}{\bf Compiled.}^^{compilation}
\item{}{That is, the Inform compiler translates text written by the author
(called the ``source code'') into a program (called the ``object code''
since it is the object of the exercise). This translation is only done
once, but the resulting program can be run many times.}
\item{2.}{\bf Procedural.}^^{procedural language}
\item{}{That is, a program is divided into
a number of ``routines'' (also called ``functions'' or ``procedures''), each
being a list of orders to be obeyed (though these orders are traditionally
called ``statements''). When the program is run, only one thing happens at
a time: at any given moment, a single routine is being obeyed.}
\item{3.}{\bf Object-oriented.}^^{object orientation}
\item{}{That is, the fabric of a typical Inform program will be woven around
``objects'' being dealt with, which are regarded as being self-contained.
For example, a program to simulate a warehouse might have objects
representing lorries and containers; each object would have a position
and contents at any given time. The program would have general rules
describing ``lorry'' and ``container'' as well as actual examples of each.
A lorry would have the ability to receive a message telling it to do
something, such as ``load up with a container and leave the warehouse''.}
\item{4.}{\bf Portable.}^^{portability}
\item{}{That is, once Inform has compiled the source code (having found no
mistakes), the resulting program can be run on almost any model of
computer. It will exhibit exactly the same behaviour on each of them.
It cannot depend on the ``environment'': it cannot suddenly run out
of memory and crash, for instance.}
\medskip\noindent%
The computer runs an Inform program (which need not be a game) with the aid
of an ``^{interpreter}''. There are at least 40 different interpreters
available for this format (called the ``Z-machine'' or ``Infocom format'')
and there may be a choice available for your model of computer: it is a good
idea to get the most modern and accurate possible. Look to see if they
support the Z-Machine Standard, and if so, up to what revision number.
\asection{2}{Example 1: Hello World}^^{Hello World}%
Traditionally, all programming language tutorials begin by giving a program
which does nothing but print ``Hello world'' and stop. Here is such a program
in Inform:
\beginstt
! "Hello world" example program
[ Main;
print "Hello world^";
];
\endtt^^{comments}
The text after the exclamation mark is a ``comment'', that is, it is text
written in the margin by the author to remind himself of what is going on
here. Such text means nothing to Inform, which ignores anything on the
same line and to the right of an exclamation mark.
Once commentary has been stripped out, Inform regards the source code as a
list of things to look at, divided by ^{semicolons} |;|. It treats line
breaks, tab characters and spaces all as so-called ``^{white space}'': that
is, a gap between two things whose size is unimportant. Thus, exactly the
same program would be produced by the source code
\beginstt
[
Main ;
print
"Hello world^" ;
]
;
\endtt
or, at the other extreme, by
\beginstt
[ Main;print"Hello world^";];
\endtt
Laying out programs legibly is a matter of forming good habits.
\danger
The exception to the rule about ignoring white space is inside quoted text,
where
\begindisplay
|"Hello world^"| and |"Hello world^"|\cr
\enddisplay
are genuinely different pieces of text and are treated as such. Inform
treats text inside quotation marks with much more care than its ordinary
program material: for instance, an exclamation mark inside quotation marks
will not cause the rest of its line to be thrown away as a comment.
Every program must contain a routine called |Main|, and in this example it
is the only routine. When a program is set running, the first instruction
obeyed is the first one in |Main|, and it carries on line by line from there.
This process is called ``execution''. When the |Main| routine is finished,
the program stops.
The routine has only one statement:
\beginstt
print "Hello world^"
\endtt
Printing is the process of writing text onto the computer screen. This
statement prints the two words ``Hello world'' and then skips the rest of
the line (or ``prints a new-line''): the |^| character, in quoted text,
means ``new-line''. For example, the statement
\beginstt
print "Blue^Red^Green^"
\endtt
prints up:
\begindisplay
Blue\cr
Red\cr
Green\cr
\enddisplay^^{statements: print}
|print| is one of 28 statements in the Inform language. The full list is as
follows:
\beginstt
box break continue do font for give
if inversion jump move new_line objectloop print
print_ret quit read remove restore return rfalse
rtrue save spaces string style switch while
\endtt^^{statements}
(Only about 20 of these are commonly used.) \S 1 covers all those not
concerned with objects, which are left until \S 3.
\asection{3}{Example 2: Elsinore}^^{Elsinore}^^{Hamlet}^^{Rosencrantz}%
The following source code has three routines, |Main|, |Rosencrantz| and
|Hamlet|:
\beginstt
[ Main;
print "Hello from Elsinore.^";
Rosencrantz();
];
[ Rosencrantz;
print "Greetings from Rosencrantz.^";
];
[ Hamlet;
print "The rest is silence.^";
];
\endtt
The resulting program prints up
\begindisplay
Hello from Elsinore.\cr
Greetings from Rosencrantz.\cr
\enddisplay
but the text ``The rest is silence.'' is never printed. Execution begins at
|Main|, and ``Hello from Elsinore'' is printed; next, the statement
|Rosencrantz()| causes the |Rosencrantz| routine to be executed. That
continues until it ends with the close-routine marker |]|, whereupon
execution goes back to |Main| just after the point where it left off: since
there is nothing more to do in |Main|, the program finishes. Thus,
|Rosencrantz| is executed but |Hamlet| is not.
In fact, when the above program is compiled, Inform notices that
|Hamlet| is never needed and prints out a warning to that effect. The
exact text produced by Inform varies from machine to machine, but will be
something like this:
\beginstt
RISC OS Inform 6.03 (May 11th 1996)
line 8: Warning: Routine "Hamlet" declared but not used
Compiled with 0 errors and 1 warning
\endtt^^{declared but not used}^^{error messages}^^{warning messages}
Errors are mistakes in the program which cause Inform to refuse to compile
it, but this is only a warning. It alerts the programmer that a mistake
may have been made (because presumably the programmer has simply forgotten
to put in a statement calling |Hamlet|) but it doesn't prevent the
compilation from taking place. Note that the opening line of the routine
|Hamlet| occurs on the 8th line of the program above.
Usually there are mistakes in a newly-written program and one goes through
a cycle of running a first draft through Inform, receiving a batch of
error messages, correcting the draft according to these messages, and trying
again. A typical error message would occur if, on line 3, we had mistyped
|Rosncrantz()| for |Rosencrantz()|. Inform would then have produced:
\beginstt
RISC OS Inform 6.03 (May 11th 1996)
line 5: Warning: Routine "Rosencrantz" declared but not used
line 8: Warning: Routine "Hamlet" declared but not used
line 3: Error: No such constant as "Rosncrantz"
Compiled with 1 error and 2 warnings (no output)
\endtt
The error message means that on line 3 Inform ran into a name which did
not correspond to any known quantity (it isn't the name of any routine, in
particular). Note that Inform never produces the
final story file if errors occur during compilation: this prevents it
from producing damaged story files. Note also that Inform now thinks the
routine |Rosencrantz| is never used, since it didn't recognise the mistype
in the way that a human reader would have done. Warnings are sometimes
produced by accident this way, so it is generally a good idea to worry
about fixing errors first and warnings afterward.
\asection{4}{Numbers and variables}^^{numbers}^^{variables}%
Internally -- that is, whatever the outward appearance -- all programs
essentially manipulate numbers. Inform understands ``number'' to be a
whole number in the range -32768 to +32767. (Special programming would be
required to represent larger numbers or fractions.) There are three
notations for writing numbers in Inform: here is an example of each.
\beginstt
-4205
$3f08
$$1000111010110
\endtt^^{hexadecimal numbers}^^{binary numbers}^^{decimal numbers}
^^{number base}^^{radix}^^{base (of numbers)}
The difference is the radix, or base, in which they are expressed. The
first is in decimal (base 10), the second hexadecimal (base 16, where
the digits after 9 are written |a| to |f| or |A| to |F|) and the third
binary (base 2). Once Inform has read in a number, it forgets which
notation was used: for instance, if the source code is altered so that
|$$10110| is replaced by |22|, this makes no difference to the program
produced.
A |print| statement can print numbers as well as text, though it always
prints them back in ordinary decimal notation. For example, the program
\beginstt
[ Main;
print "Today's number is ", $3f08, ".^";
];
\endtt
prints up
\begindisplay
Today's number is 16136.\cr
\enddisplay
since 16136 in base 10 is the same number as 3f08 in hexadecimal.
Inform recognises many other notations as ``constants'', that is, values
which are literally described in the source code. A
full list will appear later, but one other is that a single character
between single quotation marks, for instance
\beginstt
'x'
\endtt^^{constant}^^{character (in sense of text)}
is a constant. A ``character'' is a single letter or typewriter-symbol,
and all that the programmer needs to know is that each possible character
has its own numerical value.
\danger For most characters, this numerical value is the standard ASCII
value for the character: for instance, |'x'| has numerical value 120.
(This is true even if Inform is being run on a model of computer which
doesn't normally use the ASCII character set.) Exotic characters such
as |'@ss'| (the Inform notation for German sz) have non-standard codes:
see the {\sl Z-Machine Standards Document} if you really need to know.
Finally, in this initial batch of constant notations, Inform provides
two special constants:
\beginstt
true
false
\endtt
which are used to describe the truth or otherwise of possible conditions.
\danger ^|true| has the numerical value 1; ^|false| has the numerical value 0.
Inform has a concept of ``variable'' like that used in algebra, where it is
easy but limiting to express facts using only numbers:
$$ \eqalign{34 - 34 &= 0\cr
11 - 11 &= 0\cr
694 - 694 &= 0\cr} $$^^{variables (concept of)}
Although suggestive this fails to express the general case: that any number
subtracted from itself leaves zero. We express this fact symbolically
in algebra by writing
$$ x - x = 0 $$
where $x$ is a variable; the implication being ``whatever value $x$ actually
is, the statement is still true".
Likewise, in Inform what seems to be a word of text may be a variable which
represents a number: when the source code is compiled, Inform cannot know
what numerical value this text represents. When the program is run, it
will always have a numerical value at any given time. If |oil_left| is a
variable, the statement
\beginstt
print "There are ", oil_left, " gallons remaining.^";
\endtt
is executed as if |oil_left| were replaced by whatever that value currently
is. Later on, the same statement may be executed again, producing different
text because by that time |oil_left| has a different value.
Inform can only know that text (such as |oil_left|) represents a variable if
the source code has ``declared'' that it does. Each routine can declare
its own selection of variables on its opening line. For example,
in the program
\beginstt
[ Main alpha b;
alpha = 2200;
b = 201;
print "Alpha is ", alpha, " while b is ", b, "^";
];
\endtt^^{local variables}
the |Main| routine has two variables, |alpha| and |b|. Like most names
given in source code (called ``^{identifiers}''), variable names can be at
most 32 characters long and may contain letters of the alphabet, decimal
digits or the underscore |_| character (often used to imitate a space). To
prevent them looking too much like numbers, though, they may not start with a
decimal digit. (So |a44| is legal but |44a| is not.)
For example:
\beginstt
turns_still_to_play
chart45
X
\endtt
are all possible variable names. Inform ignores any difference between
upper and lower case letters in such names, for example considering
|CHArt45| as the same name as |chArT45|.
The |=| sign occurring twice in the above routine is an example of an
``operator'': a notation usually made up of the symbols on the
non-alphabetic keys on a typewriter and which means something is to be done
with the items it is written next to. In this context, |=| means ``set
equal to''. When the statement |alpha = 2200| is executed at run time,
the current value of the variable |alpha| becomes 2200 (and it keeps that
value until another such statement changes it).^^{operators}^^|=|
The variables |alpha| and |b| are called ``local variables'' because they
are local to |Main|: in effect, they are its private property. The program
\beginstt
[ Main alpha;
alpha = 2200;
Rival();
];
[ Rival;
print alpha;
];
\endtt
causes an error on the |print| statement in |Rival|, since |alpha| does not
exist there. Indeed, |Rival| could even have defined a variable of its
own also called |alpha| and this would have been a separate variable with
a probably different value.
\asection{5}{Arithmetic expressions}^^{expressions}%
^^{arithmetic expressions}%
The Inform language is rich with operators, making it concise but not always
very readable. Feeling comfortable with the operators is the main step
towards being able to follow Inform source code. Fortunately, these
operators are based on the usual rules for writing arithmetic formulae,
which gives them a headstart in familiarity.
Indeed, the most commonly used operators are ``arithmetic'': they combine
one or more numbers to give one resulting number. Whenever a number is
expected in a statement, a general ``expression'' can be given instead:
that is, a calculation giving a number as a result. For example, the
statement
\beginstt
seconds = 60*minutes + 3600*hours
\endtt
sets the variable |seconds| equal to 60 times the variable |minutes| plus
3600 times the variable |hours|. White space is not needed between operators
and ``^{operands}'' (the numbers to be operated on): the spaces on either
side of the |+| sign are only provided for legibility.
Ordinary arithmetic is carried out with the operators |+| (plus), |-|
(minus), |*| (times) and |/| (divided by).
Usually dividing one integer by another leaves a remainder: for example,
3 goes into 7 twice, with remainder 1. In Inform notation,
\begindisplay
|7/3| evaluates to 2\cr
|7%3| evaluates to 1\cr
\enddisplay^^{division}^^{remainder}
the |%| operator meaning ``remainder after division'', usually called just
``remainder''. Dividing by zero is impossible and a program which tries to
do this will go wrong.
\danger
As a brief aside, this gives an example of how Inform can and can't help
the programmer to spot mistakes. The program
\beginstt
[ Main;
print 73/0;
];
\endtt
produces an error when compiled:
\beginstt
line 2: Error: Division of constant by zero
> print 73/0;
\endtt^^{division by zero}
since Inform can see that it definitely involves doing something illegal.
However, Inform fails to notice anything amiss with the equivalent program
\beginstt
[ Main x;
x = 0;
print 73/x;
];
\endtt^^{run-time crashes}
and this program compiles correctly. The resulting story file will
``crash'' when it is run, that is, catastrophically halt. The moral is
that just because Inform compiles a program without errors, it does not
follow that the program does what the programmer intends.
\medskip\noindent
In a complicated expression the order in which the operators work may affect
the result. As most human readers would, Inform works out both of
\beginstt
23 + 2 * 700
2 * 700 + 23
\endtt^^{precedence of operators}^^{operator precedence}
to 1423, because the operator |*| has ``precedence'' over |+| and so is
acted on first. Brackets may be used to overcome this:
\beginstt
(23 + 2) * 700
2 * (700 + 23)
\endtt^^{parentheses}^^{brackets (arithmetic)}
evaluate to 17500 and 1446 respectively. Each operator has such a
``precedence level''. When two operators have the same precedence level
(for example, |+| and |-| are of equal precedence) calculation is
(almost always) ``left associative'', that is, carried out left to right:
the notation
\beginstt
a - b - c
\endtt
is equivalent to
\beginstt
(a - b) - c
\endtt
The standard rules for writing mathematics give |+| and |-| equal precedence,
lower than that of |*| and |/| (which are also equal). Inform agrees
and also pegs |%| equal to |*| and |/|.
The final purely arithmetic operator is ``^{unary minus}''. This is written
as a minus sign |-| but is not the same as ordinary subtraction. The
expression:
\beginstt
-credit
\endtt
means the same thing as:
\beginstt
0 - credit
\endtt
The operator |-| is different from all those mentioned so far because it
operates only on one number. It has higher precedence than any of the
five ``binary'' operations above. For example,
\beginstt
-credit - 5
\endtt
means |(-credit) - 5| and not |-(credit - 5)|.
One way to imagine precedence is to think of it as glue attached to the
operator. A higher level means stronger glue. Thus, in
\beginstt
23 + 2 * 700
\endtt^^{glue}
the glue around the |*| is stronger than that around the |+|, so that 2
and 700 belong bound to the |*|.
Some operators do not simply act on values but actually change the current
values of variables: expressions containing these are called
``^{assignments}'' (because they assign values as well as working them out).
One such operator is `set equals':
\beginstt
alpha = 72
\endtt
sets the variable |alpha| equal to 72. Just like |+| and the others, it
also comes up with an answer: as it happens, this value is also 72.
The other two assignment operators are |++| and |--|, which will be
familiar to any C programmer. They are unary operators, and can be used
in any of the following ways:
\beginstt
variable++
++variable
variable--
--variable
\endtt^^|++|^^|--|^^{increment}^^{decrement}
The first of these means ``read off the value of |variable|, and afterwards
increase that value by one''. In |++variable| the ``increment'' (or
increase by 1) happens first, and then the value is read off. |--| acts
in a similar way but ``decrements'' (decreases by 1). These operators
are provided as convenient shorthand forms, since their effect could
usually be achieved in other ways (just using |+| and |-|).
For example, suppose the |variable| has value 12. Then the result would be
12, 13, 12 or 11 respectively; the value left in |variable| afterwards would
be 13, 13, 11 or 11.
Note that expressions like
\beginstt
500++ (4*alpha)-- 34 = beta
\endtt
are meaningless: the values of 500 and 34 cannot be altered, and Inform
knows no way to adjust |alpha| so as to make |4*alpha| decrease by 1.
All three will cause errors.
\danger ``^{Bitwise operators}'' are provided for manipulating binary
numbers on a digit-by-digit basis, something which is often done in programs
which are working with low-level data or data which has to be stored very
compactly. Inform provides |&|, bitwise AND, \BAR, bitwise OR and |~|, bitwise
NOT. For each digit, such an operator works out the value in the answer
from the values in the operands. Bitwise NOT acts on a single operand and
results in the number whose $i$-th binary digit is the opposite of that in
the operand (a 1 for a 0, a 0 for a 1). Bitwise AND (and OR) acts on two numbers
and sets the $i$-th digit to 1 if both operands have (either operand has)
$i$-th digit set. So, for example,
\beginstt
$$10111100 & $$01010001 == $$00010000
\endtt
\danger The remaining operators will be described as needed: the full table
is laid out in \S A1.
\asection{6}{Arguments and Return Values}^^{arguments}^^{return values}%
^^{functions}^^{routines}%
As has already been said, in Inform jargon the word ``function'' is
synonymous with ``routine''. A function might be defined as a
correspondence
$$ (x_1, ..., x_n) \mapsto f(x_1 , ..., x_n ) $$
where a set of input numbers are fed in, and a single value comes out. These
input numbers are called ``arguments''. The value coming out is the
``return value'', or is said to be ``returned''.
All Inform routines are like this. A number of arguments are fed in when the
routine is ``called'' (that is, set running) and there is always a single
numerical result. This result is called the ``return value'' because it is
returned to the rest of the program. Some very simple routines conceal
this. For instance, consider |Sonnet|:
\beginstt
[ Main;
Sonnet();
];
[ Sonnet;
print "When to the sessions of sweet silent thought^";
print "I summon up remembrance of things past^";
];
\endtt
|Sonnet| is a routine which takes as input no arguments at all (it is an
example of the $n=0$ case), so it is called with nothing in between the
round brackets. Although it does return a value (as it happens, this value
is |true|) the statement |Sonnet()| simply calls the routine and throws the
return value away. If |Main| were instead given by
\beginstt
[ Main;
print Sonnet();
];
\endtt
then the output would be
\begindisplay
When to the sessions of sweet silent thought\cr
I summon up remembrance of things past\cr
1\cr
\enddisplay
because the |print| statement in |Main| has been told to print the number
resulting from a call to |Sonnet|.
Thus in Inform there is no such thing as a ``void function'' or
``procedure'': every routine returns a number even though this may
immediately be thrown away as unwanted.
When a routine is called,
\beginstt
Routine(arg1, ...)
\endtt
the arguments given are substituted into the first variables declared for
|Routine|, and execution begins running through |Routine|. Usually, there
can be any number of arguments from none up to 7, though a limit of 3
applies if Inform has been told to compile an early-model story file
(see \S 31 for details).
If execution runs into the |]| end-of-routine marker, so that the routine is
finished without having specified any definite return value, then this value
is |true|. (This is why the printed return value of |Sonnet| is 1: |true|
has the value 1.)
\asection{7}{Example 3: Cubes}^^{cubes of integers}%
A more typical, though less aesthetic, example than |Sonnet|:
\beginstt
[ Main;
print Cube(1), " ";
print Cube(2), " ";
print Cube(3), " ";
print Cube(4), " ";
print Cube(5), "^";
];
[ Cube x;
return x*x*x;
];
\endtt^^{statements: return}
which, when executed, prints
\begindisplay
1 8 27 64 125\cr
\enddisplay
The expression |Cube(3)| is calculated by substituting the number 3 into the
variable |x| when |Cube| is set running: the result of the expression is the
number returned by |Cube|.
Any ``missing arguments'' in a routine call are set equal to zero, so
the call |Cube()| is legal and does the same as |Cube(0)|.
\asection{8}{Conditions: |if|, |true| and |false|}^^{conditions}%
^^|true|^^|false|
Such routines are too simple, so far, even to express many mathematical
functions, and more flexibility will be needed.
A ``control construct'' is a kind of statement which controls whether or not,
and if so how many times or in what order, other statements are executed.
The simplest of these is |if|:
\begindisplay
|if (|\<condition>|) |\<statement>\cr
\enddisplay^^{statements: if}
which executes the \<statement> only if the \<condition>, when it is tested,
turns out to be true. For example, when the statement
\beginstt
if (alpha == 3) print "Hello";
\endtt
is executed, the word ``Hello'' is printed only if the variable |alpha|
currently has value 3. It is important not to confuse the |==| operator
(test whether or not equal to) with the |=| operator (set equal to).
Conditions are always given in (round) brackets. The basic conditions are
as follows:
\smallskip{\ninepoint
\settabs 8 \columns
\+ &|(a == b)| &&& Number |a| equals number |b|\cr
\+ &|(a ~= b)| &&& Number |a| doesn't equal number |b|\cr
\+ &|(a >= b)| &&& |a| is greater than or equal to |b|\cr
\+ &|(a <= b)| &&& |a| is less than or equal to |b|\cr
\+ &|(a > b)| &&& |a| is greater than |b|\cr
\+ &|(a < b)| &&& |a| is less than |b|\cr
\+ &|(o1 in o2)| &&& Object |o1| possessed by |o2|\cr
\+ &|(o1 notin o2)| &&& Object |o1| not possessed by |o2|\cr
\+ &|(o1 has a)| &&& Object |o1| has attribute |a|\cr
\+ &|(o1 hasnt a)| &&& Object |o1| hasn't attribute |a|\cr
\+ &|(o1 provides m)| &&& Object |o1| provides property |m|\cr
\+ &|(o1 ofclass c)| &&& Object |o1| inherits from class |c|\cr
\smallskip}\noindent
(The conditions relating to objects will be discussed later.) A useful
extension to this set is provided by the special operator |or|, which gives
alternative possibilities. For example,
\beginstt
if (alpha == 3 or 4) print "Scott";
if (alpha ~= 5 or 7 or 9) print "Amundsen";
\endtt
where two or more values are given with the word |or| between. |Scott| is
printed if |alpha| has value either 3 or 4, and |Amundsen| if the value of
|alpha| is not 5, is not 7 and is not 9. |or| can be used with any of the
conditions, and any number of alternatives can be given. For example
\beginstt
if (player in Forest or Village or Building) ...
\endtt
often makes code much clearer than writing three separate conditions out; or
\beginstt
if (x > 100 or y) ...
\endtt
can be convenient to check whether |x| is bigger than the minimum of 100
or |y|.
Conditions can also be built up from simpler ones (just as long expressions
are built up from single operators) using the three logical operators |&&|,
\BAR\BAR{} and |~~| (pronounced ``and'', ``or'' and ``not''). For example,
\beginlines
| if (alpha == 1 && (beta > 10 |\BAR\BAR| beta < -10)) print "Lewis";|
| if (~~(alpha > 6)) print "Clark";|
\endlines
``Lewis'' is printed if |alpha| equals 1 and |beta| is outside the range
-10 to 10; ``Clark'' is printed if |alpha| is less than or equal to 6.
The discussion above makes it look as if conditions are special kinds of
expression which can only use certain operators (|==|, |&&|, |or| and so on).
But this is not true: conditions are expressions like any other. It's legal
to write
\beginstt
print (beta == 4);
\endtt^^{conditions as values}
for instance, and this results in 1 being printed if beta equals 4, and 0
otherwise. Thus:
\begindisplay
the result of a true condition is 1;\cr
the result of a false condition is 0.\cr
\enddisplay
This is why |true| and |false| are defined to be 1 and 0 respectively.
Thus one might write code along the lines of
\beginstt
betaisfour = (beta == 4);
...
if (betaisfour == true) ...
\endtt
though it would be easier to write
\beginstt
betaisfour = (beta == 4);
...
if (betaisfour) ...
\endtt
because, just as conditions can be used as numbers, so numbers can be used as
conditions. Zero is considered to be ``false'', and all other values are
considered to be ``true''. Thus
\beginstt
if (1) print "Magellan";
if (0) print "da Gama";
\endtt^^{values as conditions}
always results in ``Magellan'', never ``da Gama'', being printed.
One common use of variables is as ``flags''.
A flag can only hold the value 0 or 1, false or true according to some
state of the program. The fact that a number can be used as a condition
allows natural-looking statements like
\beginstt
if (lower_caves_explored) print "You've already been that way.";
\endtt^^{flag variables}
where |lower_caves_explored| is a variable being used in the program as a
flag.
\danger Note that |&&| and \BAR\BAR{} only work out what they absolutely
need to in order to decide the truth. That is,
\beginstt
if (A && B) ...
\endtt
will work out |A| first. If this is false, there's no need to work out |B|,
and it never is worked out. Only if |A| is true is |B| actually tested.
This only matters when working out conditions like
\beginstt
if (x==7 && Routine(5)) ...
\endtt
where it can be important to know that the |Routine| is never called if |x|
has a value other than 7.
\asection{9}{Example 4: Factorials}^^{factorials}%
The factorial of a positive integer n is defined as the product
$$ 1 \times 2 \times 3 \times ... \times n $$
so that, for example, the factorial of 4 is 24. Here is an Inform routine
to calculate factorials:
\beginstt
[ Main;
print Factorial(7), "^";
];
[ Factorial n;
if (n==1) return 1;
return n*Factorial(n-1);
];
\endtt^^{recursion}
This calculates 7 factorial and comes up with 5040. (Factorials grow rapidly
and 8 factorial is already too large to hold in a standard Inform number,
so calling |Factorial(8)| would give a wrong answer.)
The routine |Factorial| actually calls itself: this is called ``recursion''.
Execution reaches ``seven routines deep'' before starting to return back up.
Each of these copies of |Factorial| runs with its own private copy of the
variable |n|.
Recursion is hazardous. If one calls the routine
\beginstt
[ Disaster;
return Disaster();
];
\endtt
then despite the reassuring presence of the word |return|, execution is tied
up forever, unable to finish evaluating the return value. The first call to
|Disaster| needs to make a second before it can finish; the second needs to
make a third; and so on. This is an example of a programming error which
will prove disastrous when the program is run, yet will cause no errors when
the source code is compiled. (It can be proved that it is impossible to
construct a compiler capable of detecting this general class of mistake.
Inform does not even try.)
\asection{10}{Code blocks, |else| and |switch|}^^{code blocks}%
^^|else|^^|switch|
A feature of all control constructs is that instead of just giving a
\<statement>, one can give a list of statements grouped together into a unit
called a ``code block''. Such a group begins with an open brace |{| and
ends with a close brace |}|. For example,
\beginstt
if (alpha > 5)
{ print "The square of alpha is ";
print alpha*alpha;
print ".^";
}
\endtt
If |alpha| is 3, nothing is printed; if |alpha| is 9,
\begindisplay
The square of alpha is 81.\cr
\enddisplay
is printed. (As usual the layout is a matter of convention: it is usual to
write code blocks on margins indented inwards by some standard number of
characters.) In some ways, code blocks are like routines, and at first it
may seem inconsistent to write routines between |[| and |]| brackets and
code blocks between braces |{| and |}|. However, code blocks cannot have
private variables of their own and do not return values: and it is possible
for execution to break out of code blocks again, or to jump from block to
block, which is impossible with routines.
An |if| statement can optionally have the form
\begindisplay
|if (|\<condition>|) |\<statement1>| else |\<statement2>\cr
\enddisplay^^{statements: if...else...}
in which case \<statement1> is executed if the condition is true, and
\<statement2> if it is false. For example,
\beginstt
if (alpha == 5) print "Five."; else print "Not five.";
\endtt
Note that the condition is only checked once. The statement
\beginstt
if (alpha == 5)
{ print "Five.";
alpha = 10;
}
else print "Not five.";
\endtt
cannot ever print both ``Five'' and then ``Not five''.
The |else| clause has a snag attached: the problem of ``^{hanging elses}''.
\beginstt
if (alpha == 1)
if (beta == 2)
print "Clearly if alpha=1 and beta=2.^";
else
print "Ambiguous.^";
\endtt
is ambiguous as to which |if| statement the |else| attaches to. The answer
(in Inform 6, though this has changed since earlier versions of the language)
is that an |else| always pairs to its nearest |if|, unless there is bracing
to indicate the contrary. Thus the |else| above pairs with the |beta|
condition, not the |alpha| condition.
In any case it is much safer to use braces to express what is meant, as in:
\beginstt
if (alpha == 1)
{ if (beta == 2)
print "Clearly if alpha=1 and beta=2.^";
else
print "Clearly if alpha=1 but beta not 2.^";
}
\endtt
The |if|...|else|... construct is ideal for switching execution between two
possible ``tracks'', like railway signals, but it is a nuisance trying to
divide between many different outcomes this way. To follow the analogy, the
construct |switch| is like a railway turntable.
\beginstt
print "The train on platform 1 is going to ";
switch(DestinationOnPlatform(1))
{ 1: print "Dover Priory.";
2: print "Bristol Parkway.";
3: print "Edinburgh Waverley.";
}
\endtt^^{statements: switch...default...}
Each possible value must be a constant, so
\beginstt
switch(alpha)
{ beta: print "The variables alpha and beta are equal!";
}
\endtt
is illegal.
Any number of outcomes can be specified, and values can be grouped together
to a common outcome. For example,
\beginstt
print "The mission STS-", num, " was flown on the Space Shuttle";
switch(num)
{ 1 to 5, 9: print " Columbia.";
6 to 8: print " Challenger.";
10 to 25: if (num == 12) print " Discovery";
print ", but it was given a flight number like 51-B.";
default: print ".";
}
\endtt
will result in a true statement being printed (as long as |num| is between 1
and, at time of writing, 78), if an incomplete one. The |default| clause is
executed if the original expression matches none of the other values, and it
must always come last if given at all. In this case, it means that if |num|
is 62, then
\begindisplay
The mission STS-62 was flown on the Space Shuttle.\cr
\enddisplay
is printed.
Note that each clause is automatically a code block and needs no braces |{|
to |}| to delimit it from the rest of the routine: this shorthand makes
|switch| statements much more legible.
\asection{11}{|while|, |do|...|until|, |for|, |break|, |continue|}%
^^|while|^^|do|^^|until|^^|for|^^|break|^^|continue|%
The other four Inform control constructs are all ``loops'', that is, ways to
repeat the execution of a given statement (or code block). Discussion of one
of the four, called |objectloop|, is deferred until \S 3.4.
The two basic forms of loop are |while| and |do|...|until|:
\begindisplay
|while (|\<condition>|) |\<statement>\cr
|do |\<statement>| until (|\<condition>|)|\cr
\enddisplay^^{statements: while}^^{statements: do...until...}
The first repeatedly tests the condition and, provided it is still true,
executes the statement. (If the condition is not even true the first time,
the statement is never executed.) For example:
\beginstt
[ SquareRoot n;
x = n;
while (x*x > n) x=x-1;
return x;
];
\endtt
a (fairly chronic) method for finding square roots. (If |SquareRoot(200)|
is called, then |x| runs down through the values 200, 199, ..., 14, at which
point |x*x <= n| since $14\times 14 = 196$.)
The |do|...|until| loop repeats the given statement until the condition
is found to be true. (Even if the condition is already satisfied, like
|(true)|, the statement is always executed the first time through.)
One particular kind of |while| loop is needed so often that there is an
abbreviation for it, called |for|. For example,
\beginstt
counter = 1;
while (counter <= 10)
{ print counter, " ";
counter++;
}
\endtt^^{statements: for}
which produces the output
\begindisplay
1 2 3 4 5 6 7 8 9 10\cr
\enddisplay
(Recall that |counter++| adds 1 to the variable |counter|.) Languages like
BASIC make extensive use of this kind of loop. For example, in BBC BASIC,
the above loop would be written
\beginstt
FOR counter = 1 TO 10
PRINT counter;" ";
NEXT
\endtt
|NEXT| is a word which (slightly clumsily) means ``the code block ends
here'', and is therefore the equivalent of Inform's |}|. The whole is used
to mean ``for values of the counter running through 1 to 10, do...'', hence
the choice of the word |FOR|.
Inform (like the language C) uses a more flexible construct than this, but
which is still called |for|. It can produce any loop in the form
\begindisplay
\<start>\cr
|while (|\<condition>|)|\cr
|{ |...\cr
| |\<update>\cr
|}|\cr
\enddisplay
where \<start> and \<update> are assignments. The notation to achieve this
is
\begindisplay
|for (|\<start>| : |\<condition>| : |\<update>|) |...\cr
\enddisplay
For example, the loop described above is achieved by
\beginstt
for (counter=1 : counter<=10 : counter++)
print counter, " ";
\endtt
Note that if the condition is false even the first time, the loop is never
executed. For instance,
\beginstt
for (counter=1 : counter<0 : counter++)
print "Banana";
\endtt
prints nothing.
\danger
At this point it is worth mentioning that several assignments can be combined
into a single statement in Inform. For example,
\beginstt
i++, score=50, j++
\endtt
(three assignments separated by commas) is a single statement. This is never
useful in ordinary code, where the assignments can be divided up by
semicolons in the usual way. In |for| loops it is useful, though:
\beginstt
for (i=1, j=5: i<=5: i++, j--) print i, " ", j, ", ";
\endtt
produces the output ``1 5, 2 4, 3 3, 4 2, 5 1,''.
\bigskip
Any of the three parts of a |for| statement can be omitted. If the
condition is missed out, it is assumed to be always true, i.e. there is no
check made to see if the loop should be ended and so the loop continues
forever.
On the face of it, the following loops all repeat forever:
\begindisplay
|while (true) |\<statement>\cr
|do |\<statement>| until (false)|\cr
|for (::) |\<statement>\cr
\enddisplay
But there is always an escape. One way is to |return| from
the current routine. Another is to |jump| to a label outside
the loop (|jump| will be covered in \S 1.13 below). It's
neater to use the statement |break|, which causes execution to
``break out of'' the current innermost loop or |switch| statement:
it can be read as ``finish early''. All these ways out are
entirely ``safe'', and there is no harm in leaving a loop only
half-done.
The other simple statement used inside loops is |continue|. This causes
the current iteration to end immediately, but does not end the whole loop.
For example,
\beginstt
for (i=1: i<=5: i++)
{ if (i==3) continue;
print i, " ";
}
\endtt
will output ``1 2 4 5''.
\asection{12}{Example 5: A number puzzle}^^{number puzzle}%
The routine |RunPuzzle| is an interesting example of a loop which, though
apparently simple enough, contains a trap for the unwary.
\beginstt
[ RunPuzzle n count;
do
{ print n, " ";
n = NextNumber(n);
count++;
}
until (n==1);
print "1^(taking ", count, " steps to reach 1)^";
];
[ NextNumber n;
if (n%2 == 0) return n/2; ! If n is even, halve it
return 3*n + 1; ! If n is odd, triple and add 1
];
\endtt
The call |RunPuzzle(10)|, for example, results in the output
\begindisplay
10 5 16 8 4 2 1\cr
(taking 6 steps to reach 1)\cr
\enddisplay
The source code assumes that, no matter what the initial value of |n|, enough
iteration will end up back at 1. If this did not happen, the program would
lock up into an infinite loop, printing numbers forever.
The routine is apparently very simple, so it would seem reasonable that by
thinking carefully enough about it, we ought to be able to decide whether or
not it is ``safe'' to use (i.e., whether it can be guaranteed to finish or
not).
And yet nobody knows whether this routine is ``safe''. The conjecture that
all |n| eventually step down to 1 is at least fifty years old but has never
been proved, having resisted all mathematical attack. (Alarmingly,
|RunPuzzle(27)| takes 111 iterations to fall back down to 1.)
\asection{13}{|quit|, |jump| and the program state}^^|quit|^^|jump|%
There are four statements left which control the flow of execution. |quit|
ends the program immediately (as if a return had taken place from the |Main|
routine). This drastic measure is best reserved for points in the program
which have detected some error condition so awful that there is no point
carrying on. Better yet, do not use it at all.
The |jump| statement transfers execution to some other named place in the
same routine. (Some programming languages call this |goto|. Since it can be
and has been put to ugly uses, the construct itself was at one time frowned
on as a vulgar construct leading programmers into sin. Good use of control
constructs will almost always avoid the need for |jump| and result in more
legible programs. But sin is universal.)
To use |jump| a notation is needed to mark particular places in the source
code. Such markers are called ``labels''. For example:
\beginstt
[ Main i;
i=1;
.Marker;
print "I have now printed this ", i++, " times.^";
jump Marker;
];
\endtt^^{labels (in programs)}^^{statements: jump}^^{statements: quit}
This program has one label, |Marker|. A statement consisting only of a
full stop and then an identifier means ``put a label here and call it
this''.
\ddanger An Inform program has the ability to save a snapshot of its entire
state and to restore back to that previous state. This snapshot includes
values of variables, the point where code is currently being executed, and
so on. Just as we cannot know if the universe is only six thousand years
old, as creationists claim, having been endowed by God with a carefully
faked fossil record; so an Inform program cannot know if it has been
executing all along or if it was only recently restarted. The statements
required are |save| and |restore|:
\begindisplay
|save |\<label>\cr
|restore |\<label>\cr
\enddisplay^^{statements: save}^^{statements: restore}
This is a rare example of an Inform feature which may depend on the host
machine's state of health: for example, if all disc storage is full, then
|save| will fail. It should always be assumed that these statements may well
fail. A |jump| to the label provided occurs if the operation has been a
success. (This is irrelevant in the case of a |restore| since, if all has
gone well, execution is now resuming from the successful branch of the |save|
statement: because that is where execution was when the state was saved.)
\asection{14}{Printing output}^^{printing output}%
When text is printed, normally each character is printed exactly as specified
in the source code. Four characters, however, have special meanings. As
explained above |^| means ``print a new-line''. The character |~|, meaning
``print a quotation mark'', is needed since quotation marks otherwise finish
strings. Thus,
\beginstt
"~Look,~ says Peter. ~Socks can jump.~^Jane agrees."
\endtt
is printed as
\begindisplay
``Look,'' says Peter. ``Socks can jump.''\cr
Jane agrees.\cr
\enddisplay
The third remaining special character is |@|, which is used for accented
characters and other unusual effects, as described below. Finally, |\|
is reserved for ``folding lines'', and used to be needed in Inform 5
when text spilled over more than one line. (It's no longer needed but kept
so that old programs still work.) If you really want to print a |~|, a |^|,
an |@| or a |\|, see below.
Text still spills over more than one line, even in the present golden age
of Inform 6. When a statement like
\beginstt
print "Here in her hairs
the painter plays the spider, and hath woven
a golden mesh t'untrap the hearts of men
faster than gnats in cobwebs";
\endtt^^{`Romeo and Juliet'}^^{William Shakespeare}
is read in by Inform, the line breaks are replaced with a single space each.
Thus the text printed is: ``Here in her hairs the painter plays the spider,
and hath woven a golden mesh...'' and so on. (There is one exception: if a
line finishes with a |^| (new-line) character, then no space is added before
the next line begins.)
\bigskip
So far, only the |print| statement has been used for printing, to print both
numbers and strings (that is, double-quoted pieces of text). Since Inform is
primarily a language for writing Adventure games, its business is text, and
it provides many other facilities for printing.
\begindisplay
|new_line|\cr
\enddisplay^^{statements: new line}
is a statement which simply prints a new-line (otherwise known as a carriage
return, as if the lever on the carriage of an old manual typewriter had been
pulled to move it right back to the left margin and turn it forward one
line). This is equivalent to
\begindisplay
|print "^"|\cr
\enddisplay
but is a convenient abbreviation. Similarly,
\begindisplay
|spaces |\<number>\cr
\enddisplay^^|spaces|^^{statements: spaces}
prints a sequence of that many spaces.
\begindisplay
|inversion|\cr
\enddisplay^^|inversion|^^{statements: inversion}
prints the version number of Inform which was used to compile the program
(it might, for instance, print ``6.01'').
\begindisplay
|box |\<string1> ... \<stringn>\cr
\enddisplay^^|box|^^{statements: box}
displays a reverse-video box in the centre of the screen, containing
\begindisplay
string1\cr
string2\cr
...\cr
stringn\cr
\enddisplay
and is usually used for popping up quotations: for example,
\beginstt
box "Passio domini nostri" "Jesu Christi Secundum" "Joannem"
\endtt
displays
\begindisplay
Passio domini nostri\cr
Jesu Christi Secundum\cr
Joannem\cr
\enddisplay
(the opening line of the libretto to ^{Arvo P\"art}'s `^{St John Passion}').
\medskip\noindent
Text is normally displayed in ordinary (or ``Roman'') type. Its actual
appearance will vary from machine to machine running the program. On many
machines, it will be displayed using a ``font'' which is variably-pitched, so
that for example a ``w'' will be wider on-screen than an ``i''. Such text is
much easier to read, but makes it very difficult to print out diagrams. The
statement
\beginstt
print "+------------+
^+ Hello +
^+------------+^";
\endtt
will print something quite irregular if the characters ``-'', ``+''
and `` '' (space) do not all have the same width. Because one
sometimes does want to print such a diagram (to represent a sketch-map,
say, or to print out a table), the statement |font| is provided:
\beginstt
font on
font off
\endtt^^|font|^^{statements: font}
|font off| switches into a fixed-pitch display style (in which all characters
definitely have the same width); |font on| goes back to the original.
In addition to this, a few textual effects can be achieved.
\beginstt
style roman
\endtt^^|style|
switches to ordinary Roman text (the default), and there are also
\beginstt
style bold
style underline
style reverse
\endtt^^{statements: style}
(|reverse| meaning ``reverse colour'': e.g. yellow on blue if the normal text
appearance is blue on yellow). An attempt will be made to approximate these
effects on any machine, but it may be that |underline| comes out as
italicised text, for example, or that |bold| is rendered by printing ordinary
Roman text but in a different colour.
\medskip\noindent
Inform programs are starting to be written which communicate in languages
other than English: Italian, Dutch, German, French and Spanish games
have all been attempted. A comprehensive range of accented characters is
available: these are reached with the aid of the ^{escape character},
|@|.^^|@|^^{accented characters}%
\medskip\noindent
Most accented characters are written as |@|, followed by an accent marker,
then the letter on which the accent appears:
\smallskip{\ninepoint
\settabs 8 \columns
\+ &|@^| & put a circumflex on the next letter: a,e,i,o,u,A,E,I,O or U\cr
\+ &|@'| & put an acute on the next letter: a,e,i,o,u,y,A,E,I,O,U or Y\cr
\+ &|@`| & put a grave on the next letter: a,e,i,o,u,A,E,I,O or U\cr
\+ &|@:| & put a diaeresis on the next letter: a,e,i,o,u,A,E,I,O or U\cr
\+ &|@c| & put a cedilla on the next letter: c or C\cr
\+ &|@~| & put a tilde on the next letter: a,n,o,A,N or O\cr
\+ &|@\| & put a slash on the next letter: o or O\cr
\+ &|@o| & put a ring on the next letter: a or A\cr
\smallskip}\noindent
In addition, there are a few others:
\smallskip{\ninepoint
\settabs 8 \columns
\+ &|@ss| & German sz\cr
\+ &|@<<| & continental European quotation marks\cr
\+ &|@>>| & \cr
\+ &|@ae| & ligatures\cr
\+ &|@AE| &\cr
\+ &|@oe| &\cr
\+ &|@OE| &\cr
\+ &|@th| & Icelandic accents\cr
\+ &|@et| &\cr
\+ &|@Th| &\cr
\+ &|@Et| & \cr
\+ &|@LL| & pound sign\cr
\+ &|@!!| & Spanish (upside-down) exclamation mark\cr
\+ &|@??| & Spanish (upside-down) question mark\cr
\smallskip}\noindent^^{ligatures}^^{Spanish punctuation}^^{acute accents}
^^{grave accents}^^{diaereses}^^{umlaut accents}^^{circumflex accents}
^^{Icelandic characters}^^{quotation marks (continental European)}
^^{German `sz'}^^{cedilla accents}^^{tilde accents}^^{slash accents}
^^{ring accents}
For instance,
\beginstt
print "Les @oeuvres d'@Aesop en fran@ccais, mon @'el@`eve!";
print "Na@:ive readers of the New Yorker will re@:elect Mr Clinton.";
print "Carl Gau@ss first proved the Fundamental Theorem of Algebra.";
\endtt^^{William J. Clinton}^^{AEsop}
Accented characters can also be referred to as constants, like other
characters. Just as |'x'| represents the character lower-case-X, so
|'@^A'| represents capital-A-circumflex.
\danger
The |@| escape character has two other uses. One gets around the problem
that, so far, it is impossible to print an ``|@|". A double |@| sign,
followed by a number, prints the character with this numerical code.
The most useful cases are:
\smallskip{\ninepoint
\settabs 8 \columns
\+ &|@@92| & comes out as ``|\|''\cr
\+ &|@@64| & comes out as ``|@|''\cr
\+ &|@@94| & comes out as ``|^|''\cr
\+ &|@@126|& comes out as ``|~|''\cr
\smallskip}\ninepoint\noindent%
enabling us to print the four characters which can't be typed directly
because they have other meanings.\tenpoint\medskip
\ddanger The second use is more obscure. Inform keeps a stock of 32
pseudo-variables to hold text, numbered from 0 to 31.
\smallskip{\ninepoint
\settabs 8 \columns
\+ &|@00| & prints out as the current contents of string 0\cr
\+ &... & ...\cr
\+ &|@31| & prints out as the current contents of string 31\cr
\smallskip}\ninepoint\noindent%
and these variables are set with the |string| statement:
\beginstt
string 0 "toadstool";
\endtt
sets string 0 to the text of the word ``toadstool''. (There is a technical
reason why these strings cannot be set equal to any text: only to literal
text, as in the above example, or to strings previously declared using the
|Low_string| directive.)\tenpoint\medskip
Finally, it is time to discuss |print|. There are two forms, |print|
and |print_ret|. The only difference is that the second prints out an
extra new-line character and returns from the current routine with the value
|true|. Thus, |print_ret| should be read as ``print and then return'', and
\beginstt
print_ret "That's enough of that.";
\endtt^^{statements: print}
is equivalent to
\beginstt
print "That's enough of that.^"; rtrue;
\endtt
In fact, as an abbreviation, it can even be shortened to:
\beginstt
"That's enough of that.";
\endtt
Although Inform newcomers are often confused by the fact that this
apparently innocent statement actually causes a return from the current
routine, it's an abbreviation which very much pays off in adventure-writing
situations. Note that if the program:
\beginstt
[ Main;
"Hello, and now for a number...";
print 45*764;
];
\endtt
is compiled, Inform will produce the warning message:
\beginstt
line 3: Warning: This statement can never be reached.
> print 45*764;
\endtt^^{reached, statement which cannot be}%
^^{statement cannot be reached}
because the bare string on line 2 is printed using |print_ret|: so the
text is printed, then a new-line is printed, and then a |return| takes
place immediately. As the warning message indicates, there is no
way the statement on line 3 can ever be executed.
So what can be printed? The answer is a list of terms, separated by commas.
For example,
\beginstt
print "The value is ", value, ".";
\endtt
contains three terms. A term can take the following forms:
\smallskip{\ninepoint
\settabs 8 \columns
\+ &\<a numerical quantity> &&& printed as a (signed, decimal) number\cr
\+ &\<text in double-quotes> &&& printed as text\cr
\+ &|(|\<rule>|) |\<quantity> &&& printed according to some special rule\cr
\smallskip}\noindent
Inform provides a stock of special printing rules built-in, and also allows
the programmer to create new ones. The most important rules are:
\smallskip{\ninepoint
\settabs 8 \columns
\+ &|(char)| & print out the character which this is the numerical code for\cr
\+ &|(string)| & print this string out\cr
\+ &|(address)| & print out the text at this array address\cr
\+ & & (this is seldom used, and then mainly to print the\cr
\+ & & text of a word entry in a game's dictionary)\cr
\smallskip}\noindent^^{printing rules}^^|(char)|^^|(address)|
\danger |print (string) ...| requires a little explanation.
\beginstt
x = "Hello!";
print (string) x;
\endtt^^|(string)|
prints out ``Hello!'', whereas
\beginstt
x = "Hello!";
print x;
\endtt
prints a mysterious number. This is because strings are
internally represented by numbers (just as everything else is).
The remaining stock of rules is provided for use in conjunction
with the Library and is documented in Chapter V: briefly,
\smallskip{\ninepoint
\settabs 8 \columns
\+ &|(the)| & print definite article then name of this object\cr
\+ &|(The)| & ditto, but capitalised\cr
\+ &|(name)| & ditto, but with no article\cr
\+ &|(a)| & ditto, but with the indefinite article\cr
\+ &|(number)| & print this number out in English\cr
\+ &|(property)| & (for debugging) print the name of this property\cr
\+ &|(object)| & (ditto) print the hardware-name of this object\cr
\smallskip}\noindent^^{case sensitivity}
Note that |(the)| in lower case does something different from |(The)|
with an upper case T. This is very unusual! (Directive names, which will
turn up in \S 2, variable names and so on are allowed to use upper
case and the case is simply ignored, so that |fRoG| means the same
as |frog|. But statement keywords, like |print| or |(name)|, have
to be in lower case -- except for |(The)|.)
To create a new rule, provide a routine with this name, and use the
rule-name in brackets.
\asection{15}{Example 6: Printing in hexadecimal}%
^^{printing hexadecimal numbers}^^{hexadecimal, printing out}%
The following pair of routines provides for printing out a number as a
four-digit, unsigned hexadecimal number. For example, so that
\beginstt
print (hex) 16339;
\endtt
prints ``3fd3''.
\beginstt
[ hex x y;
y = (x & $ff00) / $100;
x = x & $ff;
print (hdigit) y/$10, (hdigit) y, (hdigit) x/$10, (hdigit) x;
];
[ hdigit x;
x = x % $10;
if (x<10) print x; else print (char) 'a'+x-10;
];
\endtt
Once these routines have been defined, |hex| and |hdigit| are available
anywhere in the same program for use as new printing rules.
\asection{16}{Built-in functions 1: |random| and |indirect|}%
^^{functions, built-in}^^{built-in functions}
Inform provides a small stock of functions ready-defined, but which are used
much as other functions are. All but two of these concern objects and will
be left until chapter 3.
\medskip\noindent^|random| has two forms:
\begindisplay
|random(N)|\cr
\enddisplay^^{functions: random}
returns a uniformly random number in the range $1, 2, ..., N$. $N$ should always
be a positive number (between 1 and 32767) for this to work properly.
\begindisplay
|random(|two or more constant quantities, separated by commas|)|\cr
\enddisplay
returns a uniformly random choice from this selection. Thus,
\beginstt
print (string) random("red", "blue", "green", "purple", "orange");
\endtt
randomly prints the name of one of these five colours (each being equally
likely to appear). Likewise,
\beginstt
print random(13, 17);
\endtt
has a 50\% chance of printing 13, and a 50\% chance of printing 17.
\ddanger The other built-in function discussed here is ^|indirect|.
\beginstt
indirect(function, arg1, arg2, ...)
\endtt^^{functions: indirect}
calls the given function with given arguments. Thus, this is equivalent to
\beginstt
function(arg1, arg2, ...)
\endtt
but has the additional virtue that the function can be given, not just as
a literal function name, but as some calculated value:
\beginstt
indirect(random(OneRoutine, OtherRoutine), 45);
\endtt
has a 50\% chance of calling |OneRoutine(45)|, and a 50\% chance of calling
|OtherRoutine(45)|. |indirect| should be used with caution: if supplied with
a numerical first argument which doesn't correspond to any function in the
program, the program may resoundingly crash. In any event, it is often
best to achieve such effects using messages to objects.
\asection{17}{Accepting input}^^{keyboard input (direct access to)}%
\ddanger
Inform programmers seldom need to take input from the keyboard, in practice,
since in all game situations the Library's parser routines take care of all
that. However, for completeness this section covers the |read| statement
which is the main route by which keyboard input is taken. It will not make
much sense to readers who have not yet read the rest of this book.
\ninepoint
The syntax is
\begindisplay
|read |\<text array> \<parse buffer> \<routine>\cr
\enddisplay^^|read|^^{statements: read}
where the \<routine> is optional: if provided, it is called just before the
input takes place so that the screen's top line or lines of data
(the ``status line'' present in many games) can be renewed.
What the statement does is to read in a single line of text (waiting until
the user has finished typing a line and then pressed RETURN), copy this text
into the text array and then try to comprehend it, writing the results of
this comprehension exercise (``parsing'') into the parse buffer.
Before the statement is reached, the program should have entered the maximum
number of characters which can be accepted (say, 60) into the 0th entry of
the text array; the statement will then write the actual number typed into
the 1st entry, and the characters themselves into entries 2 and onward.
Thus,
\beginstt
text_array -> 0 = 60;
read text_array 0;
for (n = 0: n< text_array->1: n++) print (char) text_array->(n+2);
new_line;
\endtt
will read in a line of up to 60 characters, and then print it back again.
(The array |text_array| must have been created first, and so must the
local variable |n|, of course.)
Note that in this case, no ``parse buffer'' has been given (0 was given in
its place). If, instead of 0, an array is given here, then the |read|
statement makes an attempt to divide up the input text into individual
words, and to match these words against the game's dictionary. See \S 2.5
for details.
\tenpoint
\section{2}{The language of data structures}
\def\bsection#1#2{\bigbreak\noindent{\bf \S 2.#1\quad #2}\medskip\noindent}
\bsection{1}{Directives and constants}^^{data structures}^^{structures of data}%
Every example program so far has consisted only of a sequence of
routines, each within beginning and end markers |[| and |]|. Such routines
have no way of communicating with each other, and therefore of sharing
information with each other, except by making function calls back and forth.
This arrangement is not really suited to a large program whose task may be
to simulate something complicated (such as the world of an adventure game):
it would be useful to have some kind of central registry of information
which all routines have access to, as and when needed.
Information available to all routines in this way is said to be ``global'',
rather than ``local'' to any one routine. (As will appear in \S 3, there is
also an intermediate possibility where information is available only to a
cluster of routines working on roughly the same part of a program.)
This global information can be organised in a variety of ways. Such organised
groups are called ``data structures''. For example, a typical data structure
might be a list of 10 values. The term ``data structure'' did not appear in
\S 1 because information was only ever held in variables, the simplest possible
kind of structure (one value on its own).
Data structures are added to Inform programs using commands called ``directives''
in between definitions of routines. It's important to distinguish between
these, which direct Inform to do something now (usually, to create something)
and the statements which occur inside routines, which are merely translated in
some way but not acted on until the program has finished being compiled and is
run.
In fact, one directive has already appeared: the one written |[|, which means
``translate the following routine up to the next |]|''. In all there are
38 Inform directives, as follows:
\beginstt
Abbreviate Array Attribute Class Constant Default
Dictionary End Endif Extend Fake_action Global
Ifdef Ifndef Ifnot Ifv3 Ifv5 Iftrue
Iffalse Import Include Link Lowstring Message
Nearby Object Property Release Replace Serial
Switches Statusline Stub System_file Trace Verb
Version [
\endtt^^{directives}
Several of these are rather technical and will not be used by many
programmers (such as |Trace|, |Stub|, |Default|, |System_file|, |Abbreviate|,
|Dictionary|). Others control fine points of what is compiled and what isn't
(|Ifdef|, |Ifnot|, and so on; |Message|, |Replace|). These not-very important
directives are covered in Chapter II.
This leaves 9 central directives for ^{creating data structures}, and these are
the ones which it is important to know about:
\beginstt
Array Attribute Class Constant Extend Global
Object Property Verb
\endtt
It is conventional to write these with the initial letter capitalised: this
makes directives look unlike statements. |Attribute|, |Class|, |Object| and
|Property| are the subject of \S 3.
\medskip\noindent
The simplest directive with a ``global'' effect on the program -- an effect
all over the program, that is, not just in one routine -- is |Constant|.
The following program, an unsatisfying game of chance, shows a typical use
of |Constant|.
\beginstt
Constant MAXIMUM_SCORE = 100;
[ Main;
print "You have scored ", random(MAXIMUM_SCORE),
" points out of ", MAXIMUM_SCORE, ".^";
];
\endtt^^|Constant|^^{defined constants}^^{directives: Constant}
The maximum score value is used twice in the routine |Main|. Of course the
program is the same as it would have been if the constant definition were not
present, and |MAXIMUM_SCORE| were replaced by 100 in both places where it
occurs. The advantage of using |Constant| is that it makes it possible to
change this value from 100 to, say, 50 with only a single change, and it
makes the source code more legible to the reader by explaining what the
significance of the number 100 is supposed to be.
If no value is specified for a constant, as in the line
\beginstt
Constant DEBUG;
\endtt
then the constant is created with value 0.
\bsection{2}{Global variables}%
As commented above, so far the only variables allowed have been ``local
variables'', each private to their own routines. A ``global variable'' is a
variable which is accessible to all code in every routine. Once a global
variable has been declared, it is used in just the same way as a local
variable. The directive for declaring a global variable is |Global|:
\beginstt
Global score = 36;
\endtt^^{directives: Global}
This creates a variable called |score|, which at the start of the program has
the value 36. |score| can be altered or used anywhere in the program after
the line on which it is defined.
\bsection{3}{Arrays}^^{arrays}^^{indexed variables}%
An ``array'' is an indexed collection of (global) variables, holding a set of
numbers organised into a sequence. It allows general rules to be given for
how a group of variables should be treated. For instance, the directive
\beginstt
Array pack_of_cards --> 52;
\endtt^^{directives: Array}
creates a stock of 52 variables, referred to in the program as
\beginstt
pack_of_cards-->0 pack_of_cards-->1 ... pack_of_cards-->51
\endtt
There are two basic kinds of array: ``^{word arrays}'' (written using ^|-->| as
above) and ``^{byte arrays}'' (written using |->| similarly). Whereas the
entries of a word array can hold any number, the entries of a byte array can
only be numbers in the range 0 to 255 inclusive. (The only advantage of this is
that it is more economical on memory, and beginners are advised to use word
arrays instead.)
In addition to this, Inform provides arrays which have a little extra
structure: they are created with the 0th entry holding the number of entries.
A word array with this property is called a ^|table|; a byte array with this
property is a ^|string|.
For example, the array defined by
\beginstt
Array continents table 5;
\endtt
has six entries: |continents-->0|, which holds the number 5, and five more
entries, indexed 1 to 5. (The program is free to change |continents-->0|
later but this will not change the size: the size of an array can never change.)
As an example of using |string| arrays:
\beginstt
Array password string "DANGER";
Array phone_number string "1978-345-2160";
...
PrintString(password);
...
PrintString(phone_number);
...
[ PrintString the_array i;
for (i=1: i<=the_array->0: i++)
print (char) the_array->i;
];
\endtt
The advantage of |string| arrays, then, is that one can write a general routine
like |PrintString| which works for arrays of any size.
To recapitulate, Inform provides four kinds of array in all:
\beginstt
--> -> table string
\endtt
There are also four different ways to set up an array with its initial contents
(so the directive can take 16 forms in all). In all of the examples above,
the array entries will all contain 0 when the program begins.
Instead, we can give a list of constant values. For example,
\beginstt
Array primes --> 2 3 5 7 11 13;
\endtt^^{small prime numbers}
is a word array created with six entries, |primes-->0| to |primes-->5|,
initially holding the values 2 to 13.
The third way to create an array gives some text as an initial value (because
one common use for arrays is as ``^{strings of characters}'' or
``^{text buffers}''). The two string arrays above were set up this way.
As another example,
\beginstt
Array players_name -> "Frank Booth";
\endtt^^{Frank Booth}
sets up the byte array |players_name| as if the directive had been
\beginstt
Array players_name -> 'F' 'r' 'a' 'n' 'k' ' ' 'B' 'o' 'o' 't' 'h';
\endtt
\ddanger The fourth way to create an array is obsolete and is kept
only so that old programs still work. This is to give a list of values in
between end-markers |[| and |]|, separated by commas or semi-colons. Please
don't use this any longer.
\warning
It is up to the programmer to see that no attempt is made
to read or write non-existent entries of an array. (For instance,
|pack_of_cards-->1000|.) Such mistakes are notorious for causing programs
to fail in unpredictable ways, difficult to diagnose. Here for example is
an erroneous program:
\beginstt
Array ten --> 10;
Array fives --> 5 10 15 20 25;
[ Main n;
for (n=1: n<=10: n++) ten-->n = -1;
print fives-->0, "^";
];
\endtt
This program ought to print 5 (since that's the $0$-th entry in the array
|fives|), but in fact it prints $-1$. The problem is that the entries of |ten|
are |ten-->0| up to |ten-->9|, not (as the program implicitly assumes)
|ten-->1| to |ten-->10|. So the value $-1$ was written to |ten-->10|, an entry
which does not exist. At this point anything could have happened. As it
turned out, the value was written into the initial entry of the next array
along, ``corrupting'' the data there.^^{array bounds}^^{bounds of arrays}
\bsection{4}{Example 7: Shuffling a pack of cards}^^{shuffling a pack of cards}%
This program simulates the shuffling of a pack of playing cards.
The cards are represented by numbers in the range 0 (the ^{Ace of Hearts}) to 51
(the ^{King of Spades}). The pack itself has 52 positions, from position 0 (on
the top) to position 51 (on the bottom). It is therefore represented by the
array
\beginstt
pack_of_cards-->i
\endtt^^{pack of cards, shuffling}
whose |i|-th entry is the card number at position |i|. A new pack as produced
by the factory, still in order, would therefore be represented with card |i| in
position |i|: the pack would have the Ace of Hearts on top and the King of
Spades on the bottom.
\pageinsert
\centerline{\bf Example 7: Shuffling a pack of cards}
\beginstt
Constant SHUFFLES = 100;
Array pack_of_cards --> 52;
[ ExchangeTwo x y z;
! Initially x and y are both zero
while (x==y)
{ x = random(52) - 1; y = random(52) - 1;
}
! x and y are now randomly selected, different numbers
! in the range 0 to 51
z = pack_of_cards-->x;
pack_of_cards-->x = pack_of_cards-->y;
pack_of_cards-->y = z;
];
[ Card n;
switch(n%13)
{ 0: print "Ace";
1 to 9: print n%13 + 1;
10: print "Jack";
11: print "Queen";
12: print "King";
}
print " of ";
switch(n/13)
{ 0: print "Hearts";
1: print "Clubs";
2: print "Diamonds";
3: print "Spades";
}
];
[ Main i;
! Create the pack in "factory order":
for (i=0:i<52:i++) pack_of_cards-->i = i;
! Exchange random pairs of cards for a while:
for (i=0:i<SHUFFLES:i++) ExchangeTwo();
print "The pack has been shuffled to contain:^";
for (i=0:i<52:i++)
print (Card) pack_of_cards-->i, "^";
];
\endtt^^{exchanges of cards}
Note the use of a ``printing rule'' called |Card| to describe card number |i|.
Note also that 100 exchanges of pairs of cards is only just enough to make
the pack appear well shuffled. Redefining |SHUFFLES| as 10000 makes the
program take longer; redefining it as 10 makes the result very suspect.
\vfill
\endinsert
\danger The example code shuffles the pack in a simple way, but
there are more efficient methods. Here's one supplied
by ^{Dylan Thurston}, giving perfect randomness in 51 exchanges.
\beginstt
pack_of_cards-->0 = 0;
for (i=1:i<52:i++)
{ j = random(i+1) - 1;
pack_of_cards-->i = pack_of_cards-->j; pack_of_cards-->j = i;
}
\endtt
\bsection{5}{Seven special data structures}%
^^{dictionary, as a data structure}%
\danger All Inform programs automatically contain seven special
data structures, each being one of a kind: the object tree, the grammar,
the table of actions, the release number, the serial code,
the ``statusline flag'' and the dictionary. These data structures are
tailor-made for adventure games and (except for the object tree) can
be ignored for every other kind of program. So they are mostly covered in
Book Two.
\ninepoint\medskip\noindent
\item{1.}For the object tree (and the directives |Object| and |Class|),
see \S 3.
\item{2.}For grammar (and the directives |Verb| and |Extend|), see Chapter V,
\S\S 26 and 27.
\item{3.}For actions (and the |<...>| and |<<...>>| statements and the |##|
constant notation), see Chapter III, \S 9.
\item{4.}The release number (which is printed automatically by the
library in an Inform-written adventure game) is 1 unless otherwise specified.
The directive
\beginstt
Release <number>;
\endtt^^{directives: Release}
\item{}does this. Conventionally release 1 would be the first
published copy, and releases 2, 3, ... would be amended re-releases.
See Chapter III, \S 7, for an example.
\item{5.}The serial number is set automatically to the date of compilation
in the form 960822 (``22nd August 1996''). This can be overridden if desired
with the directive
\beginstt
Serial "dddddd";
\endtt^^{directives: Serial}
\item{}where the text must be a string of 6 digits.
\item{6.}The ``status line flag'' chooses between styles of ``status line''
at the top of an adventure game's screen display. See Chapter IV, \S 18,
for use of the |Statusline| directive.
\item{7.}The dictionary is automatically built by Inform. It is a stock
of all the English words which the game might want to recognise from what
the player has typed: it includes any words written in constants like
|'duckling'|, as well as any words given in |name| values or in grammar.
For example
\beginstt
if (first_word == 'herring') print "You typed the word herring!";
\endtt
\item{}is a legal statement. Inform notices that |herring| -- because it is in
single quotes -- is a word the program may one day need to be able to
recognise, so it adds the word to the dictionary.
Note that the constant |'herring'| is a dictionary word but the constant |'h'|
is the ASCII value of lower-case H. (Single-letter dictionary words are seldom
needed, but can be written using an ugly syntax if need be: |#n$h| is the
constant meaning ``the dictionary word consisting only of the letter H''.)
\ddanger
From this description, the dictionary appears to be something into which
words are poured, never to re-emerge. The benefit is felt when the |read|
statement comes to try to parse some input text:
\beginstt
read text_array parse_buffer;
\endtt^^{statements: read}
It must be emphasized that the |read| statement performs only the simplest
possible form of parsing, and should not be confused with the very much more
elaborate parser included in the Inform library.
What it does is to break down the line of input text into a sequence of
words, in which commas and full stops count as separate words in their own
right. (An example is given in Chapter V, \S 24.) Before using ^|read|,
the entry
\beginstt
parse_buffer->0
\endtt
should be set to the maximum number of words which parsing is wanted for.
(Any further words will be ignored.) The number of words actually parsed
from the text is written in
\beginstt
parse_buffer->1
\endtt
and a block of data is written into the array for each of these words:
\beginstt
parse_buffer-->(n*2 - 1)
\endtt
holds the dictionary value of the |n|-th word (if |n| counts 1, 2, 3, ...). If
the word isn't in the dictionary, this value is zero.
(In addition,
\beginstt
parse_buffer->(n*4)
parse_buffer->(n*4 + 1)
\endtt
are set to the number of letters in word |n|, and the offset of word |n| in the
text array.)
For example,
\beginstt
[ PleaseTypeYesOrNo i;
for (::)
{ buffer->0 = 60;
parse->0 = 1;
print "Please type ~yes~ or ~no~> ";
read buffer parse;
if (parse-->1 == 'yes') rtrue;
if (parse-->1 == 'no') rfalse;
}
];
\endtt^^{yes or no questions, primitive routine to ask}
\tenpoint
\newpage
\section{3}{The language of objects}
\quote
Objects make up the substance of the world. That is why
they cannot be composite.
\poemby{Ludwig Wittgenstein ({\oldstyle1889}--{\oldstyle1951})}{Tractatus}
\def\csection#1#2{\bigbreak\noindent{\bf \S 3.#1\quad #2}\medskip\noindent}
\csection{1}{Objects and communication}^^{objects}
The objects in a program are its constituent parts: little lumps of code
and data. The starting point of an ``object-oriented language'' is that
it's good design to tie up pieces of information in bundles with the pieces
of program which deal with them. But the idea goes further:
\medskip\par\noindent
\item{1.}{An object is something you can communicate with. (It's like a
company where many people work in the same building, sharing the same
address: to the outside world it behaves like a single person.)}
\item{2.}{Information inside the object can be kept concealed from the
outside world (like a company's confidential files). This is sometimes
called ``^{encapsulation}''.}
\item{3.}{The outside world can only ask the object to do something, and
has no business knowing how it will be done. (The company might decide to change
its stock-control system one day, but the outside world should never even
notice that this has happened, even though internally it's a dramatic shift.)}
\medskip\noindent All three principles have been seen already for routines:
(1) you can call a routine, but you can't call ``only this part of a routine'';
(2) the local variables of a routine are its own private property, and the
rest of the program can't find out or alter their values; (3) as long as the
routine still accomplishes the same task, it can be rewritten entirely and the
rest of the program will carry on working as if no change had been made.
Why bother with all this? There are two answers. First and foremost,
Inform was designed to make adventure games, where objects are the right
idea for representing items and places in the game. Secondly, the `object'
approach makes sense as a way of organising any large, complicated
program.^^{object orientation: virtue of}
\par
The other key idea is communication. One can visualise the program as being
a large group of companies, constantly writing letters to each other to
request information or ask for things to be done. In a typical ``^{message}'',
one object $A$ sends a detailed question or instruction to another object $B$,
which replies with a simple answer. (Again, we've seen this already for
routines: one routine calls another, and the other sends back a return value.)
\bigskip\noindent
Routines are only one of the four basic kinds of Inform object, which are:
\medskip^^{objects: the four kinds of}%
\item{}routines, declared using |[|...|]|;
\item{}strings in double-quotes |"like so"|;
\item{}collections of routines and global variables, declared using |Object|;
\item{}prototypes for such collections, called ``classes'' and declared using
|Class|.
\medskip\noindent^^{metaclass, definition of}^^{class, definition of}
These four kinds are called ``metaclasses''. If |O| is an object, then the
function
\beginstt
metaclass(O)
\endtt
will always tell you what kind it is, which will be one of the four values
\beginstt
Routine String Object Class
\endtt^^|metaclass|^^|Routine|^^|String|^^|Object|^^|Class|
For example,
\beginstt
metaclass("Violin Concerto no. 1")
\endtt
evaluates to |String|, whereas
\beginstt
metaclass(Main)
\endtt^^{objects: metaclass of}
should always be |Routine| (since |Main| should always be the name of the
routine where an Inform program begins to run). From \S 1 we already know
about metaclasses |Routine| and |String|, so it's the other two cases which
this section will concentrate on.
\ddanger Why only these four kinds? Why are strings objects, and not (say)
variables or dictionary words? Object-oriented
languages vary greatly in to what extreme they take the notion of object: in
the dogmatic ^{Smalltalk-80}, every ingredient of any kind in a program
is called an object: the program itself, the number 17, each variable and
so on. Inform is much more moderate. Routines, |Object|s and classes
are genuinely object-like, and it just so happens that it's convenient to
treat strings as objects (as we shall see). But Inform stops there.
\csection{2}{Built-in functions 2: the object tree}^^{object tree}%
Routines, strings and (as we shall see) classes are scattered about in an
Inform program, in no particular order, and nothing links them together.
|Object| objects are special in that they are joined up in the ``object tree''
which grows through every Inform program.
In this tree, objects have a kind of family relationship to each other: each
one has a parent, a child and a sibling. (The analogy here is with family
trees.) Normally such a relation is another object in the tree, but instead
it can be
\beginstt
nothing
\endtt^^|nothing|
which means ``no object at all''. For example, consider the tree:
\beginstt
Meadow
!
Mailbox -> Player
! !
Note Sceptre -> Cucumber -> Torch -> Magic Rod
!
Battery
\endtt^^{meadow example}
The |Mailbox| and |Player| are both children of the |Meadow|, which is their
parent, but only the |Mailbox| is {\sl the} child of the |Meadow|.
The |Magic Rod| is the sibling of the |Torch|, which is the sibling of the
|Cucumber|, and so on.
\medskip\noindent
Inform provides special functions for reading off positions in the tree:
^|parent|, ^|sibling| and ^|child| all do the obvious things, and in addition
there's a function called ^|children| which counts up how many children an
object has (where grandchildren don't count as children). For instance,
\beginstt
parent ( Mailbox ) == Meadow
children ( Player ) == 4
child ( Player ) == Sceptre
child ( Sceptre ) == nothing
sibling ( Torch ) == Magic Rod
\endtt^^{functions: parent}^^{functions: children}^^{functions: child}
^^{functions: sibling}^^{objects: child, sibling and parent of}
It is a bad idea to apply these functions to the value |nothing| (since it is
not an object, but a value representing the absence of one). One can detect
whether a quantity is a genuine object or not using |metaclass|, for
\beginstt
metaclass(X)
\endtt^^{functions: metaclass}
is |nothing| for any value |X| which isn't an object: in particular,
\beginstt
metaclass(nothing) == nothing
\endtt
\danger Hopefully it's clear why the tree is useful for writing adventure
games: it provides a way to simulate the vital idea of one thing being
contained inside another. But even in non-adventure game programs it can
be a convenience. For instance, it is an efficient way to hold
tree structures and linked lists of information.
\csection{3}{Creating objects 1: setting up the tree}%
The object tree's initial state is created with the directive |Object|. For
example,
\beginstt
Object "bucket" ...
Object -> "starfish" ...
Object -> "oyster" ...
Object -> -> "pearl" ...
Object -> "sand" ...
\endtt^^{directives: Object}^^{object tree: setting up initial state}
(where the bulk of the definitions are here abbreviated to ``|...|''),
sets up the tree structure
\beginstt
"bucket"
!
"starfish" --> "oyster" --> "sand"
!
"pearl"
\endtt
The idea is that if no arrows |->| are given in the |Object| definition, then
the object has no parent: if one |->| is given, then the object is a child of
the last object to be defined with no arrows; if two are given, then it's a
child of the last object defined with only one arrow; and so on. (The list
of definitions looks a little like the tree picture turned on its side.)
An object definition consists of a ``head'' followed by a ``body'', which is
itself divided into ``segments'' (though there the similarity with caterpillars
ends). The head takes the form:
\begindisplay
|Object |\<arrows> \<name> |"textual name"| \<parent>\cr
\enddisplay
but all of these four entries are optional.
\item{1.}The \<arrows> are as described above. Note that if one or more
arrows are given, that automatically specifies what object this is the child
of, so a \<parent> cannot be given as well.
\item{2.}The \<name> is what the object can be called inside the program;
it's analogous to a variable name.
\item{3.}The |"textual name"| can be given if the object's name ever needs
to be printed by the program when it is running.
\item{4.}The \<parent> is an object which this new object is to be a child
of. (This is an alternative to supplying arrows.)
\medskip\par\noindent
So much is optional that even the bare directive
\beginstt
Object;
\endtt
is allowed, though it makes a nameless and featureless object
which is unlikely to be useful.
\csection{4}{Statements for objects: move, remove, objectloop}%
The positions of objects in the tree are by no means fixed: they are created
in a particular formation but are often shuffled around extensively during
the program's execution. (In an adventure game, where the objects represent
items and rooms, objects are moved in the tree whenever the player picks
something up or moves around.) The statement
\begindisplay
|move |\<object>| to |\<object>\cr
\enddisplay^^{statements: move}
moves the first-named object to become a child of the second-named one. All
of the first object's own children ``move along with it'', i.e., remain its own
children. For instance, following the example in \S 3.2 above,
\beginstt
move Cucumber to Mailbox;
\endtt^^{objects: moving around the tree}
results in the tree
\beginstt
Meadow
!
Mailbox -----------> Player
! !
Cucumber -> Note Sceptre -> Torch -> Magic Rod
!
Battery
\endtt
It must be emphasized that |move| prints nothing on the screen, and indeed
does nothing at all except to rearrange the tree. When an object becomes the
child of another in this way, it always becomes the ``eldest'' child in the
family-tree sense; that is, it is the new |child()| of its parent, pushing
the previous children over into being its siblings.
It is, however, illegal to move an object out of such a structure using
\beginstt
move Torch to nothing;
\endtt
because |nothing| is not an object as such. The effect is instead achieved with
\beginstt
remove Torch;
\endtt^^{statements: remove}^^{objects: removing from tree}
which would now result in
\beginstt
Meadow Torch
! !
Mailbox -----------> Player Battery
! !
Cucumber -> Note Sceptre -> Magic Rod
\endtt
So the ``object tree'' is often fragmented into many little trees.
\bigskip\noindent
Since objects move around a good deal, it's useful to be able to test where
an object currently is; the condition |in| is provided for this. For
example,
\beginstt
Cucumber in Mailbox
\endtt
is true if and only if the |Cucumber| is one of the {\sl direct} children
of the |Mailbox|. (|Cucumber in Mailbox| is true, but |Cucumber in Meadow|
is false.) Note that
\beginstt
X in Y
\endtt
is only an abbreviation for
\beginstt
parent(X) == Y
\endtt
but it's worth having since it occurs so often.
\medskip\noindent
The one loop statement missed out in \S 1 was |objectloop|.
\begindisplay
|objectloop(|\<variable-name>|) |\<statement>\cr
\enddisplay
runs through the \<statement> once for each object in the tree, putting each
object in turn into the variable. For example,
\beginstt
objectloop(x) print (name) x, "^";
\endtt^^{statements: objectloop}
prints out a list of the textual names of every object in the tree. (Objects
which aren't given any textual names in their descriptions come out as ``?''.)
More powerfully, any condition can be written in the brackets, as long as
it begins with a variable name.
\beginstt
objectloop(x in Mailbox) print (name) x, "^";
\endtt
prints the names only of those objects which are direct children of the
|Mailbox| object.
\csection{5}{Creating objects 2: |with| properties}%
So far |Object|s are just tokens with names attached which can be shuffled
around in a tree. They become interesting when data and routines are
attached to them, and this is what the body of an object definition is for.
The body contains up to four segments, which can occur in any order; each of
the four is optional. The segments are called
\beginstt
with has class private
\endtt^^|with|^^{objects: giving properties to}
|class| will be left until later. The most important segment is |with|,
which specifies things to be attached to the object. For example,
\beginstt
Object magpie "black-striped bird"
with wingspan, worms_eaten;
\endtt^^{magpie}^^{eating worms}^^{wingspan}
attaches two variables to the bird, one called |wingspan|, the other called
|worms_eaten|. Notice that when more than one variable is given, commas are
used to separate them: and the object definition as a whole is ended by a
semicolon, as always. The values of the magpie's variables are referred to
in the rest of the program as
\beginstt
magpie.wingspan
magpie.worms_eaten
\endtt
which can be used exactly the way normal (global) variables are used. Note
that the object has to be named along with the variable, since
\beginstt
crested_glebe.wingspan
magpie.wingspan
\endtt^^{properties: definition of}
are different variables.
Variables which are attached to objects in this way are called ``properties''.
More precisely, the name |wingspan| is said to be a property, and is said to be
``provided'' by both the |magpie| and |crested_glebe| objects.
The presence of a property can be tested using the |provides| condition.
For example,
\beginstt
objectloop (x provides wingspan) ...
\endtt^^|provides|
executes the code |...| for each object |x| in the game which is defined with
a |wingspan| property.
\danger Although the provision of a property can be tested, it cannot be
changed while the program is running. The value of |magpie.wingspan| may
change, but not the fact that the magpie has a |wingspan|.
\medskip\noindent
When the above magpie definition is made, the initial values of
\beginstt
magpie.wingspan
magpie.worms_eaten
\endtt
are both 0. To create the magpie with a given wingspan, we have to specify an
initial value: we do this by giving it after the name, e.g.
\beginstt
Object magpie "black-striped bird"
with wingspan 5, worms_eaten;
\endtt
and now the program begins with |magpie.wingspan| equal to 5, and
|magpie.worms_eaten| still equal to 0. (For consistency perhaps there should be
an equals sign before the 5, but if this were the syntax then Inform programs
would be horribly full of equals signs.)
\danger Properties can be arrays instead of global variables. If two or more
consecutive values are given for the same property, it becomes an array. Thus,
\beginstt
Object magpie "black-striped bird"
with name "magpie" "bird" "black-striped" "black" "striped",
wingspan 5, worms_eaten;
\endtt^^{arrays as property values}^^{properties: holding arrays}
|magpie.name| is not a global variable (and cannot be treated as such: it
doesn't make sense to add 1 to it), it is an |-->| array. This must be
accessed using two special operators, |.&| and |.#|.
\beginstt
magpie.&name
\endtt
means ``the array which is held in magpie's |name| property'', so that the
actual name values are in the entries
\beginstt
magpie.&name-->0
magpie.&name-->1
...
magpie.&name-->4
\endtt
The size of this array can be discovered with
\beginstt
magpie.#name
\endtt
which evaluates to the twice the number of entries, in this case, to 10.
(Twice the number of entries because it is actually the number of byte
array, |->|, entries: byte arrays take only half as much storage as word
arrays.)
\danger ^|name| is actually a special property created by Inform. It has the
unique distinction that textual values in double-quotes (like the five words
given in |magpie.name| above) are entered into the game's dictionary, and not
treated as ordinary strings. (Normally one would use single-quotes for this.
The rule here is anomalous and goes back to the misty origins of Inform 1.)
If you prefer a consistent style, using single quotes:
\beginstt
Object magpie "black-striped bird"
with name 'magpie' 'bird' 'black-striped' 'black' 'striped',
wingspan 5, worms_eaten;
\endtt%
works equally well (except that single-character names like ``X'' then have to
be written |#n$X|).
\bigskip\noindent Finally, properties can also be routines. In the definition
\beginstt
Object magpie "black-striped bird"
with name "magpie" "bird" "black-striped" "black" "striped",
wingspan 5,
flying_strength
[; return magpie.wingspan + magpie.worms_eaten;
],
worms_eaten;
\endtt^^{embedded routines}^^{routines as property values}
^^{properties: holding routines}
|magpie.flying_strength| is neither a variable nor an array, but a routine,
given in square brackets as usual. (Note that the Object directive continues
where it left off after the routine-end marker, |]|.) Routines which are
written in as property values are called ``embedded'' and are mainly used
to receive messages (as we shall see).
\ninepoint
\ddanger Embedded routines are unlike ordinary ones in two ways:
\item{1.}An embedded routine has no name of its own, since it is referred to
as a property such as |magpie.flying_strength| instead.
\item{2.}If execution reaches the |]| end-marker of an embedded routine,
then it returns |false|, not |true| (as a non-embedded routine would). The
reason for this will only become clear in Chapter III when |before| and |after|
rules are discussed.
\tenpoint
\csection{6}{|private| properties and encapsulation}%
\danger
An optional system is provided for ``encapsulating'' certain properties so
that only the object itself has access to them. These are defined by giving
them in a segment of the object declaration called |private|. For instance,
\beginstt
Object sentry "sentry"
private pass_number 16339,
with challenge
[ attempt;
if (attempt == sentry.pass_number)
"Approach, friend!";
"Stand off, stranger.";
];
\endtt^^|private|^^{encapsulation, setting up}^^{objects: encapsulation of}
^^{properties: encapsulation of}
makes the sentry provide two properties: |challenge|, which is public,
and |pass_number|, which can be used only by the sentry's own embedded
routines.
\ddanger This makes the |provides| condition slightly more interesting than it
appeared in the previous section. The answer to the question of whether
or not
\beginstt
sentry provides pass_number
\endtt^^|provides|
depends on who's asking: this condition is true if it is tested in one of
the sentry's own routines, and otherwise false. A |private| property
is so well hidden that nobody else can even know whether or not it exists.
\csection{7}{Attributes, |give| and |has|}^^{attribute, definition of}%
In addition to properties, objects have flag variables attached. (Recall
that flags are variables which are either true or false: the flag is either
flying, or not.) However, these are provided in a way which is quite
different. Unlike property names, attribute names have to be declared before
use with a directive like:
\beginstt
Attribute tedious;
\endtt^^{tedium of magpies, the}^^|Attribute|^^{directives: Attribute}
^^{objects: giving attributes to}
Once this declaration is made, every object in the tree has a |tedious| flag
attached, which is either true or false at any given time. The state can be
tested by the |has| condition:
\beginstt
if (magpie has tedious) ...
\endtt
tests whether the magpie's |tedious| flag is currently set, or not.
The magpie can be created already having attributes using the |has| segment
in its declaration:
\beginstt
Object magpie "black-striped bird"
with wingspan, worms_eaten
has tedious;
\endtt^^|has|
The |has| segment contains a list of attributes (with no commas in between)
which should be initially set. In addition, an attribute can have a
^{tilde} |~| in front, indicating ``this is definitely not held''. This is
usually what would have happened anyway, but class inheritance (see below)
disturbs this.
Finally, the state of such a flag is changed in the running of the program
using the |give| statement:
\beginstt
give magpie tedious;
\endtt^^{statements: give}
sets the magpie's |tedious| attribute, and
\beginstt
give magpie ~tedious;
\endtt
clears it again. The give statement can take a list of attributes, too:
\beginstt
give door ~locked open;
\endtt
for example, meaning ``take away |locked| and add on |open|''.
\csection{8}{Classes and inheritance}^^{inheritance}
^^{objects: inheritance from classes}%
Having covered routines and strings in \S 1, and |Object|s above, the fourth
and final metaclass to discuss is that of ``classes''. A class is a kind of
prototype object from which other objects are copied. These other objects are
sometimes called ``^{instances}'' or ``^{members}'' of the class, and are said
to ``inherit from'' it.
For example, clearly all birds ought to have wingspans, and the property
\beginstt
flying_strength
[; return magpie.wingspan + magpie.worms_eaten;
],
\endtt
(attached to the |magpie| in the example above) is using a formula which should
work for any bird. We might achieve this by using directives as follows:
\beginstt
Class Bird
with wingspan 7,
flying_strength
[; return self.wingspan + self.worms_eaten;
],
worms_eaten;
Bird "magpie"
with wingspan 5;
Bird "crested glebe";
Bird "Great Auk"
with wingspan 15;
Bird "early bird"
with worms_eaten 1;
\endtt^^{directives: Class}
The first definition sets up a new class called |Bird|. Every example of a
|Bird| now automatically provides |wingspan|, a |flying_strength| routine and
a count of |worms_eaten|. Note that the four actual birds are created using
the |Bird| class-name instead of the usual plain |Object| directive, but this
is only a convenient short form for definitions such as:
\beginstt
Object "magpie"
with wingspan 5
class Bird;
\endtt^^|class|
where |class| is the last of the four object definition segments. It's just
a list of classes which the object has to inherit from.
The |Bird| routine for working out |flying_strength| has to be written in such
a way that it can apply to any bird. It has to say ``the flying strength of
any bird is equal to its wingspan plus the number of worms it has eaten''.
To do this, it has used the special value ^|self|, which means ``whatever
object is being considered at the moment''. More of this in the next section.
Note also that the |Bird| |with| specifies a |wingspan| of 7. This is the value
which its members will inherit, unless their own definitions over-ride this,
as the magpie and great Auk objects do. Thus the initial position is:
\beginstt
Bird Value of wingspan Value of worms_eaten
magpie 5 0
crested glebe 7 0
Great Auk 15 0
early bird 7 1
\endtt
\ddanger In rare cases, clashes between what a class says and what the object
says are resolved differently: see \S 8.
\medskip\noindent
Inform has ``^{multiple inheritance}'', which means that any object can inherit
from any number of classes. Thus, an object has no single class; rather,
it can be a member of several classes at once.
Every object is a member of at least one class, because the four ``metaclasses''
|Routine|, |String|, |Object| and |Class| are themselves classes.
(Uniquely, |Class| is a member of itself.) The magpie above is a member of
both |Bird| and |Object|.
To complicate things further, classes can themselves inherit from other
classes:
\beginstt
Class BirdOfPrey
class Bird
with wingspan 15,
people_eaten;
BirdOfPrey kestrel;
\endtt^^{subclasses}^^{birds of prey}^^{kestrels}
makes |kestrel| a member of both |BirdOfPrey| and of |Bird|. Informally,
|BirdOfPrey| is called a ``subclass'' of |Bird|.
Given all this, it's impossible to have a function called |class|, analogous
to |metaclass|, to say what class something belongs to. Instead, there is a
condition called ^|ofclass|:
\beginstt
kestrel ofclass Class
\endtt
is false, while
\beginstt
kestrel ofclass BirdOfPrey
kestrel ofclass Bird
kestrel ofclass Object
"Canterbury" ofclass String
\endtt
are all true. This condition is especially handy for use with |objectloop|:
\beginstt
objectloop (x ofclass Bird) move x to Aviary;
\endtt^^{Aviary}
moves all the birds to the |Aviary|.
\csection{9}{Messages}^^{messages}^^{objects: sending messages to}%
That completes the story of how to create objects, and it's time to begin
communicating with them by means of messages.
Every message has a sender, a receiver and some parameter values
attached, and it always produces a reply (which is just a single value). For
instance,
\beginstt
x = lamp.addoil(5, 80);
\endtt
sends the message |addoil| with parameters 5 and 80 to the object |lamp|, and
puts the reply value into |x|. Just as properties like |magpie.wingspan|
are variables attached to objects, so messages are received by routines
attached to objects, and message-sending is very like making an ordinary
Inform function call. The ``reply'' is what was called the return value
in \S 1, and the ``parameters'' used to be called function call arguments.
But slightly more is involved, as will become apparent.
\bigskip\noindent
What does the lamp object do to respond to this message? First of all, it
must do something. If the programmer hasn't specified an |addoil| routine
for the lamp, then an error message will be printed out when the program
is run, along the lines of
\beginstt
*** The object "lamp" does not provide the property "addoil" ***
\endtt
Not only does |lamp.addoil| have to exist, but it has to hold one of the
four kinds of object, or else |nothing|. What happens next depends
on the |metaclass| of |lamp.addoil|:^^{receiving messages}
\smallskip{\ninepoint
\settabs 8 \columns
\+ &|metaclass| & What happens: &&& The reply is:\cr
\+ & & &&& \cr
\+ &|Routine| & the routine is called with the &&& the routine's return value\cr
\+ & & the given parameters\cr
\+ &|String| & the string is printed, followed &&& |true|\cr
\+ & & by a new-line\cr
\+ &|Object| & nothing &&& the object\cr
\+ &|Class| & nothing &&& the class\cr
\+ &|nothing| & nothing &&& |false|, or 0, or |nothing|\cr
\+ & & &&& (all different ways of writing 0)\cr
\smallskip}\noindent
\danger If |lamp.addoil| is a list rather than a single value then the
first entry is the one looked at, and the rest are ignored.
For example,
\beginstt
print kestrel.flying_strength();
\endtt
will print out 15, by calling the |flying_strength| routine provided by the
|kestrel| (the same one it inherited from |Bird|), which adds its wingspan of
15 to the number of worms it has so far eaten (none), and then returns 15.
(You can see all the messages being sent in a game as it runs
with the debugging verb ^{``messages''}: see \S 30 for details.)
\danger For examples of all the other kinds of receiving property, here is
roughly what happens when the Inform library tries to move the player northeast
from the current room (the |location|) in an adventure game:
\beginstt
x = location.ne_to();
if (x == nothing) "You can't go that way.";
if (x ofclass Object) move player to x;
\endtt
This allows directions to be given with some flexibility in properties like
|ne_to| and so on:
\beginstt
Object Octagonal_Room "Octagonal Room"
with ...
ne_to "The north-east doorway is barred by an invisible wall!",
w_to Courtyard,
e_to
[; if (Amulet has worn)
{ print "A section of the eastern wall suddenly parts before
you, allowing you into...^";
return HiddenShrine;
}
],
s_to
[; if (random(5) ~= 1) return Gateway;
print "The floor unexpectedly gives way, dropping you through
an open hole in the plaster...^";
return random(Maze1, Maze2, Maze3, Maze4);
];
\endtt^^{Octagonal Room}
Two special variables help with the writing of message routines:
^|self| and ^|sender|. |self| always has as value the |Object| which is
receiving the message, while |sender| has as value the |Object| which sent it,
or |nothing| if it wasn't sent from |Object| (but from some free-standing
routine). For example,
\beginstt
pass_number
[; if (~~(sender ofclass CIA_Operative))
"Sorry, you aren't entitled to know that.";
return 16339;
];
\endtt
\csection{10}{Access to superclass values}%
\ninepoint%
\danger A fairly common situation in Inform coding is that one has a general
class of objects, say |Treasure|, and wants to create an instance of this class
which behaves slightly differently. For example, we might have
\beginstt
Class Treasure
with deposit
[; if (self provides deposit_points)
score = score + self.deposit_points;
else score = score + 5;
"You feel a sense of increased esteem and worth.";
];
\endtt
and we want to create an instance called |Bat_Idol| which (say) flutters
away, resisting deposition, but only if the room is dark:
\beginstt
Treasure Bat_Idol "jewelled bat idol"
with deposit
[; if (location == thedark)
{ remove self;
"There is a clinking, fluttering sound!";
}
...
];
\endtt^^{superclass, definition of}
In place of |...|, we have to copy out all of the previous code about
depositing treasures. This is clumsy: what we really want is a way of
sending the deposit message to |Bat_Idol| but ``as if it had not changed the
value of deposit it inherited from |Treasure|''. We achieve this with the
so-called ^{superclass operator}, ^|::|. (The term ``superclass'' is borrowed
from the ^{Smalltalk-80} system, where it is more narrowly defined.) Thus, in
place of |...|, we could simply write:
\beginstt
self.Treasure::deposit();
\endtt
to send itself the |deposit| message again, but this time diverted to the
property as provided by Treasure.
The |::| operator works on all property values, not just for message sending.
In general,
\beginstt
object.class::property
\endtt
evaluates to the value of the given property which the class would normally
pass on (or gives an error if the class doesn't provide that property or if
the object isn't a member of that class). Note that |::| exists as an operator
in its own right, so it is perfectly legal to write, for example,
\beginstt
x = Treasure::deposit; Bat_Idol.x();
\endtt
To continue the avian theme, |BirdOfPrey| might have its
own |flying_strength| routine:
\beginstt
flying_strength
[; return self.Bird::flying_strength() + self.people_eaten;
],
\endtt
reflecting the idea that, unlike other birds, these can gain strength by
eating people.
\tenpoint
\csection{11}{Philosophy}%
\ninepoint^^{objects: philosophy of}^^{philosophy of objects}
\ddanger This section is best skipped until the reader feels entirely happy
with the rest of Chapter I. It is aimed mainly at those worried
about whether the ideas behind the apparently complicated system of classes and
objects are sound. (As ^{Stephen Fry} once put it, ``Socialism is all very well
in practice, but does it work in theory?'') We begin with two definitions:
\item{}{\bf object}
\item{}a member of the program's object tree, or a routine in the
program, or a literal string in the program. (Routines and
strings can't, of course, be moved around in the object tree, but
the tests |ofclass| and |provides| can be applied to them, and
they can be sent messages.) Objects are part of the compiled
program produced by Inform.
\item{}{\bf class}
\item{}an abstract name for a set of objects in the game, which may have
associated with it a set of characteristics shared by its objects.
Classes themselves are frequently described by text in the program's
source code, but are not part of the compiled program produced by Inform.
\medskip\noindent Here are the full rules:
\item{(1)}Compiled programs are composed of objects, which may have variables
attached called ``properties''.
\item{(2)}Source code contains definitions of both objects and classes.
\item{(3)}Any given object in the program either is, or is not, a member of
any given class.
\item{(4)}For every object definition in the source code, an object is made
in the final program. The definition specifies which classes this object is
a member of.
\item{(5)}If an object |X| is a member of class |C|, then |X| ``inherits''
property values as given in the class definition of |C|.
\medskip\noindent The details of how inheritance takes place are omitted here.
But note that one of the things which can be inherited from class |C| is being
a member of some other class, |D|.
\medskip\noindent
\item{(6)}For every class definition, an object is made in the final program
to represent it, called its ``class-object''.
\medskip\noindent For example, suppose we have a class definition like:
\beginstt
Class Dwarf
with beard_colour;
\endtt
The class |Dwarf| will generate a class-object in the final program, also
called |Dwarf|. This class-object exists in order to receive messages like
|create| and |destroy| and, more philosophically, in order to represent
the concept of ``dwarfness'' within the simulated world.
It is important to remember that the class-object of a class is not normally
a member of that class. The concept of dwarfness is not itself a dwarf:
the condition |Dwarf ofclass Dwarf| is false. Individual dwarves provide
a property called |beard_colour|, but the class-object of |Dwarf| does not:
the concept of dwarfness has no single beard colour.
\medskip\noindent
\item{(7)}Classes which are automatically defined by Inform are called
``metaclasses''. There are four of these: |Class|, |Object|, |Routine|
and |String|.
\medskip\noindent
It follows by rule (6) that every Inform program contains the class-objects
of these four, also called |Class|, |Object|, |Routine| and |String|.
\medskip\noindent
\item{(8)}Every object is a member of one, and only one, metaclass:
\item{(8.1)}The class-objects are members of |Class|, and no other class.
\item{(8.2)}Routines in the program (including those given as property
values) are members of |Routine| and no other class.
\item{(8.3)}Static strings in the program (including those given as property
values) are members of |String|, and of no other class.
\item{(8.4)}The objects defined in the source code are members of |Object|,
and possibly also of other classes defined in the source code.
\medskip\noindent
It follows from (8.1) that |Class| is the unique class whose class-object
is one of its own members: the condition |Class ofclass Class| is true,
whereas |X ofclass X| is false for every other class |X|.
There is one other unusual feature of metaclasses, and it is a rule provided
for pragmatic reasons (see below) even though it is not very elegant:
\medskip\noindent
\item{(9)}Contrary to rules (5) and (8.1), the class-objects of the four
metaclasses do not inherit from |Class|.
\bigskip\noindent
This concludes the list of rules. To see what they entail, one needs to
know the definitions of the four metaclasses. These definitions are never
written out in any textual form inside Inform, as it happens, but here are
definitions equivalent to what actually does happen. (There is no such
directive as |Metaclass|: none is needed, since only Inform itself can
define metaclasses, but the definitions here pretend that there is.)
\beginstt
Metaclass Object;
\endtt
In other words, this is a class from which nothing is inherited. So the
ordinary objects described in the source code only have the properties which
the source code says they have.
\beginstt
Metaclass Class
with create [; ... ],
recreate [ instance; ... ],
destroy [ instance; ... ],
copy [ instance1 instance2; ... ],
remaining [; ... ];
\endtt
So class-objects respond only to these five messages, which are described in
detail in the next section, and provide no other properties: {\bf except} that
by rule (9), the class-objects |Class|, |Object|, |Routine| and |String|
provide no properties at all. The point is that these five messages are
concerned with object creation and deletion at run time. But Inform is a
compiler and not, like ^{Smalltalk-80} or other highly object-oriented
languages, an interpreter. We cannot create the program while it is actually
running, and this is what it would mean to send requests for creation or
deletion to |Class|, |Object|, |Routine| or |String|. (We could write the
above routines to allow the requests to be made, but to print out some error
if they ever are: but it is more efficient to have rule (9) instead.)
\beginstt
Metaclass Routine
with call [ parameters...; ... ];
\endtt
Routines therefore provide only |call|. See the next section for how to use
this.
\beginstt
Metaclass String
with print [; print_ret (string) self; ],
print_to_array [ array; ... ];
\endtt
Strings therefore provide only |print| and |print_to_array|. See the next
section for how to use these.
\bigskip\noindent
To demonstrate this, here is an Inform code representation of what happens
when the message
\beginstt
O.M(p1, p2, ...)
\endtt
is sent.
\beginstt
if (~~(O provides M)) "Error: O doesn't provide M";
P = O.M;
switch(metaclass(P))
{ nothing, Object, Class: return P;
Routine: return P.call(p1, p2, ...);
String: return P.print();
}
\endtt
(The messages |call| and |print| are actually implemented by hand, so this
is not actually a circular definition. Also, this is simplified to remove
details of what happens if |P| is an array.)
\tenpoint
\csection{12}{Sending messages to routines, strings or classes}%
^^{messages: to routines, strings and classes}%
\danger In the examples so far, messages have only been sent to proper
|Object|s. But it's a logical possibility to send messages to objects of the
other three metaclasses too: the question is whether they are able to receive
any. The answer is yes, because Inform provides 8 properties for such objects,
as follows.
\ninepoint
The only thing you can do with a |Routine| is to call it. Thus, if |Explore| is
the name of a routine, then
\beginstt
Explore.call(2, 4); and Explore(2, 4);
\endtt^^|call|^^{messages: call}
are equivalent expressions. The message |call(2,4)| means ``run this routine
with parameters (2,4)''. This is not quite redundant, because it can be used
more flexibly than ordinary function calls:
\beginstt
x = Explore; x.call(2, 4);
\endtt
The |call| message replies with the routine's return value.
Two different messages can be sent to a |String|. The first is |print|, which
is provided because it logically ought to be, rather than because it is
useful. So, for example,
\beginstt
("You can see an advancing tide of bison!").print();
\endtt^^|print|^^{messages: print}
prints out the string, followed by a new-line; the |print| message replies
|true|, or 1.
\ddanger |print_to_array| is more useful. It copies out the text of the
string into entries 2, 3, 4, ... of the supplied byte array, and writes the
number of characters as a word into entries 0 and 1. That is, if |A| has
been declared as a suitably large array,
\beginstt
("A rose is a rose is a rose").print_to_array(A);
\endtt^^|print to array|^^{messages: print to array}
will cause the text of the string to be copied into the entries
\beginstt
A->2, A->3, ..., A->27
\endtt
with the value 26 written into
\beginstt
A-->0
\endtt
And the reply value of the message is also 26, for convenience.
Five different messages can be sent to objects of metaclass Class, i.e., to
classes, and these are detailed in the next section. (But an exception to this
is that no messages at all can be sent to the four metaclasses |Class|,
|Object|, |Routine| and |String|.)
\tenpoint
\csection{13}{Creating and deleting objects}%
^^{objects: creation and deletion during play}%
^^{creating objects}^^{deleting objects}%
A vexed problem in all object-oriented systems is that it is often elegant
to grow data structures organically, simply conjuring new objects out of
mid-air and attaching them to the structure already built. The problem
is that since resources cannot be infinite, there will come a point
where no new objects can be conjured up. The program must be written so
that it can cope with this, and this can present the programmer with
some difficulty, since the conditions that will prevail when the program
is being run may be hard to predict.
In an adventure-game setting, object creation is useful for something like
a ^{beach full of stones}: if the player wants to pick up more and more stones,
the game needs to create a new object for each stone brought into play.
Inform allows object creation, but it insists that the programmer must specify
in advance what the maximum resources ever needed will be: for example, the
maximum number of stones which can ever be in play. Although this is
a nuisance, the reward is that the resulting program is guaranteed to work
correctly on every machine running it (or else to fail in the same way
on every machine running it).
The model is this. When a class is defined, a number $N$ is specified, which
is the maximum number of created instances of the class which the programmer
will ever need at once. When the program is running, ``instances'' can be
created (up to this limit); or deleted. One can imagine the class having a
stock of instances, so that creation consists of giving out one of the
stock-pile and deletion consists of taking one back.
Classes can receive the following five messages:
\medskip\noindent|remaining()|^^{messages: remaining}
\par\noindent What is the current value of $N$? That is, how many
more instances can be created?
\medskip\noindent|create()|^^{messages: create}
\par\noindent Replies with a newly created instance, or
with |nothing| if no more can be created.
\medskip\noindent|destroy(I)|^^{messages: destroy}
\par\noindent Destroys the instance |I|, which must previously have
been created.
\medskip\noindent|recreate(I)|^^{messages: recreate}
\par\noindent Re-initialises the instance |I|, as if it had been
destroyed and then created again.
\medskip\noindent|copy(I, J)|^^{messages: copy}
\par\noindent Copies |I| to be equal to |J|, where both have to be
instances of the class.
\medskip
\danger Note that |recreate| and |copy| can be sent for any instances, not just
instances which have previously been created. For example,
\beginstt
Plant.copy(Gilded_Branch, Poison_Ivy)
\endtt
copies over all the |Plant| properties and attributes from |Poison_Ivy| to
|Gilded_Branch|, but leaves all the rest alone. Likewise,
\beginstt
Treasure.recreate(Gilded_Branch)
\endtt
only resets the properties to do with |Treasure|, leaving the |Plant| properties
alone.
Unless the definition of a class |C| is made in a special way, |C.remaining()|
will always reply 0, |C.destroy()| will cause an error and |C.create()| will
be refused. This is because the magic number $N$ for a class is normally 0.
The ``special way'' is to give $N$ in brackets after the class name. For
example, if the class definition for |Leaf| begins:
\beginstt
Class Leaf(100) ...
\endtt
then initially |Leaf.remaining()| will reply 100, and the first 100 |create()|
messages will certainly be successful. Others will only succeed if leaves
have been destroyed in the mean time. In all other respects |Leaf| is an
ordinary class.
\ninepoint
\danger Object creation and destruction may need to be more sophisticated
than this. For example, we might have a data structure in which every object
of class |A| is connected in some way with four objects of class |B|. When a
new |A| is created, four new |B|s need to be created for it; and when an |A| is
destroyed, its four |B|s need to be destroyed. In an adventure game setting,
we might imagine that every Dwarf who is created has to carry an Axe of his own.
When an object has been created (or recreated), but before it has been
``given out'' to the program, a |create| message is sent to it (if it provides
|create|). This gives the object a chance to set itself up sensibly.
Similarly, when an object is about to be destroyed, but before it actually is, a
|destroy| message is sent to it (if it provides |destroy|). For example:
\beginstt
Class Axe(30);
Class Dwarf(7)
with beard_colour,
create
[ x; self.beard_colour = random("black", "red", "white", "grey");
! Give this new dwarf an axe, if there are any to spare
x = Axe.create(); if (x ~= nothing) move x to self;
],
destroy
[ x;
! Destroy any axes being carried by this dwarf
objectloop (x in self && x ofclass Axe) Axe.destroy(x);
];
\endtt
\tenpoint
\csection{14}{Footnote on common vs. individual properties}%
^^{individual properties}^^{common properties}
^^{properties: common vs individual}
\ddanger
The properties used in the sections above are all examples of
``individual properties'', which some objects provide and others do not.
There are also ``common properties'' which, because they are inherited
from the class |Object|, are held by every member of |Object|.
An example is |capacity|. The |capacity| can be read for an ordinary
game object (say, a crate) even if it doesn't specify a
|capacity| for itself, and the resulting ``default'' value will
be 100. However, this is only a very weak form of inheritance --
you can't change the crate's |capacity| value and the condition
|crate provides capacity| evaluates to |false|.
\ninepoint
The properties defined by the Inform library, such as
|capacity|, are all common: mainly because common properties
are marginally faster to access and marginally cheaper on memory.
Only 62 are available, of which the library uses up 48.
Individual properties, on the other hand, are practically
unlimited. It is therefore worth declaring a common property only
in those cases where it will be used very often in your program.
You can declare common properties with the directive:
\begindisplay
|Property |\<name>|;|
\enddisplay^^{directives: Property}
which should be made after the inclusion of ``Parser'' but before
first use of the new name. The class |Object| will now
pass on this property, with value 0, to all its members. This
so-called ``default value'' can optionally be specified. For
example, the library itself makes the declaration
\begindisplay
|Property capacity 100;|
\enddisplay
which is why all containers in a game which don't specify any particular
|capacity| can hold up to 100 items.
\tenpoint
\chapter{Chapter II: Using the Compiler}
\vskip 1in
\verywidepoem
I was promised a horse, but what I got instead
was a tail, with a horse hung from it almost dead.
\tlwidequoteby{^{Palladas of Alexandria} ({\oldstyle319}?--{\oldstyle400}?)}{translated by ^{Tony Harrison} ({\oldstyle1937}--)}
\section{4}{The language of Inform}
\def\dsection#1#2{\bigbreak\noindent{\bf \S 4.#1\quad #2}\medskip\noindent}
\dsection{1}{ICL}^^{ICL}^^{Inform Command Language (ICL)}
^^{switches (command line)}
The Inform compiler is quite configurable: it has a number of settings
which can be altered to suit the convenience of the user. Many of these
settings are ``switches'', which usually have just two possible states,
off or on. However, some can be set to a single-digit number.
The other numerical settings are ``^{memory settings}'', which control
how much of your computer's memory Inform uses while running (too low and
it may not be able to compile games of the size you desire; too high and
it may choke any other programs in the computer for space).
Finally, there are ``^{path variables}'', which contain text and are used
to sort out filenames for the files Inform uses or creates. The usage
of these variables varies widely from machine to machine, or rather, from
one operating system to another.
If Inform seems to work adequately for you already, this section can
safely be ignored until the day comes to compile a really big project.
Times like that call for the ability to conveniently change many settings
at once, and a tiny language called ``ICL'' is provided for you to supply
detailed specifications.
\bigskip\noindent On many systems, though not usually the Apple Macintosh,
the user sets Inform running by typing a command at the ``command line'',
that is, in response to a prompt printed by the computer. For example,
under RISC OS one would press function key f12 from the desktop and be
given the prompt |*|, to which one might reply
\beginstt
inform ruins
\endtt^^{desktop (RISC OS)}^^{command line}
On computers with more doggedly windowed interfaces, there will be a
higher-level interface of some kind provided with Inform, which should
come with its own brief documentation.
The usual way to alter switches on the command line is to give a word of
options after the |inform| command, introduced by a minus sign. The
switches are all single letters, and by default are mostly off. For
example, the |-x| switch causes Inform to print a row of hash signs as it
compiles:
\beginstt
inform -x shell
RISC OS Inform 6.01 (April 25th 1996)
::###############################################################
\endtt
One hash sign is printed for every 100 textual lines of source code compiled.
(On my own machine, an ^{Acorn Risc PC 700}, about 10 hashes are printed
every second: that is, the compilation speed is about 1000 lines per second.)
Although |-x| is provided to indicate that a slow compilation is continuing
normally, many designers use it to get a feeling for how large their games
are, and it's a morale boost when the row of hashes spills over onto a
second screen line.
Inform has documentation built-in on the subject of switches and other
ICL features, which may vary from machine to machine. Running Inform with
no filename will print this ``^{help information}''. In addition, |-h1|
will print details of filenaming conventions in use on your machine, and
|-h2| will print a list of switches and their settings.
The full ^{command line syntax} is
\begindisplay
|inform| \<ICL commands> \<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|. This is called
``^{filename translation}''. No detailed information on filenaming rules
is given here, because it varies so much from machine to machine: see the
|-h1| on-line documentation. Note however that a filename can contain
spaces if it is written in double-quotes.
\bigskip\noindent
One possible ICL command is to give a filename in brackets: e.g.,
\begindisplay
|inform -x (skyfall_setup) ...|
\enddisplay
sets the |-x| switch, then runs through the text file |skyfall_setup|
executing each line as an ICL command. As an example, this file might
read as follows:
\beginstt
! Setup file for "Skyfall"
-d ! Contract double spaces
$max_objects=1000 ! 500 of them snowflakes
(usual_setup) ! include my favourite settings, too
+module_path=mods ! keep modules in the "mods" directory
\endtt^^{`Skyfall' setup file}
Note that ICL can include comments after |!|, just as in Inform.
Otherwise, an ICL file has one command per line (with no dividing
semicolons), and the possibilities are as follows:
\medskip
\par\noindent|-<switches>|\par\noindent
set these switches; or unset any switch preceded by a tilde |~|.
(For example, |-a~bc| sets |a|, unsets |b| and sets |c|.)
\par\noindent|$list|\par\noindent
list current memory settings
\par\noindent|$?<name>|\par\noindent
ask for information on what this memory setting is for
\par\noindent|$small|\par\noindent
set the whole collection of memory settings to suitable levels for a small
game
\par\noindent|$large|\par\noindent
ditto, for a slightly larger game
\par\noindent|$huge|\par\noindent
ditto, for a reasonably big one
\par\noindent|$<name>=<quantity>|\par\noindent
alter the named memory setting to the given level
\par\noindent|+<name>=<filename>|\par\noindent
set the named pathname variable to the given filename, which
should be one or more filenames of directories, separated by commas
\par\noindent|compile <filename> <filename>|\par\noindent
compile the first-named file, containing source code, writing
the output program to the (optional) second-named file
\par\noindent|(<filename>)|\par\noindent
execute this ICL file (files may call each other in this way)
\medskip
\dsection{2}{Controlling what is compiled}%
Several directives instruct Inform to ``compile this part next'' or ``only
compile this...''. First,
\beginstt
Include "filename";
\endtt
instructs Inform to compile the whole of the source code in the given
file, and only carry on compiling from here once that is complete. It is
exactly equivalent to removing the ^|Include| directive and replacing it
with the whole file |"filename"|. (The rules for how Inform interprets
|"filename"| vary from machine to machine: run Inform with the |-h1|
switch for information.) Note that you can write
\beginstt
Include ">shortname";
\endtt
to mean ``the file called |"shortname"| which is in the same
directory that the present file came from''. This is convenient
if all the files making up the source code of your game are
housed together.
\danger\ninepoint%
Next, there are a number of ``^{conditional compilation}'' directives.
They take the general form of a condition:
\beginstt
Ifdef <name>; Is the name defined as having some meaning?
Ifndef <name>; Is the name undefined?
Iftrue <condition>; Is this condition true?
Iffalse <condition>; Is this condition false?
\endtt^^|Ifdef|^^|Ifndef|^^|Iftrue|^^|Iffalse|
followed by a chunk of Inform and then either
\beginstt
Ifnot;
\endtt^^|Ifnot|
and another chunk of Inform, or just
\beginstt
Endif;
\endtt^^|Endif|
At this point it is perhaps worth mentioning that (most) directives can
also be interspersed with statements in routine declarations, provided
they are preceded by a |#| sign. For example:
\beginstt
[ MyRoutine;
#Iftrue MAX_SCORE > 1000;
print "My, what a long game we're in for!^";
#Ifnot;
print "Let's have a quick game, then.^";
#Endif;
PlayTheGame();
];
\endtt
which actually only compiles one of the two |print| statements, according to
what the value of the constant |MAX_SCORE| is.
\ddanger Four more arcane directives control conditional compilation.
\beginstt
Default <name> <value>;
\endtt^^|Default|
defines \<name> as a constant if it wasn't already the name of something:
so it's equivalent to the manoeuvre
\beginstt
Ifndef <name>;
Constant <name> = <value>;
Endif;
\endtt
Similarly,
\beginstt
Stub <name> <number>;
\endtt^^|Stub|
defines a routine with this name and number of local variables, if it isn't
already the name of something: so it's equivalent to
\beginstt
Ifndef <name>;
[ <name> x1 x2 ... x<number>;
];
Endif;
\endtt
\ddanger
Large blocks of code intended to be used in many different games, such as
the files which make up the Inform library, should be marked somewhere with
the directive
\beginstt
System_file;
\endtt^^|System file|
If this is done, it is possible for an outside program including the file
to use |Replace|. The idea is that a sequence like:
\beginstt
Replace DoSomething;
...
Include "SomeLibrary";
...
[ DoSomething; "Tarantaraa!"; ];
\endtt
allows a routine |DoSomething|, which would normally be defined in the
|Include| file |"SomeLibrary"|, to be defined in this file instead. The
definition in the |Include| file is simply ignored. In this way, one can
override the library routines without actually having to modify the library
source code. To recap, the rule here is that a routine's definition is
ignored if both (a) it occurs in a declared ``system file'', and (b)
its name has been given in a |Replace| directive.
\bigskip\noindent
One way to follow what is being compiled is to use the ^|Message| directive.
The compiler can be made to print messages at compile time using:
\beginstt
Message "information"
Message error "error message"
Message fatalerror "fatal error message"
Message warning "warning message"
\endtt
For example,
\beginstt
Ifndef VN_1610;
Message fatalerror "This code can only be compiled by Inform 6.1";
Endif;
\endtt^^|VN ****|
(By a special rule, the condition |VN_1610|-is-defined is true if and only
if the version number is 6.10 or more; similarly for other four-digit
numbers beginning with a 1.) Informational messages are simply printed: e.g.,
\beginstt
Message "Library extension by Boris J. Parallelopiped";
\endtt^^{Boris J. Parallelopiped}
just prints out this line (with a carriage return).
\dsection{3}{Using the linker}^^{external program}^^{Jekyll and Hyde}
The process of ``^{linking}'' is as follows. A game being compiled (called the
``external'' program) may ^|Link| one or more pre-compiled sections of code
called ``^{modules}''.
Suppose the game Jekyll has a subsection called Hyde. Then these two
methods of making Jekyll are, nearly, equivalent:
\item{(i)} Putting |Include "Hyde";| in the source code for |"Jekyll"|,
and compiling |"Jekyll"|.
\item{(ii)} Compiling |"Hyde"| with the |-M| (``module'') switch set,
then putting |Link "Hyde";| into the same point in the source code for
|"Jekyll"|, and compiling |"Jekyll"|.
\par\noindent
Option (ii) is much faster as long as |"Hyde"| does not change very often,
since its ready-compiled module can be left lying around while |"Jekyll"|
is being developed.
Because ``^{linking the library}'' is by far the most common use of the
linker, this is made simple. All you have to do is compile your
game with the |-U| switch set, or, equivalently, to begin your source code
with
\beginstt
Constant USE_MODULES;
\endtt
(This assumes that you already have pre-compiled copies of the two library
modules: if not, you'll need to make them with
\beginstt
inform -M library.parserm
inform -M library.verblibm
\endtt
(where |library.parserm| should be replaced with the filename for your
copy of the library file ``parserm'', and likewise for ``verblibm'').)
Note that it is essential not to make any ^|Attribute| or ^|Property|
declarations {\it before} the |Include "Parser"| line in the source
code, though {\it after} that point is fine. (Library 6/2 and later
will print an error message if you make this mistake, but under 6/1
it can be a source of mysterious problems.)
\ddanger\ninepoint You can also write your own library modules, or indeed
subdivide a large game into many modular parts. But there are certain
restrictions to the possibilities. (Real experts may want to look at
the {\sl Technical Manual} here.) Here's a brief list of these:
\ninepoint\medskip\noindent 1.\qquad
The module must make the same |Property| and |Attribute| directives
as the main program. Including the library file ^|"linklpa.h"|
(``link library properties and attributes'') declares the library's
stock, so it would be sensible to begin a module with
\beginstt
Include "linklpa";
\endtt
and then include a similar file defining all the extra common properties
and attributes which are needed by the program (if any).
\medskip\noindent 2.\qquad
The module cannot contain grammar (i.e., use |Verb| or |Extend| directives)
or create fake actions.
\medskip\noindent 3.\qquad
The module can only use global variables defined outside the module
if they are explicitly declared before use using the |Import| directive.
For example,
\beginstt
Import global frog;
\endtt
allows the rest of the module's source code to refer to the variable
|frog| (which must be defined in the outside program). Note that
the Include file ^|"linklv.h"| (``link library variables'') imports all
the library variables, so it would be sensible to include this.
\medskip\noindent 4.\qquad
An object in the module can't inherit from a class defined outside
the module. (But an object outside can inherit from a class inside.)
\medskip\noindent 5.\qquad
Certain constant values in the module must be known at
module-compile-time (and must not, for instance, be a symbol only defined
outside the module). For instance: the size of an array must be
known now, not later; the number of duplicate members of a |Class|;
and the quantities being compared in an |Iftrue| or |Iffalse|.
\medskip\noindent 6.\qquad
The module can't: define the |Main| routine; use the |Stub| or |Default|
directives; or define an object whose parent object is not also in the
same module.
\bigskip\noindent These restrictions are mild in practice. As an example,
here is a short module to play with:
\beginstt
Include "linklpa"; ! Make use of the properties, attributes
Include "linklv"; ! and variables from the Library
[ LitThings x;
objectloop (x has light)
print (The) x, " is currently giving off light.^";
];
\endtt
It should be possible to compile this |-M| and then to |Link| it into
another game, making the routine |LitThings| exist in that game.
\tenpoint
\section{5}{Compiler options and memory settings}%
It is time to give a full list of the ``switches'', which are the
main way to make choices about how Inform will operate. (This list
can always be printed out with the |-h2| switch.)
\beginlines
| a trace assembly-language (without hex dumps; see -t)|
| c more concise error messages|
| d contract double spaces after full stops in text|
| d2 contract double spaces after exclamation and question marks, too|
| e economy mode (slower): make use of declared abbreviations|
| f frequencies mode: show how useful abbreviations are|
| g traces calls to functions (except in the library)|
| g2 traces calls to all functions|
| h print this information|
| i ignore default switches set within the file|
| j list objects as constructed|
| k output Infix debugging information to "gamedebug"|
| l list every statement run through Inform|
| m say how much memory has been allocated|
| n print numbers of properties, attributes and actions|
| o print offset addresses|
| p give percentage breakdown of story file|
| q keep quiet about obsolete usages|
| r record all the text to "gametext"|
| s give statistics|
| t trace assembly-language (with full hex dumps; see -a)|
| u work out most useful abbreviations (very very slowly)|
| 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|
| v7 compile to version-7 (*) story file|
| v8 compile to version-8 (*) story file|
| (*) formats for very large games, requiring|
| slightly modified game interpreters to play|
| w disable warning messages|
| x print # for every 100 lines compiled|
| y trace linking system|
| z print memory map of the Z-machine|
| D insert "Constant DEBUG;" automatically|
| E0 Archimedes-style error messages (current setting)|
| E1 Microsoft-style error messages|
| E2 Macintosh MPW-style error messages|
| F1 use temporary files to reduce memory consumption|
| M compile as a Module for future linking|
| R0 use filetype 060 + version number for games (default)|
| R1 use official Acorn filetype 11A for all games|
| T enable throwback of errors in the DDE|
| U insert "Constant USE_MODULES;" automatically|
\endlines^^{compiler switches}^^{switches (on command line)}
Note that the list may vary slightly from machine to machine:
|R0|, |R1| and |T| above are for Acorn RISC OS machines only,
for example.
\danger
Note that these switches can also be selected by putting a ^|Switches|
directive, such as |Switches xdv8s;| right at the start of the source
code.
Only two switches have a really drastic effect:
\medskip
\noindent |M|\qquad Makes Inform compile a ``module'', not a ``game''.
See \S 4.3.
\medskip
\noindent |v|\qquad Chooses the format of the game to be compiled.
|v5| is the default, but if a game begins to overflow this, try |v8|.
(The other settings are intended mainly for maintainers of Infocom
interpreters to test their wares.)
\medskip
\noindent |i|\qquad 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.
\medskip
Many of the remaining switches make Inform produce text as it runs,
without affecting the actual compilation:
\medskip
\noindent |a l m n t y|\qquad Tracing options to help with maintaining
Inform, or for debugging assembly language
programs.^^{debugging: switches to help assembly language debugging}
^^{assembly language: tracing switches}
\noindent |o p s z|\qquad To print out information about the final game file:
the |s| (^{statistics}) option is particularly useful to keep track of how
large the game is growing.
\noindent |c w q E T|\qquad 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 RISC OS machines, error throwback
will occur in the `Desktop Development Environment'. |q| causes
``this usage is obsolete'' warnings to be suppressed, which may
be useful when compiling very long, very old programs. Finally, |E| is
provided since different error formats fit in better with debugging tools
on different machines.
\noindent |f|\qquad Indicates roughly how many bytes the abbreviations saved.
\noindent |h|\qquad Prints out the help information.
\noindent |j x|\qquad Makes Inform print out steady text to prove that it's
still awake: on very slow machines this may be a convenience.
\noindent |k|\qquad Writes a ``debugging information'' file for the use of
the ^{Infix} debugger (the filename will be something suitable for
your machine).^^{debugging: information file}^^{debugging: using Infix}
\noindent |r|\qquad Intended to help with proof-reading the text of a game:
transcribes all of the text in double-quotes to the given file (whose
filename will be something suitable for your machine).
\noindent |u|\qquad Tries 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\noindent
\noindent |D U|\qquad When these switches are set, the constants
^|DEBUG| (which make the Library add the debugging suite to a game)
and |USE_MODULES| (which speeds up compilation by linking in the Library
rather than recompiling it) are automatically defined. This is just a
convenience: it's a nuisance to keep adding and removing source code
lines to do the same thing.
\medskip\noindent
This leaves three more switches which actually alter the game file which
Inform would compile:
\medskip
\noindent |d|\qquad 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. Stepping up to |-d2|
also contracts double spaces after question or exclamation
marks.^^{double spacing}
\noindent |e|\qquad 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|\qquad Makes 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.^^{debugging: tracing calls to every routine in game}
\danger\ninepoint
There are two directives for setting switches, to be used if there's
no other convenient way on your system (for example if you have a poor
windowed front end and no command line to type on). These are:
\begindisplay
|Switches |\<some settings>|;|\cr
|Version |\<number>|;|\cr
\enddisplay
These can only be used as first lines in the program and are illegal once
other directives or routines have been given. Note that
\beginstt
Version 6;
\endtt
(for instance) is redundant, as it is equivalent to
\beginstt
Switches v6;
\endtt
\bigskip
\danger\ninepoint%
Inform's memory management is very flexible, but sometimes needs attention
from the user, rather than being able to tinker with itself automatically.
This is unfortunate but Inform has to run in some quite hostile
environments and is obliged to be cautious.
\ninepoint
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 three main choices: |$small|, |$large| and |$huge|. (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| compiles
almost anything and |$huge| has been used only for ^{`Curses'} and
^{`Jigsaw'} in their most advanced states, and even they hardly need it.
A typical game, compiled with |$large|, will cause Inform to allocate about
350K 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 210K (on my
computer). Thus, the total memory consumption of the compiler at work
will be about 500K.^^{memory: small, large or huge}
^^{memory: typical consumption of by compiler}\
Running
\beginstt
inform $list
\endtt^^{memory}
^^{memory: compiler 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^^{error messages: memory allocation}
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.
Users of Unix, where |$| and |?| are special shell characters, will need
to type
\beginstt
inform '$?list' inform '$?MAX_VERBS'
\endtt
and so on.
\tenpoint
\section{6}{All the Inform error messages}^^{error messages (list of)}%
Three kinds of error are reported by Inform: a ^{fatal error} is a breakdown
severe enough to make Inform stop working at once; an ^{error} allows Inform
to continue for the time being, but will cause Inform not to finally output
the story file (this is to prevent damaged story files being created); and
a ^{warning} means that Inform suspects you may have made a mistake, but will
not take any action itself.
\ninepoint
\subsection{Fatal errors}\medskip\noindent
\medskip\noindent 1. {\sl Too many errors}
\beginlines
|Too many errors: giving up|
\endlines^^{error messages: fatal errors}^^{too many errors}
After 100 errors, Inform stops (in case it has been given the wrong source file
altogether, such as a program for a different language altogether).
\medskip\noindent 2. {\sl Input/output problems}
\par\noindent Most commonly, Inform has the wrong filename:
\beginlines
|Couldn't open input file <filename>|
|Couldn't open output file <filename>|
\endlines
(and so on). More seriously the whole process of file input/output (or ``I/O'')
may go wrong for some reason to do with the host computer: for instance, if it
runs out of disc space. Such errors are rare and look like this:
\beginlines
|I/O failure: couldn't read from temporary file 2|
\endlines
Normally you can only have at most 64 files of source code in a single
compilation. If this limit is passed, Inform generates the error
\beginlines
|Program contains too many source files: increase #define MAX_SOURCE_FILES|
\endlines
(This might happen if the same file accidentally |Include|s itself.) Finally,
if a non-existent pathname variable is set in ICL, the error
\beginlines
|No such path setting as <name>|
\endlines
is generated.
\medskip\noindent 3. {\sl Running out of memory}^^{running out of memory}
\par\noindent If there is not enough memory even to get started,
the following appear:
\beginlines
|Run out of memory allocating <number> bytes for <something>|
|Run out of memory allocating array of <number>x<number> bytes for <something>|
\endlines
(There are four similar |hallocate| errors unique to the PC `Quick C' port.)
More often memory 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^^{error messages: memory allocation}
(For details of memory settings, see \S 5 above.) In a really colossal game,
it is just conceivable that you might hit
\beginlines
|One of the memory blocks has exceeded 640K|
\endlines
which would need Inform to be recompiled to get around (but I do not expect
anyone ever to have this trouble). Much more likely is the error
\beginlines
|The story file/module exceeds version <n> limit (<number>K) by <number> bytes|
\endlines
If you're already using version 8, then the story file is full: you might be
able to squeeze more game in using the ^|Abbreviate| directive, but basically
you're near to the maximum game size possible. Otherwise, the error suggests
that you might want to change the version from 5 to 8, and the game will be
able to grow at least twice as large again.
\bigskip
\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. The most common error
by far takes the form
\beginstt
Expected ... but found ...
\endtt
(of which there are over 100 kinds): most are straightforward to sort out,
but a few take some practice. One of the trickiest things to diagnose is
a loop statement having been misspelt. For example, the lines
\beginstt
pritn "Hello";
While (x==y) print "x is still y^";
\endtt
produce one error each:
\beginstt
line 1: Error: Expected assignment or statement but found pritn
line 2: Error: Expected ';' but found print
\endtt
The first is fine. The second is odd: a human immediately sees that
|While| is meant to be a |while| loop, but Inform is not able to make
textual guesses like this. Instead Inform decides that the code intended was
\beginstt
While (x==y); print "x is still y^";
\endtt
with |While| assumed to be the name of a function which hasn't been declared yet.
Thus, Inform thinks the mistake is that the |;| has been missed out.
In that example, Inform repaired the situation and was able to carry on as normal
in subsequent lines. But it sometimes happens that a whole cascade of errors
is thrown up, in code which the user is fairly sure must be nearly right. What
has happened is that one syntax mistake threw Inform off the right track, so that
it continued not to know where it was for many lines in a row. Look at the first
error message, fix that and then try again.
\medskip\noindent 1. {\sl Reading in the source-code}
\beginlines
|Illegal character found in source: (char) <hexadecimal number>|
|Unrecognised combination in source: <text>|
|Alphabetic character expected after <text>|
|No such accented character as <text>|
|Name exceeds the maximum length of <number> characters: <name>|
|The following name is reserved by Inform for its own use as a routine name;|
| you can use it as a routine name yourself (to override the standard|
| definition) but cannot use it for anything else: <name>|
|The obsolete '#w$word' construct has been removed|
|Binary number expected after '$$'|
|Hexadecimal number expected after '$'|
|Too much text for one pair of 's to hold|
|Too much text for one pair of "s to hold|
\endlines
Note that, for instance, a |^| character is illegal in ordinary source
code (producing the first error above), but is allowed within quotation
marks.
\medskip\noindent 2. {\sl Variables and arrays}
\beginlines
|Variable must be defined before use: <name>|
|'=' applied to undeclared variable|
|Local variable defined twice: <name>|
|All 236 global variables already declared|
|No array size or initial values given|
|Array sizes must be known now, not externally defined|
|An array must have a positive number of entries|
|A 'string' array can have at most 256 entries|
|Entries in byte arrays and strings must be known constants|
|Missing ';' to end the initial array values before "[" or "]"|
\endlines
The limit of 236 global variables is absolute: a program even approaching this
limit should probably be making more use of object properties to store its
information. ``Entries... must be known constants'' is a restriction on what
byte or string arrays may contain: basically, numbers or characters; defined
constants (such as object names) may only be used if they have already been
defined. This restriction does not apply to the more normally used word and
table arrays.
\medskip\noindent 3. {\sl Routines and function calls}
\beginlines
|No 'Main' routine has been defined|
|It is illegal to nest routines using '#['|
|A routine can have at most 15 local variables|
|Argument to system function missing|
|System function given with too many arguments|
|Only constants can be used as possible 'random' results|
|A function may be called with at most 7 arguments|
|Duplicate definition of label: <name>|
\endlines
Note that the system function |random|, when it takes more than one
argument, can only take constant arguments (this enables the possibilities
to be stored efficiently within the program). Thus
|random(random(10), location)| will produce an error. To make a
random choice between non-constant values, write a |switch| statement instead.
\medskip\noindent 4. {\sl Expressions and arithmetic}
\beginlines
|Missing operator: inserting '+'|
|Evaluating this has no effect: <operator>|
|'=' applied to <operator>|
|Brackets mandatory to clarify order of: <operator>|
|Missing operand for <operator>|
|Missing operand after <something>|
|Found '(' without matching ')'|
|No expression between brackets '(' and ')'|
|'or' used improperly|
|Division of constant by zero|
|Label name used as value: <name>|
|System function name used as value: <name>|
|No such constant as <name>|
\endlines
``Operators'' include not only addition |+|, multiplication |*| and so on,
but also more exotic Inform constructs like |-->| (``array entry'') and
|.| (``property value''). An example of an operator where ``Evaluating
this has no effect'' is in the statement
\beginstt
34 * score;
\endtt
where the multiplication is a waste of time, since nothing is done with the
result. ``$=$ applied to operator'' means something like
\beginstt
(4 / fish) = 7;
\endtt
which literally means ``set $4/$|fish| to 7'' and results in the error
``$=$ applied to $/$''.
``Brackets mandatory to clarify order'' means that an ambiguous expression
like
\beginstt
frogs == ducks == geese
\endtt
requires clarification: which |==| is to be worked out first?
\medskip\noindent 5. {\sl Miscellaneous errors in statements}
\beginlines
|'do' without matching 'until'|
|'default' without matching 'switch'|
|'else' without matching 'if'|
|'until' without matching 'do'|
|'break' can only be used in a loop or 'switch' block|
|At most 32 values can be given in a single 'switch' case|
|Multiple 'default' clauses defined in same 'switch'|
|'default' must be the last 'switch' case|
|'continue' can only be used in a loop block|
|A reserved word was used as a print specification: <name>|
|No lines of text given for 'box' display|
|In Version 3 no status-line drawing routine can be given|
|The 'style' statement cannot be used for Version 3 games|
\endlines
For instance, |print (fixed) X| gives the ``reserved word in print
specification'' error because |fixed| is a reserved statement internal
keyword. Anyway, call such a printing routine something else.
\medskip\noindent 6. {\sl Object and class declarations}
\beginlines
|Two textual short names given for only one object|
|The syntax '->' is only used as an alternative to 'Nearby'|
|Use of '->' (or 'Nearby') clashes with giving a parent|
|'->' (or 'Nearby') fails because there is no previous object|
|'-> -> ...' fails because no previous object is deep enough|
|Two commas ',' in a row in object/class definition|
|Object/class definition finishes with ','|
|Not an individual property name: <name>|
|No such property name as <name>|
|Not a (common) property name: <name>|
|Property should be declared in 'with', not 'private': <name>|
|Limit (of 32 values) exceeded for property <name>|
|Duplicate-number not known at compile time|
|The number of duplicates must be 1 to 10000|
\endlines
Note that ``common properties'' (those provided by the library,
or those declared with |Property|) cannot be made |private|.
All other properties are called ``individual''. The ``number
of duplicates'' referred to is the number of duplicate instances
to make for a new class, and it needs to be a number Inform can
determine now, not later on in the source code (or in another
module altogether). The limit 10000 is arbitrary and imposed to
help prevent accidents.
\medskip\noindent 7. {\sl Grammar}
\beginlines
|Two different verb definitions refer to <name>|
|There is no previous grammar for the verb <name>|
|There is no action routine called <name>|
|No such grammar token as <text>|
|'=' is only legal here as 'noun=Routine'|
|Not an action routine: <name>|
|This is a fake action, not a real one: <name>|
|Too many lines of grammar for verb: increase #define MAX_LINES_PER_VERB|
\endlines
At present verbs are limited to 20 grammar lines each, though this
would be easy to increase. (A grammar of this kind of length
can probably be written more efficiently using general parsing
routines, however.)
\medskip\noindent 8. {\sl Conditional compilation}
\beginlines
|'Ifnot' without matching 'If...'|
|Second 'Ifnot' for the same 'If...' condition|
|End of file reached in code 'If...'d out|
|This condition can't be determined|
\endlines
``Condition can't be determined'' only arises for |Iftrue|
and |Iffalse|, which make numerical or logical tests: for instance,
\beginstt
Iftrue #strings_offset==$4a50;
\endtt
can't be determined because even though both quantities are
constants, the |#strings_offset| will not be known until compilation
is finished. On the other hand, for example,
\beginstt
Iftrue #version_number>5;
\endtt
can be determined, as the version number was set before compilation.
\medskip\noindent 9. {\sl Miscellaneous errors in directives}
\beginlines
|You can't 'Replace' a system function already used|
|Must specify 0 to 3 local variables for 'Stub' routine|
|A 'Switches' directive must come before the first constant definition|
|All 48 attributes already declared|
|All 62 properties already declared|
|'alias' incompatible with 'additive'|
|The serial number must be a 6-digit date in double-quotes|
|A definite value must be given as release number|
|A definite value must be given as version number|
|The version number must be in the range 3 to 8|
|All 64 abbreviations already declared|
|All abbreviations must be declared together|
|It's not worth abbreviating <text>|
|'Default' cannot be used in -M (Module) mode|
|'LowString' cannot be used in -M (Module) mode|
\endlines
\medskip\noindent 10. {\sl Linking and importing}
\beginlines
|File isn't a module: <name>|
|Link: action name clash with <name>|
|Link: program and module give differing values of <name>|
|Link: module (wrongly) declared this a variable: <name>|
|Link: this attribute is undeclared within module: <name>|
|Link: this property is undeclared within module: <name>|
|Link: this was referred to as a constant, but isn't: <name>|
|Link: <type> <name> in both program and module|
|Link: <name> has type <type> in program but type <type> in module|
|Link: failed because too many extra global variables needed|
|Link: module (wrongly) declared this a variable: <name>|
|Link: this attribute is undeclared within module: <name>|
|Link: this property is undeclared within module: <name>|
|Link: this was referred to as a constant, but isn't: <name>|
|'Import' cannot import things of this type: <name>|
|'Import' can only be used in -M (Module) mode|
\endlines
Note that the errors beginning ``Link:'' are exactly those occurring
during the process of linking a module into the current compilation.
They mostly arise when the same name is used for one purpose in the
current program, and a different one in the module.
\medskip\noindent 11. {\sl Assembly language}
\beginlines
|Label out of range for branch|
|Opcode specification should have form "VAR:102"|
|Unknown flag: options are B (branch), S (store),|
| T (text), I (indirect addressing), F** (set this Flags 2 bit)|
|Only one '->' store destination can be given|
|Only one '?' branch destination can be given|
|No assembly instruction may have more than 8 operands|
|This opcode does not use indirect addressing|
|Indirect addressing can only be used on the first operand|
|Store destination (the last operand) is not a variable|
|Opcode unavailable in this Z-machine version: <name>|
|Assembly mistake: syntax is <syntax>|
|Routine contains no such label as <name>|
|For this operand type, opcode number must be in range <range>|
\endlines
\medskip\noindent 12. {\sl None of the above}
\par \noindent If you should see an incomprehensible error
message beginning with |***|, then Inform itself has malfunctioned.
This is not meant to happen, but it's conceivable that it might occur
in the process of linking in a module which has been damaged in some way.
Finally, error messages can also be produced from within the program
(deliberately) using |Message|. It may be that a mysterious message
is being caused by an included file written by someone other than yourself.
\bigskip
\subsection{Warnings}\medskip\noindent^^{warning messages (list)}
\medskip\noindent 1. {\sl Questionable practices}
\beginlines
|This statement can never be reached|
\endlines^^{statement cannot be reached}
There is no way that the statement being compiled can ever be executed when the
game is played. Here is an obvious example:
\beginstt
return; print "Goodbye!";
\endtt
where the |print| statement can never be reached, because a |return| must just
have happened. Beginners often run into this example:
\beginstt
"You pick up the gauntlet."; score=score+1; return;
\endtt
Here the |score=score+1| statement is never reached because the text, given on
its own, means ``print this, then print a new-line, then return from the current
routine''. The intended behaviour needs something like
\beginstt
print "You pick up the gauntlet.^"; score=score+1; return;
\endtt\medskip
\beginlines
|<type> <name> declared but not used|
\endlines
For example, a |Global| directive was used to create a variable, which was then
never used in the program.
\beginlines
|'=' used as condition: '==' intended?|
\endlines
Although a line like
\beginstt
if (x = 5) print "My name is Alan Partridge.";
\endtt
is legal, it's probably a mistake: |x=5| sets |x| to 5 and results in 5, so the
condition is always true. Presumably it was a mistype for |x==5| meaning ``test
|x| to see if it's equal to 5''.
\beginlines
|Unlike C, Inform uses ':' to divide parts of a 'for' loop|
| specification: replacing ';' with ':'|
\endlines
Programmers used to the C language will now and then habitually type a |for|
loop in the form
\beginstt
for (i=0; i<10; i++) ...
\endtt
but Inform needs colons, not semicolons: however, as it can see what was intended,
it makes the correction automatically and issues only a warning.
\beginlines
|Missing ','? Property data seems to contain the property name <name>|
\endlines
The following, part of an object declaration, is legal but unlikely:
\beginstt
with found_in MarbleHall
short_name "conch shell", name "conch" "shell",
\endtt
As written, the |found_in| property has a list of three values: |MarbleHall|,
|short_name| and |"conch shell"|. |short_name| throws up the warning because
Inform suspects that a comma was missed out and the programmer intended
\beginstt
with found_in MarbleHall,
short_name "conch shell", name "conch" "shell",
\endtt
\beginlines
|This is not a declared Attribute: <name>|
\endlines
Similarly, suppose that a game contains a |pen|. Then the following |give|
statement is dubious but legal:
\beginstt
give MarbleDoorway pen;
\endtt
The warning is caused because it's far more likely to be a misprint for
\beginstt
give MarbleDoorway open;
\endtt
\beginlines
|Without bracketing, the minus sign '-' is ambiguous|
\endlines
For example,
\beginstt
Array Doubtful --> 50 10 -20 56;
\endtt
because Inform is not sure whether this contains three entries, the middle one
being $10-20=-10$, or four. It guesses four, but suggests brackets to clarify
the situation.
\beginlines
|Array entry too large for a byte|
\endlines^^{questionable practices}
Byte |->| and |string| arrays can only hold numbers in the range 0 to 255.
If a larger entry is supplied, only the remainder mod 256 is stored, and this
warning is issued.
\beginlines
|Verb disagrees with previous verbs: <verb>|
\endlines
The |Extend only| directive is used to cleave off a set of synonymous English
verbs and make them into a new Inform verb. For instance, ordinarily ``take'',
``get'', ``carry'' and ``hold'' are one single Inform verb, but this directive
could split off ``carry'' and ``get'' from the other two. The warning would
arise if one tried to split off ``take'' and ``drop'' together, which come from
different original Inform verbs. (It's still conceivably usable, which is why
it's a warning, not an error.)
\beginlines
|This does not set the final game's statusline|
\endlines
An attempt to choose, e.g., |Statusline time| within a module, having no effect
on the program into which the module will one day be linked. Futile.
\beginlines
|This module has a more advanced format than this release of the|
| Inform 6 compiler knows about: it may not link in correctly|
\endlines
\medskip\noindent 2. {\sl Obsolete usages}^^{obsolete usages}
\beginlines
|more modern to use 'Array', not 'Global'|
|use '->' instead of 'data'|
|use '->' instead of 'initial'|
|use '->' instead of 'initstr'|
|use 'word' as a constant dictionary address|
|'#a$Act' is now superceded by '##Act'|
|'#n$word' is now superceded by ''word''|
|'#r$Routine' can now be written just 'Routine'|
|all properties are now automatically 'long'|
|use the ^ character for the apostrophe in <dictionary word>|
\endlines
These all occur if Inform compiles a syntax which was correct under Inform
5 (or earlier) but has now been withdrawn in favour of something better.
\ddanger No Inform library file (or any other file marked |System_file|)
produces warning messages. It may contain many declared but unused routines,
or may contain obsolete usages for the sake of backward
compatibility.^^|System file|
\tenpoint
\chapter{Chapter III: Fundamentals}
\section{7}{Getting started}
\poem
Nothing so difficult as a beginning
In poesy, unless perhaps the end.
\poemby{^{Lord Byron} ({\oldstyle1788}--{\oldstyle1824})}{Don Juan, IV iv}
\noindent
The examples in Chapters III and IV of this manual will put together
a small game called ^{`Ruins'}. Its first state is very close to
the minimal ^{`Shell'} game supplied with Inform:
\beginstt
Constant Story "RUINS";
Constant Headline "^An Interactive Worked Example^
Copyright (c) 1995 by Graham Nelson.^";
Include "Parser";
Include "VerbLib";
Object Forest "Dark Forest"
with description
"In this tiny clearing, the pine-needle carpet is broken by
stone-cut steps leading down into darkness. Dark olive
trees crowd in on all sides, the air steams with warm recent
rain, midges hang in the air.",
has light;
[ Initialise;
location = Forest;
"^^^^^Days of searching, days of thirsty hacking through the briars of
the forest, but at last your patience was rewarded. A discovery!^";
];
Include "Grammar";
\endtt
If you can compile this successfully, Inform is probably set up and working
properly on your computer. Compilation may take a few seconds, because the
game `includes' three library files which contain a great deal more code.
These files are themselves written in Inform
and contain the core of ordinary rules common to all games:
\medskip
\settabs 6 \columns
\+ & ^|Parser| & a program for decoding what the player types;\cr
\+ & ^|VerbLib| & how verbs, like ``take'' or ``drop'', work;\cr
\+ & ^|Grammar| & the grammar table, or what the Parser understands.\cr
\medskip\noindent
(If compilation is annoyingly slow, it should be easy enough to ``link the
library files'', which is much faster: see \S 4.3) Apart from the
inclusions, `Ruins' contains:
\medskip
\item{(a)} strings (that is, quoted text) giving the game's name and a
^{copyright message}, to be printed out when appropriate;
\item{(b)} a routine, called ^|Initialise|, which is run when the game begins,
and simply sets where the player starts (not that there's much choice yet!)
and prints a ^{`welcome' message};
\item{(c)} an object, so far the only room.
\medskip
\par\noindent `Ruins' is at this stage an extremely dull game:
\beginlines
|Days of searching, days of thirsty hacking through the briars of the forest,|
|but at last your patience was rewarded. A discovery!|
||
|RUINS|
|An Interactive Worked Example|
|Copyright (c) 1995 by Graham Nelson.|
|Release 1 / Serial number 960825 / Inform v6.04 Library 6/1|
||
|Dark Forest|
|In this tiny clearing, the pine-needle carpet is broken by stone-cut steps|
|leading down into darkness. Dark olive trees crowd in on all sides, the air|
|steams with warm recent rain, midges hang in the air.|
||
|>i|
|You are carrying nothing.|
||
|>north|
|You can't go that way.|
||
|>wait|
|Time passes.|
||
|>quit|
|Are you sure you want to quit? yes|
\endlines
\par\noindent (The ``Release'' number is 1 unless you set it otherwise,
putting a directive like |Release 2;| into the source code. The
``Serial number'' is set by Inform to the date of compilation.)
\medskip\noindent
In an Inform game, ^{objects} are used to simulate everything: rooms and
items to be picked up, scenery, intangible things like mist and even
some abstract ideas (like the direction `north'). The library is
also present in every game, and can be thought of as a referee, or
umpire, rather than part of the game's world.
Our second object is added by writing the following just after the
|Forest| ends and just before |Initialise| begins:^^{mushroom}
^^{speckled mushroom}
\beginlines
|Object -> mushroom "speckled mushroom"|
| with name "speckled" "mushroom" "fungus" "toadstool";|
\endlines
(The arrow |->| means that the mushroom begins inside the Forest
rather than alongside it.) If the game is recompiled, the mushroom
is now in play: the player can call it ``speckled mushroom'',
``mushroom'', ``toadstool'' and so on. It can be taken, dropped,
looked at, looked under and so on. However, it only adds the rather
plain line ``There is a speckled mushroom here.'' to the Forest's
description. So here is a more lavish version:
\beginlines
|Object -> mushroom "speckled mushroom"|
| with name "speckled" "mushroom" "fungus" "toadstool",|
| initial|
| "A speckled mushroom grows out of the sodden earth, on a long stalk.";|
\endlines
The ^|initial| message is used to tell the player about the mushroom when
the Forest is described. (Once the mushroom has been picked or moved, the
message is no longer used: hence the name `initial'.) The mushroom is,
however, still ``nothing special'' when the player asks to ``look at'' or
``examine'' it. To provide a more interesting close-up view, we must give
the mushroom its own |description|:
\beginlines
|Object -> mushroom "speckled mushroom"|
| with name "speckled" "mushroom" "fungus" "toadstool",|
| initial|
| "A speckled mushroom grows out of the sodden earth, on a long stalk.",|
| description|
| "The mushroom is capped with blotches, and you aren't at all sure|
| it's not a toadstool.",|
| has edible;|
\endlines
Now if we examine the mushroom, as is always wise before eating, we get a
cautionary hint; still, thanks to the |edible| notation, we're now able
to eat it.
These show the two kinds of feature something can have: a ``property'',
which has some definite value or list of values (such as |name|), and
an ``attribute'', which is either present or not but has no particular
value (such as |edible|). Values of properties change during play,
and attributes come and go. For instance,
\beginstt
mushroom.description = "You're sure it's a toadstool now.";
give mushroom general;
if (mushroom has edible) print "It's definitely edible.^";
\endtt
manipulate the attributes and properties. (^|general| is the name used
for an attribute with no particular meaning to the game, but which is
left free for your program to use as it likes. Similarly, ^|number|
is a general-purpose property.)^^{properties}^^{attributes}
We can go much further with form-filling like this, but for the sake of
example we'll begin some honest programming by adding the following
property to the mushroom:
\beginlines
| after|
| [; Take: "You pick the mushroom, neatly cleaving its thin stalk.";|
| Drop: "The mushroom drops to the ground, battered slightly.";|
| ],|
\endlines
The property ^|after| doesn't just have a string for a value: it has a
routine of its own. Now after something happens to the mushroom,
the |after| routine is called to see if any special rules apply. 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.
The game can now manage a brief but plausible dialogue:
\beginlines
|Dark Forest|
|In this tiny clearing, the pine-needle carpet is broken by stone-cut steps|
|leading down into darkness. Dark olive trees crowd in on all sides, the air|
|steams with warm recent rain, midges hang in the air.|
|A speckled mushroom grows out of the sodden earth, on a long stalk.|
|>get mushroom|
|You pick the mushroom, neatly cleaving its thin stalk.|
|>look at it|
|The mushroom is capped with blotches, and you aren't at all sure it's not a|
|toadstool.|
|>drop it|
|The mushroom drops to the ground, battered slightly.|
\endlines
The mushroom is a little more convincing now, but still passive.
We can give it a somewhat sad new rule by adding yet another property,
this time with a more substantial routine:
\beginlines
| before|
| [; Eat: if (random(100) <= 30)|
| { deadflag = 1;|
| "The tiniest nibble is enough. It was a toadstool,|
| and a poisoned one at that!";|
| }|
| "You nibble at one corner, but the curious taste repels you.";|
| ],|
\endlines^^{routines: simple example of}
The |before| routine is called before the player's intended action takes
place. So when the player tries typing, say, ``eat the mushroom", what happens
is: in 30\% of cases, she dies of ^{toadstool poisoning}; and in the other
70\%, she simply nibbles a corner of fungus (without consuming it
completely).
\danger Like many programming languages, Inform braces together blocks of
code so that several statements can come under the |if| condition.
^|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.
Note that if the first text is printed, the rule ends there, and does
not flow on into the second text. So one and only one message is printed.
Here is how this is achieved: although it's not obvious from the look of
the program, the |before| routine is being asked the question
``Do you want to interfere with the usual rules?''. It must reply,
that is, ``return'', either ``true'' or ``false'' meaning yes or no.
Because this question is asked and answered many times in a large Inform
game, there are several abbreviations for how to reply. For example,
\beginstt
return true;
rtrue;
\endtt
both do the same thing. Moreover,
\beginstt
print_ret "The tiniest nibble... ...at that!";
\endtt
performs three useful tasks: prints the message, then prints a carriage
return, and then returns true. And this is so useful that a bare string
\beginstt
"The tiniest nibble... ...at that!";
\endtt
is understood to mean the same thing. To just print the text, the
statement |print| has to be written out in full. Here is an example:
\beginlines
| before|
| [; Taste: print "You extend your tongue nervously.^";|
| rfalse;|
| ];|
\endlines
In this rule, the text is printed, but the answer to ``Do you want
to interfere?'' is no, so the game will then go on to print something
anodyne like ``You taste nothing unexpected.'' (In fact the |rfalse|
was unnecessary, because if a rule like this never makes any
decision, then the answer is assumed to be ``false''.)
\exercise The present |after| routine for the mushroom is misleading,
because it says the mushroom has been picked every time it's taken (which
will be odd if it's taken, dropped then taken again). Correct this to
complete the definition of the `Ruins'
mushroom.^^{exercises: mushroom picking}
\answer{^^{exercises: mushroom picking}
Change the mushroom's |after| rule to:
\beginstt
after
[; Take: if (self hasnt general)
{ give self general;
"You pick the mushroom, neatly cleaving its thin stalk.";
}
"You pick up the slowly-disintegrating mushroom.";
Drop: "The mushroom drops to the ground, battered slightly.";
],
\endtt
As mentioned above, |general| is a general-purpose attribute, free for the
designer to use. The `neatly cleaving' message can only happen once, because
after that the mushroom object must have |general|. Note that the mushroom
is allowed to call itself |self| instead of |mushroom|.}
\danger More generally, some |before| or |after| rules ought to apply only
once in the course of a game. For instance, examining the tapestry reveals
a key, only once. A sneaky way to do this is to make the appropriate rule
destroy itself, so for example
\beginstt
tapestry.before = NULL;
\endtt^^|NULL|^^{once-only rules}^^{removing rules}^^{tapestry and key}
removes the entire |before| rule for the tapestry. |NULL| is a special
value, which the properties |before|, |after|, |life| and |describe|
hold to indicate ``none''.
\bigskip\noindent
Here is another typical object definition:
\beginstt
Object "stone-cut steps" Forest
with name "steps" "stone" "stairs" "stone-cut",
description
"The cracked and worn steps descend into a dim chamber. Yours
might be the first feet to tread them for five hundred years.",
door_to Square_Chamber,
door_dir d_to
has scenery door open;
\endtt^^{`Ruins'}^^{stone-cut steps}
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|. (Though |with| and
|has| can be given the other way round.)
\noindent
Note that the first line, the so-called header, is a little different
in form to those above. Firstly, it gives no ``program name'' for the
steps (in the way that |mushroom| was given as program-name for the
speckled mushroom) -- there is a blank in between the |Object| directive
and the text of the words ``short-cut steps''. This is perfectly legal,
and is sensible because the program never needs to refer to the steps
object directly. Secondly, the initial position of the steps is specified
not by using arrows |->| but by actually quoting the object it is to
be placed inside, the |Forest|. This is sometimes convenient and is only
legal if the |Forest| has already been defined (earlier on in the
program). Such a restriction is actually useful as it prevents you from
setting up a `loop' -- one object in another in a third in the first,
for instance.
\newpage
\section{8}{Introducing messages and classes}
\widepoem
On a round ball
A workman that hath copies by, can lay
An Europe, Afrique and an Asia,
And quickly make that, which was nothing, All.
\widepoemby{John Donne ({\oldstyle1571}?--{\oldstyle1631})}{Valediction: Of Weeping}
\noindent%
In fact, messages have already appeared in \S 7. Recall from \S 3
that a message called |messagename| can be sent to an object called
|objectname| with various supplied details (called |info1| and |info2|
here, though there can be any number from none to 6) as follows:
\beginstt
objectname.messagename(info1, info2);
\endtt
And the given object sends back a reply value (which is just a single
quantity). This is what is really happening when the player tries to
eat the mushroom: first the library sends the mushroom a |before| message
to warn it that something will happen; it might reply |true|, in which
case the library gives up; otherwise the eating takes place, and the
library sends an |after| message to inform the mushroom of its demise.
Properties like |before|, then, are really rules to deal with incoming
messages. The same applies to most of the properties in \S 3. For
example, the message
\beginstt
mushroom.description();
\endtt
is sent when the player tries to examine the mushroom: if the reply is
|false| then the game prints ``You see nothing special about the speckled
mushroom.'' Now the mushroom was set up with
\beginstt
description
"The mushroom is capped with blotches, and you aren't at all sure
it's not a toadstool.",
\endtt
which doesn't look like a rule for receiving a message, but it is one
all the same: it means ``print this text out, print a new-line and
reply |true|''. A more complicated rule could have been given instead,
as in the following elaboration of the ^{stone-cut steps} in ^{`Ruins'}:
\beginstt
description
[; print "The cracked and worn steps descend into a dim chamber.
Yours might ";
if (Square_Chamber has visited)
print "be the first feet to tread";
else print "have been the first feet to have trodden";
" them for five hundred years. On the top step is inscribed
the glyph Q1.";
],
\endtt^^{properties: holding routines}^^{routines: as property values}
|visited| is an attribute which is currently held only by rooms which
the player has been to. (The glyphs will be explained later on, as will
the |SquareChamber| room, which is where the steps will lead down into.)
The library, i.e., the standard game rules, can send out about 40
different kinds of message, |before| and |description| being two of these.
The more interesting an object is, the more ingeniously it will respond
to these messages: an object which ignores all incoming messages will be
lifeless and inert in play, like a small stone.
\ddanger In fact there are subtle differences between how the library
uses properties, and message-sending: the |name| property, for example,
is not really a message-receiver but is just what it appears
to be -- a list of useful data. Also, the library is careful not
to send (for instance) a |description| message to an object which doesn't
provide a rule for what to do with one. But the idea is right.
So the library is sending out messages to your objects all the time
during play. Your objects can also send each other messages, including
``new'' ones that the library would never send. It's sometimes
convenient to use these to trigger off happenings in the game.
For example, suppose the ^{`Ruins'} are home to a ^{parrot} which
squawks from time to time, for a variety of reasons:
\beginstt
Object -> parrot "red-tailed parrot"
with name "red" "tailed" "red-tailed" "parrot" "bird",
description
"Beautiful plumage.",
squawk
[ utterance;
if (self in location)
print "The parrot squawks, ~", (string) utterance,
"! ", (string) utterance, "!~^";
],
has animate;
\endtt^^{red-tailed parrot}^^{squawking}^^{messages: parrot example}
We might then, for instance, change the |after| rule for dropping the
mushroom to read:
\beginstt
Drop: parrot.squawk("Drop the mushroom");
"The mushroom drops to the ground, battered slightly.";
\endtt
so that the wretched creature would squawk ``Drop the mushroom! Drop the
mushroom!'' each time this was done. Likewise, |squawk| messages could
be sent for any number of other reasons connected with other objects.
But at present it would be an error to send a |squawk| message to any
object other than the parrot, since only the parrot has been given a
rule telling it what to do if it receives one.
\exercise Make a ^{medicine bottle}, which can be opened in a variety
of ways in the game, so that the opening--code only occurs once in
the bottle definition.^^{exercises: opening medicine bottle}
\answer{^^{exercises: opening medicine bottle}
\beginlines
|Object medicine "guaranteed child-proof medicine bottle" cupboard|
| with name "medicine" "bottle",|
| description "~Antidote only: no preventative effect.~",|
| openup|
| [; give self open ~locked; "The bottle cracks open!";|
| ],|
| has container openable locked;|
\endlines
Any other code in the game can send the message |medicine.openup()|
to crack open the bottle. For brevity, this solution assumes that
the bottle is always visible to the player when it is opened -- if not
the printed message will be incongruous.}
\bigskip\noindent%
In most games there are groups of objects with certain rules in common,
which it would be tiresome to have to write out many times. For
making such a group, a class definition is the better technique.
These closely resemble object definitions, but since they define prototypes
rather than actual things, they have no initial location. (An individual
tree may be somewhere, but the concept of being a tree has no
particular place.) So the `header' part of the definition is simpler.
For example, the scoring system in ^{`Ruins'}^^{scoring in `Ruins'}\
works as follows: the player, an archaeologist of the old school,
gets a certain number of points for each `treasure' (i.e., cultural
artifact) he can filch and put away into his packing case. This is
implemented with the following class:
\beginlines
| Class Treasure|
| with cultural_value 10,|
| after|
| [; Insert:|
| if (second==packing_case)|
| score = score + self.cultural_value;|
| "Safely packed away.";|
| ],|
| before|
| [; Take, Remove:|
| if (self in packing_case)|
| "Unpacking such a priceless artifact had best wait|
| until the Metropolitan Museum can do it.";|
| ];|
\endlines^^{treasure class}^^{Metropolitan Museum}
Note that |self| is a variable, which always means ``whatever object
I am''. If we used it in the definition of the mushroom it would mean
the mushroom: used here, it means whatever treasure happens to be
being dealt with.
(Explanations about |Insert| and |Remove| will come later, but hopefully
the idea is clear enough.) An object of the class |Treasure| inherits
the properties and attributes it defines: in this case, an object of class
|Treasure| picks up the given score and rules automatically. So
\beginlines
|Treasure statuette "pygmy statuette"|
| with description|
| "A menacing, almost cartoon-like statuette of a pygmy spirit|
| with a snake around its neck.",|
| initial "A precious Mayan statuette rests here!",|
| name "snake" "mayan" "pygmy" "spirit" "statue" "statuette";|
\endlines^^{pygmy statuette}^^{cultural value}
inherits the |cultural_value| score of 10 and the rules about taking
and dropping. If the statuette had itself set |cultural_value| to 15, say,
then the value would be 15, because the object's actual definition always
takes priority over anything the class might have specified.
A more unusual artifact:
\beginlines
|Treasure honeycomb "ancient honeycomb"|
| with article "an",|
| name "ancient" "old" "honey" "honeycomb",|
| description "Perhaps some kind of funerary votive offering.",|
| initial "An exquisitely preserved, ancient honeycomb rests here!",|
| after|
| [; Eat: "Perhaps the most expensive meal of your life. The honey|
| tastes odd, perhaps because it was used to store the entrails|
| of the king buried here, but still like honey.";|
| ],|
| has edible;|
\endlines^^{ancient honeycomb}^^{honeycomb}
The honeycomb now has two |after| rules: a new one of its own, plus the
existing one that all treasures have. Both apply, but the new one happens
first.^^{classes: inheritance rules}^^{precedence of class inheritance}
\danger So comparing |cultural_value| and |after|, there seems to be an
inconsistency. In the first case, an object's own given value wiped out
the value from the class, but in the second, the two values were joined
up into a list. Why? The reason is that some of the library's properties
are special (again) in being what's called ``^{additive}'', so that their
values accumulate into a list when class inheritance takes place. The
three useful examples are |before|, |after| and |name|.
^^{classes: and additive properties}^^{properties: additive}
\ddanger Non-library properties you invent (like |squawk| or
|cultural_value|) will never be additive, unless you write a directive
like:
\beginstt
Property additive squawk;
\endtt
(before |squawk| is otherwise mentioned) to say so.
\noindent Finally, note that an object can inherit from several
classes at once (see \S 3 for how to give such a definition). Moreover,
a class can itself inherit from other classes, so it's easy to make a
class for ``like Treasure but with |cultural_value| normally 8 instead
of 10''.^^{classes: and subclasses}
\refs See ^{`Balances'} for an extensive use of message-sending.
\nextref
^{`Advent'} has a treasure-class similar to this one, and uses
class definitions for the many similar maze and dead-end rooms
(and the sides of the fissure).
\nextref
That class definitions can be worthwhile even when only two
objects use them, can be seen from the kittens-class in
^{`Alice Through The Looking-Glass'}.
\nextref ^{`Balances'} defines many complicated classes:
see especially the white cube, spell and scroll classes.
\nextref ^{`Toyshop'} contains one easy one (the wax candles) and
one unusually hard one (the building blocks).
\newpage
\section{9}{Actions and reactions}
\widepoem
Only the actions of the just
Smell sweet and blossom in their dust.
\widepoemby{^{James Shirley} ({\oldstyle1594}--{\oldstyle1666})}{The Contention of Ajax and Ulysses}
\widequote
..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.
\widepoemby{^{Donna Tartt}}{The Secret History}
\noindent
Inform is a language obsessed with ^{actions}. An `action' is an attempt
to perform one simple task: for instance,
\begindisplay
|Inv| \qquad |Take sword|\qquad |Insert gold_coin cloth_bag|
\enddisplay
are all examples. Here the actual actions are |Inv|, |Take| and
|Insert|. An action has 0, 1 or 2 objects supplied
with it (or, in a few special cases, some numerical information rather than
objects). Most actions are triggered off by the game's parser: in fact,
the parser's job can be summed up as reducing the player's keyboard
commands to actions. Sometimes one action causes another; a really
complicated keyboard command (``empty the sack into the umbrella stand'')
may fire off quite a sequence of actions.
An action is only an attempt to do something: it may not succeed.
Firstly, a |before| rule might interfere, as we have seen already.
Secondly, the action might not even be very sensible. The parser will
happily generate the action |Eat iron_girder| if the player asked to do
so in good English. In this case, even if no |before| rule interferes,
the normal game rules will ensure that the girder is not consumed.
Actions can also be generated by your own code, and this perfectly
simulates the effect of a player typing something. For example,
generating a |Look| action makes the game produce a room description
as if the player had typed ``look''. More subtly, suppose the air
in the ^{Pepper Room} causes the player to sneeze each turn and drop
something at random. This could be programmed directly, with objects
being moved onto the floor by explicit |move| statements. But then
suppose the game also contains a toffee apple, which sticks to the
player's hands. Suddenly the toffee apple problem has an unintended
solution. So rather than moving the objects directly to the floor,
the game should generate |Drop| actions. The result might read:
\begindisplay
You sneeze convulsively, and lose your grip on the toffee apple...\cr
The toffee apple sticks to your hand!\cr
\enddisplay
which is at least consistent.
As an example of causing actions, an odorous |low_mist| will soon settle over
^{`Ruins'}. It will have the |description| ``The mist carries a
rich aroma of broth.'' The alert player who reads this will immediately
type ``smell mist'', and we want to provide a better response than the game's
stock reply ``You smell nothing unexpected.'' An economical way of doing this
is to somehow deflect the action |Smell low_mist| into the action
|Examine low_mist| instead, so that the ``aroma of broth'' message is
printed in this case too. Here is a suitable |before| rule to do that:
\beginstt
Smell: <Examine self>; rtrue;
\endtt^^{actions: statements to cause}
The statement |<Examine self>| causes the action |Examine low_mist| to be
triggered off immediately, after which whatever was going on at the time
resumes. In this case, the action |Smell low_mist| resumes, but since we
immediately return |true| the action is stopped dead.
Causing an action and then returning |true| (i.e., causing a new action
and killing the old one) is so useful that it has an abbreviation,
putting the action in double angle-brackets. For example,
\beginstt
<Look>; <<ThrowAt smooth_stone spider>>;
\endtt
will behave as if the player has asked to look around and to throw
the stone at the spider, and will then return |true|.
\medskip\noindent
At any given time, just one action is under way (though others
may be waiting to resume when the current one has finished). This
current action is stored in the three variables
\beginstt
action noun second
\endtt
|noun| and |second| hold the objects involved, or the special
value |nothing| if they aren't involved at all. |action| holds
the kind of action. Its possible values can be referred to in
the program using the |##| notation: for example
\beginstt
if (action == ##Look) ...
\endtt
tests to see if the current action is a |Look|.
\danger Why have |##| at all, why not just write |Look|? Partly
because this way the reader can see at a glance that an action
type is being referred to, but also because the name might be
wanted for something else. For instance there's a variable called
|score| (holding the current game score), quite different from
the action type |##Score|.
\ddanger For a few actions, the `noun' (or the `second noun') is
actually a number (for instance, ``set timer to 20'' would probably
end up with |noun| being |timer| and |second| being 20). Occasionally
one needs to be sure of the difference, e.g., to tell if |second|
is holding a number or an object. It's then useful to know that
there are two further variables, ^|inp1| and ^|inp2|, parallel to
|noun| and |second| and usually equal to them -- but equal to 1 to
indicate ``some numerical value, not an object''.
\bigskip
\noindent
The library supports about 120 different actions and any game of serious
proportion will add some more of its own. This list is initially daunting
but many are used only rarely and others are always knocked down into
simpler actions (for example, |<Empty rucksack table>|, meaning
``empty the contents of the rucksack onto the table'', is broken down into
a stream of actions like |<Remove fish rucksack>| and |<PutOn fish table>|).
It's useful to know that an object can only enter the player's possession
through a |Take| or |Remove| action: block those two and it can never be
acquired whatever the player types.
The list of actions is traditionally divided into three groups, called
Group 1, Group 2 and Group 3.^^{actions: groups of}^^{groups of actions}\
Group 1 contains ^{`meta' actions} for controlling the game, like |Score|
and |Save|, which are treated quite differently from other actions and
are not worth listing. Of the rest, actions which normally do something
form Group 2, while actions which normally only print a polite refusal
form Group 3. Group 2 contains:
\beginstt
Inv, Take, Drop, Remove, PutOn, Insert, Enter, Exit, Go, Look, Examine,
Unlock, Lock, SwitchOn, SwitchOff, Open, Close, Disrobe, Wear, Eat, Search.
\endtt
It should be apparent why these do something. However, an action
like |Listen| falls into Group 3: the library would normally respond
to it by printing ``You hear nothing unexpected.'' Only if your program
interferes (using a |before| rule) can anything happen. Group 3 contains,
in rough order of usefulness:
\beginstt
Pull, Push, PushDir [push object in direction], Turn,
Consult, LookUnder [look underneath something], Search,
Listen, Taste, Drink, Touch, Smell,
Wait, Sing, Jump [jump on the spot], JumpOver, Attack,
Swing [something], Blow, Rub, Set, SetTo, Wave [something],
Burn, Dig, Cut, Tie, Fill, Swim, Climb, Buy, Squeeze,
Pray, Think, Sleep, Wake, WaveHands [i.e., just "wave"],
WakeOther [person], Kiss, Answer, Ask, ThrowAt,
Yes, No, Sorry, Strong [swear word], Mild [swear word]
\endtt
\danger Actions involving other people, like |Kiss|, are often best
dealt with by a |life| rule, which will be discussed in \S 16.
\danger A few actions (e.g., |Transfer|, |Empty|, |GetOff|) are omitted
from the list above because they're always translated into more familiar
ones. For instance, |InvWide| (asking for a ``wide--format'' inventory
listing) always ends up in an |Inv|.
\ddanger The ^|Search| action (generated by ``look inside \<container>''
or ``search \<something>'') only ever prints text, but is in Group 2
rather than Group 3 because it does something substantial. It decides
whether something is a container, and if there's enough light to see by,
it prints out the contents. Thus, a |before| rule applied to |Search|
traps the searching of random scenery, while an |after| can be used
to alter the contents-listing rules of containers.
\ddanger Most of the group 2 actions -- specifically,
\beginstt
Take, Drop, Insert, PutOn, Remove, Enter, Exit, Go, Unlock, Lock,
SwitchOn, SwitchOff, Open, Close, Wear, Disrobe, Eat
\endtt^^{silent actions}^^|keep silent|
can happen ``silently''. If the variable |keep_silent| is set to 1,
then these actions print nothing in the event of success. (E.g.,
if the door was unlocked as requested.) They print up objections
as usual if anything goes wrong (e.g., if the suggested key doesn't
fit). This is useful to implement implicit actions: for instance,
to code a door which will be automatically unlocked by a player
asking to go through it, who is holding the right key.
\bigskip
\noindent
The standard stock of actions is easily added to. Two things are
necessary to create a new action: first one must provide a routine
to make it happen. For instance:
\beginstt
[ BlorpleSub;
"You speak the magic word ~Blorple~. Nothing happens.";
];
\endtt^^{actions: creation of}
Every action has to have a ``subroutine'' like this, the name of which
is always the name of the action with |Sub| appended. Secondly,
one must add grammar so that |Blorple| can actually be called for.
Far more about grammar in Chapter V: for now we add the simplest of
all grammar lines, a directive^^{making grammar}
\beginstt
Verb "blorple" * -> Blorple;
\endtt
placed after the inclusion of the |Grammar| file. (The spacing around
the |*| is just a matter of convention.) The word ``blorple" can now
be used as a verb. It can't take any nouns, so the parser will complain
if the player types ``blorple daisy''.
^|Blorple| is now a typical Group 3 action. |before| rules can be
written for it, and it can be triggered off by a statement like
\beginstt
<Blorple>;
\endtt
\ddanger To make it a Group 1 action, define the verb as |meta| (see \S 26).
\ddanger To make it a Group 2 action, rewrite the subroutine in the
following form:
\beginstt
[ WhateverSub;
... do whatever the action is supposed to do,
printing a suitable message and returning
if it turns out not to be a sensible thing to do...
if (AfterRoutines()==1) rtrue;
... print a suitable message saying that it has been done ...
];
\endtt
(^|AfterRoutines| is a library routine which sends suitable |after|
messages to see if the objects want to prevent the usual message
being printed.)
\danger A few of the library's actions fall into none of Groups 1,
2 or 3, though these aren't proper actions at all, but are used
only to signal goings-on. For instance, when the player types
^{``throw rock at dalek''}, the parser generates the action
|ThrowAt rock dalek|. As usual the rock is sent a |before| message
asking if it objects to being thrown at a ^{Dalek}. Since the Dalek
may also have an opinion on the matter, another |before| message
is sent to the Dalek, but this time as if the action were something
called |ThrownAt|. For example, here is a dartboard's response to a
dart:
\beginstt
before
[; ThrownAt: if (noun==dart)
{ move dart to self; "Triple 20!"; }
move noun to location;
print_ret (The) noun, " bounces back off the board.";
],
\endtt^^{dartboard}^^|ThrownAt|^^|ThrowAt|
Such an imaginary action -- usually, as in this case, a perfectly
sensible action seen from the point of view of the second object
involved, rather than the first -- is called a ``fake action''.
The important ones are |ThrownAt|, |Receive| and |LetGo|
(the latter two being used for containers: see \S 11).
\ddanger If you really need to, you can declare a new fake action
with the directive |Fake_action| \<Action-name>|;|.^^|Fake Action|
\ddangerexercise |ThrownAt| would be unnecessary if Inform had an
idea of |before| and |after| routines which an object could provide if
it were the |second| noun of an action. How might this be
implemented?^^{exercises: before on second noun}
\answer{^^{exercises: before on second noun}
Briefly: provide a |GamePreRoutine| which tests to see if
|second| is an object, rather than |nothing| or a number. If it is,
check whether the object has a |second_before| rule (i.e. test the
condition |(object provides second_before)|). If it has, send the
|second_before| message to it, and return the reply as the return
value from |GamePreRoutine|.}
\tenpoint
\bigskip\noindent
Actions are processed in a simple way, but one which involves many
little stages. There are three main stages:
^^{actions: sequence of processing}
\smallskip
\item{(a)}{`Before'. An opportunity for your code to interfere with
or block altogether what might soon happen.}
\item{(b)}{`During'. The library takes control and decides if the
action makes sense according to its normal world model: for example,
only an |edible| object may be eaten; only an object in the
player's possession can be thrown at somebody, and so on. If the
action is impossible, a complaint is printed and that's all.
Otherwise the action is now carried out.}
\item{(c)}{`After'. An opportunity for your code to react to what
has happened, after it has happened but before any text announcing
it has been printed. If it chooses, your code can print and cause
an entirely different outcome. If your code doesn't interfere,
the library reports back to the player (with such choice phrases as
``Dropped.'').}
\danger Group 1 actions (like |Score|) have no `Before' or
`After' stages: you can't (easily) stop them from taking place.
They aren't happening in the game's world, but in the player's.
\danger The `Before' stage consults your code in five ways, and
occasionally it's useful to know in what order:
\smallskip\ninepoint
\item{i.} The ^|GamePreRoutine| is called, if you have written one.
If it returns `true',
nothing else happens and the action is stopped.
\item{ii.} The |orders| property of the player is called on the
same terms. For more details, see \S 16.
\item{iii.} And the |react_before| of every object in scope
(which roughly means `in the vicinity').
\item{iv.} And the |before| of the current room.
\item{v.} If the action has a first noun, its |before| is called
on the same terms.\tenpoint
\danger The library processes the `During' stage by calling
the action's subroutine. (Subroutines like |TakeSub| make up
a large part of the library.)
\danger The `After' stage only applies to Group 2 actions, as
all Group 3 actions have been packed up at the `During' stage
if not `Before'. During `After' the sequence is as follows:
|react_after| rules for every object in scope (including the
player object); the room's |after|; the first noun's |after|
and finally |GamePostRoutine|.
\ddanger Two things are fake about ``fake actions'' (see above):
they don't have subroutines, and they never occur in the grammar
of any verb (so they're never directly generated by the parser).
\danger
As mentioned above, the parser can generate very peculiar actions,
and this sometimes needs to be remembered when writing |before|
rules. Suppose a |before| rule intercepts the action of putting
the mushroom in the crate, and makes something exciting happen
as a result. Now even if the mushroom is, say, sealed up inside
a glass jar, the parser might still generate this action: the
impossibility won't be realised until `During' time. So the
exciting happening should be written as an |after| rule, when the
attempt to put the mushroom in the crate has already succeeded.
\dangerexercise This kind of snag could be avoided altogether if Inform
had a `validation stage' in action processing, to check whether an action is
sensible before allowing it to get as far as |before| rules. How could
this be added to Inform?^^{actions: validation (exercise)}
^^{exercises: action validation}
\answer{Put any validation rules desired into the |GamePreRoutine|.
For example, the following will filter out any stray |Drop| actions for
unheld objects:^^{actions: validation (exercise)}
^^{exercises: action validation}
\beginstt
[ GamePreRoutine;
if (action==Drop && noun notin player)
"You aren't holding ", (the) noun, ".";
rfalse;
];
\endtt}
\ddanger To some extent you can even meddle with the `During' stage
(and with the final messages produced), and thus even interfere with
Group 1 actions if you are unscrupulous enough, by cunning use of the
^|LibraryMessages| system. See \S 21.
\refs
In a game compiled with the |-D| switch set, typing in the ``actions''
verb will result in trace information being printed each time any
action is generated. Try putting many things into a rucksack and
asking to ``empty'' it for an extravagant list.
\nextref
Diverted actions (using |<<| and |>>|) are commonplace. They're used
in about 20 places in ^{`Advent'}: a good example is the way ``take water''
is translated into a |Fill bottle| action.
\nextref
Sometimes you want ``fake fake actions'' which are fully--fledged
actions (with action routines and so on) but are still never generated
by the parser (see \S 16).
\chapter{Chapter IV: The Model World}
\vskip 0.5in
\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}
({\oldstyle1898}--{\oldstyle1963})}{The Discarded Image}
\section{10}{Places, scenery, directions 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} ({\oldstyle1922}--)}{The White Mountains}
\noindent
Back to ^{`Ruins'}: what lies at the foot of the stone steps? We'll now
add four rooms, connected together:
$$\eqalign{&{\tt Square~Chamber} \leftrightarrow {\tt Web}\cr
&{\tt ~~~~~~}\updownarrow\cr
&{\tt ~~~Corridor}\cr
&{\tt ~~~~~~}\updownarrow\cr
&{\tt ~~~~Shrine}\cr} $$
with the Square Chamber lying underneath the original Forest location.
For instance, here's the Square Chamber's definition:
\beginlines
|Object Square_Chamber "Square Chamber"|
| with name "lintelled" "lintel" "lintels" "east" "south" "doorways",|
| description|
| "A sunken, gloomy stone chamber, ten yards across. A shaft|
| of sunlight cuts in from the steps above, giving the chamber|
| a diffuse light, but in the shadows low lintelled doorways to|
| east and south lead into the deeper darkness of the Temple.",|
| u_to Forest, e_to Web, s_to Corridor,|
| has light;|
\endlines^^{Square Chamber}^^{east lintel}^^{directions}
Like the Forest, this place has |light|, however dim. (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.) Now although this is a room,
and can't be referred to by the player in the way that a manipulable object
can, it still can have a ^|name| property. These |name| words are those which
Inform knows ^{``you don't need to refer to''}, and it's a convention of the
genre that the designer should signpost off the game in this way. (Note
that they'll only be looked at if what the player types is unrecognised,
so the word ``east'' is understood quite normally; but a reference to
``east lintel'' will get the ``don't need to refer to'' treatment.)
This room is unfurnished, so:
\beginlines
|Object -> "carved inscriptions"|
| with name "carved" "inscriptions" "carvings" "marks" "markings" "symbols"|
| "moving" "scuttling" "crowd" "of",|
| initial|
| "Carved inscriptions crowd the walls, floor and ceiling.",|
| description "Each time you look at the carvings closely, they seem|
| to be still. But you have the uneasy feeling when you look|
| away that they're scuttling, moving about. Their meaning|
| is lost on you.",|
| has static;|
\endlines^^{carved inscriptions}
This is part of the fittings, hence the |static| attribute, which means it
can't be taken or moved. As we went out of our way to describe a shaft
of sunlight, we'll include that as well:
\beginlines
|Object -> sunlight "shaft of sunlight"|
| with name "shaft" "of" "sunlight" "sun" "light" "beam" "sunbeam" "ray"|
| "rays" "sun^s",|
| description "The shaft of sunlight glimmers motes of dust in the|
| air, making it seem almost solid."|
| has scenery;|
\endlines^^{shaft of sunlight}
(The |^| symbol in |"sun^s"| means an apostrophe, so the word is ``sun's''.)
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 add a |before| rule:
\beginlines
| before|
| [; Examine, Search: ;|
| default: "It's only an insubstantial shaft of sunlight.";|
| ],|
\endlines^^{perfectionism}
so that the player can look at or through the sunlight, but any other
request involving them will be turned down. Note that a ^|default|
rule, if given, means ``any action except those already mentioned''.
We can't actually get into the Square Chamber yet, though. Just because
there is a ^{map connection} up from here to the Forest, it doesn't follow
that there's a corresponding connection down. So we must add a |d_to|
to the Forest, and while we're at it:
\beginlines
| d_to Square_Chamber,|
| u_to "The trees are spiny and you'd cut your hands to ribbons|
| trying to climb them.",|
| cant_go "The rainforest-jungle is dense, and you haven't hacked|
| through it for days to abandon your discovery now. Really,|
| you need a good few artifacts to take back to civilization|
| before you can justify giving up the expedition.",|
\endlines^^{spiny trees}^^|cant go|
The property |cant_go| contains what is printed when the player tries to go
in a nonexistent direction, and replaces ``You can't go that way''.
As is often the case with properties, instead of giving an actual
message you can instead give a routine to print one out, to vary what's
printed with the circumstances. The Forest needs a |cant_go| because
in real life one could go in every direction from there: what we're
doing is explaining the game rules to the player: go underground, find some
ancient treasure, then get out to win. The Forest's |u_to| property is
a string, not a room; this means that attempts to go up result only in
that string being printed.
\bigskip
\noindent
Rooms also have rules of their own. We might add the following |before|
rule to the Square Chamber:
\beginlines
| before|
| [; Insert:|
| if (noun==mushroom && second==sunlight)|
| { remove mushroom;|
| "You drop the mushroom on the floor, in the glare of|
| the shaft of sunlight. It bubbles obscenely,|
| distends and then bursts into a hundred tiny insects|
| which run for the darkness in every direction. Only|
| tiny crumbs of fungus remain.";|
| }|
| ],|
\endlines
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, and they apply to anything which happens in the given room.
This particular rule could easily enough have been part of the definition of
the mushroom or the sunlight, and in general a room's rules are best used
only for geographical fixtures.
\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:
\beginlines
| after|
| [; Go: if (noun==d_obj)|
| print "You feel on the verge of a great discovery...^";|
| ],|
\endlines
will print the message when its room is entered via the ``down" direction.
Note that since the message is printed with the ^|print| command,
there is no ``return true'' from this routine, so it returns false:
and so the usual game rules resume after the printing of the message.
\noindent
Some objects are present in many rooms at once. The ^{`Ruins'}, for
instance, are misty:
\beginlines
|Object low_mist "low mist"|
| with name "low" "swirling" "mist",|
| initial "A low mist swirls about your feet.",|
| description "The mist carries a rich aroma of broth.",|
| found_in Square_Chamber Forest,|
| before|
| [; Examine, Search: ;|
| Smell: <<Examine self>>;|
| default: "The mist is too insubstantial.";|
| ],|
| has static;|
\endlines^^{low mist}^^|found in|
The |found_in| property gives a list of places in which the mist
is found (so far just the Square Room and the Forest).
\danger If the rainforest contained many misty rooms, it would be tedious to
give the full list and even worse to have to alter it as the mist drifted
about in the course of the game. Fortunately |found_in| can contain a
routine instead of a list. This can look at the current |location| and say
whether or not the object should be put in it when the room is entered, e.g.,
\beginlines
|Object Sun "Sun",|
| with ...|
| found_in|
| [; if (location has light) rtrue;|
| ],|
| has scenery;|
\endlines^^{the Sun}
\ddanger |found_in| is only consulted when the player's location changes,
so if the mist has to dramatically lift or move then it needs to be moved
or removed `by hand'. A good way to lift the mist forever is to |remove|
it, and then give it the |absent| attribute, which prevents it from
manifesting itself whatever |found_in| says.
\medskip\noindent
Some pieces of scenery afflict the ^{other four senses}. The mist smells
of broth, which means that if the player types ``smell'' in a place
where the mist is, then she should be told about the broth. For this,
a |react_before| rule attached to the mist is ideal:
\beginlines
| react_before|
| [; Smell: if (noun==0) <<Smell low_mist>>;|
| ],|
\endlines^^|react before|^^{senses}^^{broth (smell of)}
^^{hearing (sense)}^^{smell (sense)}^^{touch (sense)}^^{taste (sense)}
This is called a ``react'' rule because the mist is reacting to the
fact that a |Smell| action is taking place nearby. |noun| is compared
with zero to see if the player has indeed just typed ``smell'' (not,
say, ``smell crocus''). Thus, when the action |Smell| takes place
near the mist, it is converted into |Smell low_mist|; whereas the
action |Smell crocus| would be left alone.^^{stealing actions}
^^{diverting actions}^^{actions: diversion of}
The ^{five senses} all have actions in Inform: |Look|, |Listen|,
|Smell|, |Taste| and |Touch|. Of these, |Look| never has a noun
attached (because |Examine| is provided for close-ups), |Smell| and
|Listen| may or may not have while |Taste| and |Touch| always
have.^^{actions: of the five senses}
\exercise (Cf. ^{`Spellbreaker'}.) Make an orange cloud descend on the
player, which can't be seen through or walked out
of.^^{orange cloud}^^{exercises: orange cloud surrounding player}
\answer{^^{orange cloud}^^{exercises: orange cloud surrounding player}
\beginlines
|Object orange_cloud "orange cloud"|
| with name "orange" "cloud",|
| react_before|
| [; Look: "You can't see for the orange cloud surrounding you.";|
| Go, Exit: "You wander round in circles, choking.";|
| Smell: if (noun==0) "Cinnamon? No, nutmeg.";|
| ],|
| has scenery;|
\endlines}
\medskip
\noindent
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, a direction is any object in
the special object |compass|.^^{directions: direction objects}
^^{objects: direction and compass objects}
\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}^^{exercises: Mayan directions}
\answer{^^{exercises: Mayan directions}
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 scenery;|
\endlines^^{world colours}^^{Mayan directions}^^{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| called |white_to| to be
|n_to|, and then enter map directions in the source code using
Mayan direction 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}
^^{exercises: reflecting the map east-west}
\answer{^^{reflecting the map}^^{exercises: reflecting the map east-west}
\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.^^{exercises: exchanging ``east''/``west''}
\answer{^^{exercises: exchanging ``east''/``west''}
This is a prime candidate for using ^{variable strings}
^|@nn|. 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.)}
\danger The ordinary Inform directions all have the |number|
property defined (initially set to zero): this is to provide a
set of scratch variables useful, for instance, when ^{coding mazes}.
\ddanger If the constant |WITHOUT_DIRECTIONS| is defined before
inclusion of the library files, then 10 of the default direction
objects are not defined by the library. The designer is expected to
define alternative ones (and put them in the ^|compass| object);
otherwise the game will be rather static. (The ``in" and ``out"
directions are still created, because they're needed for getting
into and out of enterable
objects.)^^|WITHOUT DIRECTIONS|
^^{directions: compiling without the usual}
\refs ^{`Advent'} has a very tangled-up map in places (see the
mazes) and a well-constructed exterior of forest and valley
giving an impression of space with remarkably few rooms. The
mist object uses |found_in| to the full, and see also the
stream (a single object representing every watercourse in the game).
Bedquilt and the Swiss Cheese room offer classic confused-exit
puzzles.
\nextref
For a simple movement rule using |e_to|, see the Office in
^{`Toyshop'}.
\nextref
The library extension ^{``smartcantgo.h''} by ^{David Wagner}
provides a system for automatically printing out ``You can only go
east and north.''-style messages.
\nextref ^{`A Scenic View'}, by ^{Richard Barnett}, demonstrates
a system for providing examinable scenery much more concisely
(without defining so many objects).
\newpage
\section{11}{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}
\widequote
The year has been a good one for the Society {\sl (hear, hear)}.
This year our members have put more things on top of other things
than ever before. But, I should warn you, this is no time for
complacency. No, there are still many things, and I cannot
emphasize this too strongly, {\sl not} on top of other things.
\tvquoteby{`The ^{Royal Society For Putting Things On Top Of
Other Things}'}{{\sl ^{Monty Python's Flying Circus}},
programme {\oldstyle18} ({\oldstyle1970})}
\noindent
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|. A |locked| object (whether it be a door or a
container) cannot be opened. But if it has |lockable| then it can be
locked or unlocked with the key object given in the |with_key| property.
If |with_key| is undeclared, then no key will fit, but this will not be told
to the player, who can try as many as he likes.^^|with key|
Containers (and supporters) are able to react to things being put inside
them, or removed from them, by acting on the signal to |Receive| or
|LetGo|. For example, deep under the ^{`Ruins'} is a chasm which,
perhaps surprisingly, is implemented as a container:
\beginlines
|Object -> chasm "horrifying chasm"|
| with name "blackness" "chasm" "pit" "depths" "horrifying" "bottomless",|
| react_before|
| [; Jump: <<Enter self>>;|
| Go: if (noun==d_obj) <<Enter self>>;|
| ],|
| before|
| [; Enter: deadflag=1;|
| "You plummet through the silent void of darkness!";|
| ],|
| after|
| [; Receive: remove noun;|
| print_ret (The) noun, " tumbles silently into the|
| darkness of the chasm.";|
| Search: "The chasm is deep and murky.";|
| ],|
| has scenery open container;|
\endlines
(Actually the definition is a little longer, so that the chasm reacts to a
huge pumice-stone ball being rolled into it; see `Ruins'.) Note the use of
an |after| rule for the ^|Search| action: this is because an attempt to
``examine'' or ^{``look inside''} the chasm will cause this action.
|Search| means, in effect, ``tell me what is inside the container'' and the
|after| rule prevents a message like ``There is nothing inside the chasm.''
from misleading the player. Note also that the chasm `steals' any stray
|Jump| action and converts it into an early death.
\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^^{exercises: acquisitive bag}
\answer{^^{toothed bag}^^{acquisitive bag}^^{exercises: acquisitive bag}
\beginlines
|Object -> bag "toothed bag"|
| 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:|
| "The bag wriggles hideously as it swallows ",|
| (the) noun, ".";|
| ],|
| has container open;|
\endlines}
\danger ^|LetGo| and ^|Receive| are examples of actions which aren't
explicitly requested by the player, but are generated by the game in the
course of play (so-called ``fake actions'').
\danger |Receive| is sent to an object $O$ both when a player tries to put
something in $O$, and put something on $O$. In the rare event that $O$
needs to react differently to these, it may consult the variable
|receive_action| to find out whether |##PutOn| or |##Insert| is the
cause.^^|receive action|
\noindent
The ^{`Ruins'} packing case is a typical container:
\beginlines
|Object -> packing_case "packing case"|
| with name "packing" "case" "box" "strongbox",|
| initial|
| "Your packing case rests here, ready to hold any important|
| cultural finds you might make, for shipping back to civilisation.",|
| before|
| [; Take, Remove, PushDir:|
| "The case is too heavy to bother moving, as long as your|
| expedition is still incomplete.";|
| ],|
| has static container open;|
\endlines^^{packing case}
\noindent
Now suppose we want a portable television set with 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. But members of
an object which isn't a container are normally assumed by the game to
be hidden invisibly inside (they are said to be ``not in scope''). We
have to override this in order to make the four buttons visible from
outside, by giving the television the ^|transparent| attribute.
\exercise Implement a ^{television set} with attached power button and
screen.^^{exercises: television set}
\answer{^^{exercises: television set}
\beginlines
|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;|
|Object -> power_button "power button"|
| with name "power" "button" "switch",|
| after|
| [; SwitchOn, SwitchOff: <<Examine screen>>;|
| ],|
| has switchable;|
|Object -> 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^^{Japanese cartoon}^^{television set}^^{Manga}^^{cartoon}}
\exercise Make a ^{glass box} and a ^{steel box}, which would behave
differently when a lamp is shut up inside
them.^^{exercises: glass and steel boxes}
\answer{\beginlines
|Object -> glass_box "glass box with a lid"|
| with name "glass" "box" "with" "lid"|
| has container transparent openable open;|
|Object -> steel_box "steel box with a lid"|
| with name "steel" "box" "with" "lid"|
| has container openable open;|
\endlines^^{exercises: glass and steel boxes}}
\danger It sometimes happens that an object should have ^{sub-objects},
like lamps and buttons, as well as possessions, in which case the
above solution is unsatisfactory. Fuller details will be given in the
``scope addition'' rules in \S 28, but briefly: an
object's |add_to_scope| property may contain a list of sub-objects
to be kept attached to it (and these sub-objects don't count as
possessions).^^|add to scope|^^{scope: addition to}
\exercise Implement a ^{macram\'e bag} hanging from the ceiling, inside
which objects are visible (and audible, etc.) but cannot be touched or
manipulated in any way.^^{exercises: macram\'e bag}
\answer{^^{macram\'e bag}^^{exercises: macram\'e bag}
(The |describe| part of this answer but is only decoration.) Note the
careful use of |inp1| and |inp2| rather than |noun| or |second|:
see the note at the end of \S 9.
\beginlines
|Object -> macrame_bag "macrame bag"|
| with name "macrame" "bag" "string" "net" "sack",|
| react_before|
| [; Examine, Search, Listen, Smell: ;|
| default:|
| if (inp1>1 && inp1 in self)|
| print_ret (The) inp1, " is tucked away in the bag.";|
| if (inp2>1 && inp2 in self)|
| print_ret (The) inp2, " is tucked away in the bag.";|
| ],|
| describe|
| [; print "^A macrame bag hangs from the ceiling, shut tight";|
| if (child(self)==0) ".";|
| print ". Inside you can make out ";|
| WriteListFrom(child(self), ENGLISH_BIT); ".";|
| ],|
| has container transparent;|
|Object -> -> "gold watch"|
| with name "gold" "watch",|
| description "The watch has no hands, oddly.",|
| react_before|
| [; Listen: if (noun==0 or self) "The watch ticks loudly."; ];|
\endlines}
\refs Containers and supporters abound in the example games
(except ^{`Advent'}, which is too simple, though see the
water-and-oil carrying bottle). Interesting containers include
the lottery-board and the podium sockets from ^{`Balances'} and
the ^{`Adventureland'} bottle.
\nextref
For supporters, the hearth-rug, chessboard, armchair and mantelpiece
of ^{`Alice Through The Looking-Glass'} are typical examples; the
mantelpiece and spirit level of ^{`Toyshop'} make a simple puzzle,
and the pile of building blocks a complicated one; see also the
scales in ^{`Balances'}.
\section{12}{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} ({\oldstyle1907}--{\oldstyle1973})}{Song}
\noindent^^{doors}
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|:
\smallskip
\item{(a)} give the object the |door| attribute;
\item{(b)} set its |door_to| property to the destination;
\item{(c)} set its |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\smallskip\noindent
For example, here is a closed and locked door, blocking the
way into the ^{`Ruins'} shrine:^^{stone door}
\beginlines
|Object Corridor "Stooped Corridor"|
| with description "A low, square-cut corridor, running north to south,|
| stooping you over.",|
| n_to Square_Chamber,|
| s_to StoneDoor;|
|Object -> StoneDoor "stone door"|
| with description "It's just a big stone door.",|
| name "door" "massive" "big" "stone" "yellow",|
| when_closed|
| "Passage south is barred by a massive door of yellow stone.",|
| when_open|
| "The great yellow stone door to the south is open.",|
| door_to Shrine,|
| door_dir s_to,|
| with_key stone_key|
| 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 -> StoneDoor "stone door"|
| with description "It's just a big stone door.",|
| name "door" "massive" "big" "stone" "yellow",|
| when_closed|
| "The passage is barred by a massive door of yellow stone.",|
| when_open|
| "The great yellow stone door is open.",|
| door_to|
| [; if (location==Corridor) return Shrine; return Corridor; ],|
| door_dir|
| [; if (location==Shrine) return n_to; return s_to; ],|
| with_key stone_key,|
| found_in Corridor Shrine,|
| has static door openable lockable locked;|
\endlines^^{doors: two-way}
where |Corridor| has |s_to| set to |StoneDoor|, and |Shrine| has
|n_to| set to |StoneDoor|. The door can now be opened, closed, entered,
locked or unlocked from either side. We could also make |when_open|
and |when_closed| into routines to print different descriptions of the
door on each side.
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 point is
that two different actions cause the player to go through the door.
Suppose the door is in the south wall. The player may type ``go south'',
which directly causes the action |Go s_obj|. Or the player may ``enter
door'' or ``go through door'', causing |Enter the_door|. Provided the
door is actually open, the |Enter| action then looks at the door's
|door_dir| property, finds that the door faces south and generates
the action |Go s_obj|. Thus, however the player tries to go through
the door, it is the |Go| action that finally results.
This has an important consequence: if you put |before| and |after|
routines on the ^|Enter| action for the |StoneDoor|, they only apply to
a player typing ``enter door" and not to one just typing ``south". So
one safe way is to trap the |Go| action. A neater method is to
put some code into a |door_to| routine. If a |door_to|
routine returns 0 instead of a room, then the player is told that
the door ``leads nowhere'' (like the famous broken bridge of Avignon).
If |door_to| returns 1, or `true', then the library stops the action
on the assumption that something has happened and the player has been
told already.^^{doors: trapping movement through}
\exercise Create a ^{plank bridge} across a chasm, which collapses if
the player walks across it while carrying
anything.^^{bridge which collapses}^^{exercises: plank bridge}
\answer{^^{plank bridge}^^{bridge which collapses}
^^{exercises: plank bridge}The
``plank breaking'' rule is implemented here in its |door_to| routine.
Note that this returns `true' after killing the player.
\beginlines
|Object -> PlankBridge "plank bridge"|
| with description "Extremely fragile and precarious.",|
| name "precarious" "fragile" "wooden" "plank" "bridge",|
| when_open|
| "A precarious plank bridge spans the chasm.",|
| door_to|
| [; if (children(player)~=0)|
| { deadflag=1;|
| "You step gingerly across the plank, which bows under|
| your weight. But your meagre possessions are the straw|
| which breaks the camel's back! There is a horrid crack...";|
| }|
| print "You step gingerly across the plank, grateful that|
| you're not burdened.^";|
| if (location==NearSide) return FarSide; return NearSide;|
| ],|
| door_dir|
| [; if (location==NearSide) return s_to; return n_to;|
| ],|
| found_in NearSide FarSide,|
| has static door open;|
\endlines
There might be a problem with this solution if your game also contained
a character who wandered about, and whose code was clever enough to run
|door_to| routines for any |door|s it ran into. If so, |door_to| could
perhaps be modified to check that the |actor| is the |player|.}
\refs ^{`Advent'} is especially rich in two-way doors: the steel grate
in the streambed, two bridges (one of crystal, the other of rickety
wood) and a door with rusty hinges. See also the iron gate in `Balances'.
\section{13}{Switchable objects}
\widequote
Steven: `Well, what does this do?'\quad Doctor: `That is the dematerialising
control. And that over yonder is the horizontal hold. Up there is the
scanner, these are the doors, that is a chair with a panda on it. Sheer
poetry, dear boy. Now please stop bothering me.'
\tvquoteby{^{Dennis Spooner},
{\sl The Time Meddler}}{{\sl Dr Who}, serial {\oldstyle 17} ({\oldstyle1965})}
^^{Doctor Who}
\noindent
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}^^{Gotham City}^^{holy 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
Something more portable would come in handy for the
explorer of ^{`Ruins'}, who would hardly have embarked on his expedition
without a decent light source$\ldots$
\beginlines
|Object sodium_lamp "sodium lamp"|
| with name "sodium" "lamp" "heavy",|
| describe|
| [; if (self hasnt on) |
| "^The sodium lamp squats heavily on the ground.";|
| "^The sodium lamp squats on the ground, burning away.";|
| ],|
| battery_power 40,|
| before|
| [; Examine: print "It is a heavy-duty archaeologist's lamp, ";|
| if (self hasnt on) "currently off.";|
| if (self.battery_power < 10) "glowing a dim yellow.";|
| "blazing with brilliant yellow light.";|
| Burn: <<SwitchOn self>>;|
| SwitchOn:|
| if (self.battery_power <= 0)|
| "Unfortunately, the battery seems to be dead.";|
| if (parent(self) hasnt supporter && self notin location)|
| "The lamp must be securely placed before being lit.";|
| Take, Remove:|
| if (self has on)|
| "The bulb's too delicate and the metal frame's too|
| hot to lift the lamp while it's switched on.";|
| ],|
| after|
| [; SwitchOn: give self light;|
| SwitchOff: give self ~light;|
| ],|
| has switchable;|
\endlines^^{sodium lamp}
The `Ruins' lamp will eventually be a little more complicated, with a
daemon to make the ^{battery power} run down and to extinguish the lamp
when it runs out; and it will be pushable from place to place, making it
not quite as useless as the player will hopefully think at first.
\danger A point to note is that this time the |when_on| and |when_off|
properties haven't been used to describe the lamp when it's on the ground:
this is because once an object has been held by the player, it's normally
given only a perfunctory mention in room descriptions (``You can also see a
sodium lamp and a grape here.''). But the ^|describe| property has priority
over the whole business of how objects are described in ^{room
descriptions}. When it returns true, as above, the usual description process
does nothing further. For much more on room descriptions, see \S 22.
\refs The original switchable object was the brass lamp from ^{`Advent'}
(which also provides verbs ``on'' and ``off'' to switch it). (The other
example games are generally pre-electric in setting.)
\newpage
\section{14}{Things to enter, travel in and push around}
\quote
$\ldots$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}}
\noindent
Some objects in a game are ^|enterable|, which means that a player can get
inside or onto them. Usually, ``inside" means 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 the
^{altar} from ^{`Ruins'}, a ^|supporter|:
\beginlines
|Object -> stone_table "slab altar"|
| with name "stone" "table" "slab" "altar" "great",|
| initial "A great stone slab of a table, or altar, dominates the Shrine.",|
| has enterable supporter;|
\endlines^^{stone altar}
A chair to sit on, or a bed to lie down on, should also be
a |supporter|.
If the player gets into a |container| and then closes it, the
effect is like being in a different location. (Unless the container
has the |transparent| attribute and is therefore see-through.)
The interior may be dark, but if there's light to see by, the
player will want to see some kind of room description. In any case,
many enterable objects ought to look different from inside or on
top. Inside a vehicle, a player might be able to see a steering
wheel and a dashboard, for instance. On top of a cupboard, it
might be possible to see through a skylight window.
For this purpose, any |enterable| object can provide an
|inside_description|, which can be a string or a routine
to print one, as usual. If the exterior location is still
visible, then the ``^{inside description}'' is added to the
normal room description, and otherwise it becomes that
description. As an extreme example, suppose that the player
gets into a huge cupboard, closes the door behind her and
then gets into a plastic cabinet inside that. The resulting
room description might read like so:
\begindisplay
{\bf The huge cupboard} (in the plastic cabinet)\cr
It's a snug little cupboard in here, almost a room in itself.\cr
\cr
In the huge cupboard you can see a pile of clothes.\cr
\cr
The plastic walls of the cabinet distort the view.\cr
\enddisplay
The second line is the |inside_description| for the huge
cupboard, and the fourth is that for the plastic cabinet.
\exercise (Also from `Ruins'.) Implement a cage which can be opened,
closed and entered.^^{exercises: cage to open and enter}
\answer{^^{`Ruins'}^^{exercises: cage to open and enter}
\beginlines
|Object -> cage "iron cage"|
| with name "iron" "cage" "bars" "barred" "iron-barred",|
| when_open|
| "An iron-barred cage, large enough to stoop over inside,|
| looms ominously here.",|
| when_closed "The iron cage is closed.",|
| inside_description "You stare out through the bars.",|
| has enterable container openable open transparent static;|
\endlines}
\medskip
\noindent
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",|
| description "Large enough to sit inside. Among the controls is a|
| prominent on/off switch. The numberplate is KAR 1.",|
| when_on "The red car sits here, its engine still running.",|
| when_off "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.
It may then return:
\begindisplay
0\quad to disallow the movement, printing a refusal;\cr
1\quad to allow the movement, moving vehicle and player;\cr
2\quad to disallow but print and do nothing; or\cr
3\quad to allow but print and do nothing.\cr
\enddisplay
If you want to move the vehicle in your own code, return 3, not 2: otherwise
the old location may be restored by subsequent workings.
\medskip\noindent
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
east.^^{exercises: car that won't go east}
\answer{^^{exercises: car that won't go east}
Change the car's |before| to
\beginlines
| before|
| [; Go: if (noun==e_obj)|
| { print "The car will never fit through your front door.^";|
| return 2;|
| }|
| if (car has on) "Brmm! Brmm!";|
| print "(The ignition is off at the moment.)^";|
| ],|
\endlines^^{little red car}}
\danger
Objects like the car 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. For example (^{`Ruins'} again):
\beginlines
|Object -> huge_ball "huge pumice-stone ball"|
| with name "huge" "pumice" "pumice-stone" "stone" "ball",|
| description "A good eight feet across, though fairly lightweight.",|
| initial|
| "A huge pumice-stone ball rests here, eight feet wide.",|
| before|
| [; PushDir:|
| if (location==Junction && second==w_obj)|
| "The corridor entrance is but seven feet across.";|
| AllowPushDir(); rtrue;|
| Pull, Push, Turn: "It wouldn't be so very hard to get rolling.";|
| Take, Remove: "There's a lot of stone in an eight-foot sphere.";|
| ],|
| after|
| [; PushDir:|
| if (second==s_obj) "The ball is hard to stop once underway.";|
| if (second==n_obj) "You strain to push the ball uphill.";|
| ],|
| has static;|
\endlines^^{pumice ball}^^{eight-foot pumice ball}^^{ball of pumice}
\dangerexercise The library does not normally allow pushing objects up or down.
How can the pumice ball allow this?^^{exercises: pushing pumice ball uphill}
\answer{^^{pumice ball}^^{eight-foot pumice ball}^^{ball of pumice}
^^{`Ruins'}^^{exercises: pushing pumice ball uphill}
Insert these lines into the |before| rule for |PushDir|:
\beginlines
| if (second==u_obj) <<PushDir self n_obj>>;|
| if (second==d_obj) <<PushDir self s_obj>>;|
\endlines}
\refs For an |enterable| |supporter| puzzle, see the magic carpet
in ^{`Balances'} (and several items in
^{`Alice Through The Looking-Glass'}).
\section{15}{Reading matter and consultation}
\widequote
Even at present$\ldots$ we still know very little about how access
to printed materials affects human behaviour.
\widepoemby{^{Elizabeth Eisenstein}}{The Printing Revolution
in Early Modern Europe}
\begindisplay
look up figure 18 in the engineering textbook\cr
\enddisplay
is a difficult line for Inform to understand, because almost anything
could appear in the first part: even its format depends on what the
second part is. This kind of request, and more generally
\begindisplay
look up \<any words here> in \<the object>\cr
read about \<any words here> in \<the object>\cr
consult \<the object> about \<any words here>\cr
\enddisplay^^{reading books}^^{{\tt Consult} action}
cause the |Consult object| action. Note that |second| is just zero:
formally, there is no second noun attached to a |Consult| action.
The object has to parse the \<any words here> part itself, in a |before|
rule for |Consult|. The following variables are set up to make this
possible:
\smallskip
|consult_from| holds the number of the first word in the \<any...>
clause;^^|consult from|\
|consult_words| holds the number of words in the \<any...> clause
(at least 1).^^|consult words|\
\smallskip\noindent
The words given are parsed using library routines like
|NextWord()|, |TryNumber(word-number)| and so on: see \S 24 for
full details. As usual, the |before| routine should return true
if it has managed to deal with the action; returning false will
make the library print ``You discover nothing of interest in$\ldots$''.
Little hints are placed here and there in the ^{`Ruins'}, written
in the ^{glyphs} of an ancient dialect of Mayan. Our explorer has,
of course, come equipped with the latest and finest scholarship
on the subject:
\beginlines
|Object dictionary "Waldeck's Mayan dictionary"|
| with name "dictionary" "local" "guide" "book" "mayan"|
| "waldeck" "waldeck^s",|
| description "Compiled from the unreliable lithographs of the|
| legendary raconteur and explorer ~Count~ Jean Frederic|
| Maximilien Waldeck (1766??-1875), this guide contains|
| what little is known of the glyphs used in the local|
| ancient dialect.",|
| before|
| [ w1 w2 glyph other; Consult:|
| if (consult_words>2) jump GlyphHelp;|
| wn=consult_from;|
| w1 = NextWord(); ! First word of subject |
| w2 = NextWord(); ! Second word (if any) of subject |
| if (consult_words==1 && w1=='glyph' or 'glyphs')|
| jump GlyphHelp;|
| ! We want to recognise both "glyph q1" and "q1 glyph":|
| glyph=w1; other=w2;|
| if (w1=='glyph') { glyph=w2; other=w1; }|
| ! So now glyph holds the name, and other the other word|
| if (consult_words==2 && other~='glyph') jump GlyphHelp;|
| switch(glyph)|
| { 'q1': "(This is one glyph you have memorised!)^^|
| Q1: ~sacred site~.";|
| 'circle': "Circle: ~the Sun; also life, lifetime~.";|
| ...|
| default: "That glyph is so far unrecorded.";|
| }|
| ! All three of the ways the text can go wrong lead to|
| ! this message being produced:|
| .GlyphHelp; "Try ~look up <name of glyph> in book~.";|
| ],|
| has proper;|
\endlines^^{dictionary of Mayan glyphs}^^{Jean Frederic Waldeck}
^^{Waldeck's Mayan dictionary}^^{Mayan dictionary}
Note that this understands any of the forms ``q1'', ``glyph q1'' or
``q1 glyph'' but is careful to reject, for instance, ``glyph q1 glyph''.
(These aren't genuine Mayan glyphs, but some of the real ones have similar
names, dating from when their syllabic equivalents weren't known: G8,
the Lord of the Night, for instance.)
\exercise To mark the 500th anniversary of ^{William Tyndale} (the first
English translator of the ^{New Testament}), prepare an edition of the
^{four Gospels}.^^{Bible}^^{exercises: Tyndale's Bible}
\answer{^^{William Tyndale}^^{New Testament}^^{four Gospels}^^{Bible}
^^{exercises: Tyndale's Bible}
\beginlines
|Object -> bible "black Tyndale Bible"|
| with name "bible" "black" "book",|
| initial "A black Bible rests on a spread-eagle lectern.",|
| description "A splendid foot-high Bible, which must have survived|
| the burnings of 1520.",|
| before|
| [ w x; Consult:|
| wn = consult_from; w = NextWord();|
| switch(w)|
| { 'matthew': x="Gospel of St Matthew";|
| 'mark': x="Gospel of St Mark";|
| 'luke': x="Gospel of St Luke";|
| 'john': x="Gospel of St John";|
| default: "There are only the four Gospels.";|
| }|
| if (consult_words==1)|
| "You read the ", (string) x, " right through.";|
| w = TryNumber(wn);|
| if (w==-1000)|
| "I was expecting a chapter number in the ",|
| (string) x, ".";|
| "Chapter ", (number) w, " of the ", (string) x,|
| " is too sacred for you to understand now.";|
| ];|
\endlines}
\ddanger
Ordinarily, a request by the player to ``read'' something is translated
into an |Examine| action. But the ``read'' verb is defined independently
of the ``examine'' verb in order to make it easy to separate the two
requests. For instance:
\beginlines
|Attribute legible;|
|...|
|Object textbook "textbook"|
| with name "engineering" "textbook" "text" "book",|
| description "What beautiful covers and spine!",|
| before|
| [; Consult, Read:|
| "The pages are full of senseless equations.";|
| ],|
| has legible;|
|...|
|[ ReadSub; <<Examine noun>>; ];|
|Extend "read" first * legible -> Read;|
\endlines^^{``examine'' v. ``read''}^^{``read'' v. ``examine''}^^{legibility}
\ninepoint
Note that ``read" causes a |Read| action only for |legible| objects,
and otherwise causes |Examine| in the usual way. |ReadSub| is coded
as a translation to |Examine| as well, so that if a |legible| object
doesn't provide a |Read| rule then an |Examine| happens after all.
\tenpoint
\refs If you really need more elaborate topic-parsing (for, e.g.,
``look up \<something> in the catalogue'', where any object name might
appear) then extending the grammar for |look| may be less trouble.
For a good implementation see ^{`Encyclopaedia Frobozzica'}, by
^{Gareth Rees}.
\section{16}{Living creatures and conversation}
\widepoem
To know how to live is my trade and my art.
\poemby{^{Michel de Montaigne} ({\oldstyle1533}--{\oldstyle1592})}{Essays}
\widepoem
Everything that can be said can be said clearly.
\poemby{^{Ludwig Wittgenstein} ({\oldstyle1889}--{\oldstyle1951})}{Tractatus}
\noindent
This rummage through special kinds of objects finishes up with the most
sophisticated kind: living ones. Note that the finer points of this
section, on the arts of conversation, require some knowledge of Chapter
V.
Animate objects, such as sea monsters, mad aunts or nasty little dwarves,
have a property called ^|life|. This behaves somewhat like a |before|
or |after| routine, but only applies to the following actions:
\medskip
\stepin=60pt
\block{Attack}^^|Attack|%
The player is making hostile advances$\ldots$
\medskip
\block{Kiss}^^|Kiss|%
$\ldots$or excessively friendly ones$\ldots$
\medskip
\block{WakeOther}^^|WakeOther|%
$\ldots$or simply trying to rouse the creature from sleep.
\medskip
\block{ThrowAt}^^|ThrowAt|%
The player asked to throw |noun| at the creature.
\medskip
\block{Give}^^|Give|%
The player asked to give |noun| to the creature$\ldots$
\medskip
\block{Show}^^|Show|%
$\ldots$or, tantalisingly, just to show it.
\medskip
\block{Ask}^^|Ask|%
The player asked about something. Just as with a ``consult''
topic (see \S 15 passim), the variables |consult_from|
and |consult_words| are set up to indicate which words the
object might like to think about. (In addition, |second|
holds the dictionary value for the first word which isn't
|'the'|, but this is much cruder.)
\medskip
\block{Tell}^^|Tell|%
Likewise, the player is trying to tell the creature about
something. The topic is set up just as for |Ask| (that is,
|consult_from| and |consult_words| are set, and |second|
also holds the first interesting word).
\block{Answer}^^|Answer|%
This can happen in two ways. One is if the player types ``answer \<some text>
to troll" or ``say \<some text> to troll''; the other is if he gives an
order which the parser can't sort out, such as
``troll, og south", and which the |orders| property hasn't handled
already. Once again, variables are set as if it
were a ``consult'' topic. (In addition, |noun| is set to the
first word, and an attempt to read the text as a number is
stored in the variable |special_number|: for instance,
^{``computer, 143"} will cause |special_number| to be set to
143.)^^|special number|
\medskip
\block{Order}^^|Order|%
This catches any `orders' which aren't
handled by the |orders| property (see below); |action|,
|noun| and |second| are set up as usual.
\bigskip
\noindent
If the |life| routine doesn't exist, or returns false, events take their
usual course. |life| routines tend to be quite lengthy, even for
relatively static characters such as the ^{priest} who stands in
the ^{`Ruins'} ^{Shrine}:
\beginlines
|Object -> priest "mummified priest"|
| with name "mummified" "priest",|
| description|
| "He is desiccated and hangs together only by will-power. Though|
| his first language is presumably local Mayan, you have the curious|
| instinct that he will understand your speech.",|
| initial "Behind the slab, a mummified priest stands waiting, barely|
| alive at best, impossibly venerable.",|
| life|
| [; Answer: "The priest coughs, and almost falls apart.";|
| Ask: switch(second)|
| { 'dictionary', 'book':|
| if (dictionary has general)|
| "~The ~bird~ glyph... very funny.~";|
| "~A dictionary? Really?~";|
| 'glyph', 'glyphs', 'mayan', 'dialect':|
| "~In our culture, the Priests are ever literate.~";|
| 'king', 'tomb', 'shrine', 'temple', 'altar', 'slab':|
| "~The King (life! prosperity! happiness!) is buried|
| deep under this Shrine, where you will never go.~";|
| }|
| "~You must find your own answer.~";|
| Tell: "The priest has no interest in your sordid life.";|
| Attack, Kiss: remove self;|
| "The priest desiccates away into dust until nothing|
| remains, not a breeze nor a bone.";|
| ThrowAt: move noun to location; <<Attack self>>;|
| Show, Give:|
| if (noun==dictionary && dictionary hasnt general)|
| { give dictionary general;|
| "The priest reads a little of the book, laughing|
| in a hollow, whispering way. Unable to restrain|
| his mirth, he scratches in a correction somewhere|
| before returning the book.";|
| }|
| "The priest is not very interested in earthly things.";|
| ],|
| has animate;|
\endlines^^{mummified priest}^^{desiccated priest}
(Some of the |Ask| topics are omitted for brevity.)
Of course an |animate| object still has |before| and |after| routines
like any other, so you can trap many other kinds of behaviour.
Animate creatures can also |react_before| and |react_after|, and it's
here that these properties really come into their own:%
^^|react before|^^|react after|
\beginstt
react_before
[; Drop: if (noun==satellite_gadget)
print "~I wouldn't do that, Mr Bond,~ says Blofeld.^^";
Shoot: remove beretta;
"As you draw, Blofeld snaps his fingers and a giant
magnet snatches the gun from your hand. It hits the
ceiling with a clang. Blofeld silkily strokes his cat.";
];
\endtt^^{Ernst Stavro Blofeld}^^{Blofeld, Ernst Stavro}
^^{James Bond}^^{Bond, James}^^{giant magnet}^^{Beretta pistol}
If Blofeld moves from place to place, these rules move with him.
\exercise Arrange for a bearded psychiatrist to place the player
under observation, occasionally mumbling insights such as
``Subject puts green cone on table.
Interesting.''^^{exercises: bearded psychiatrist}
\answer{^^{exercises: bearded psychiatrist}
Note that whether reacting before or after, the psychiatrist
does not cut any actions short, because |react_before| and
|react_after| both return false.
\beginlines
|Object -> psychiatrist "bearded psychiatrist"|
| with name "bearded" "doctor" "psychiatrist" "psychologist" "shrink",|
| initial "A bearded psychiatrist has you under observation.",|
| life|
| [; "He is fascinated by your behaviour, but makes no attempt to|
| interfere with it.";|
| ],|
| react_after|
| [; Insert: print "~Subject puts ", (name) noun, " in ",|
| (name) second, ". Interesting.~^^";|
| Look: print "~Pretend I'm not here,~ says the psychiatrist.^";|
| ],|
| react_before|
| [; Take, Remove: print "~Subject feels lack of ", (the) noun,|
| ". Suppressed Oedipal complex? Mmm.~^";|
| ],|
| has animate;|
\endlines}
\noindent
Another example is the coiled snake from ^{`Balances'}, which
shows that even the tiniest |life| routine can be adequate for an animal:
\beginstt
Object -> snake "hissing snake"
with name "hissing" "snake",
initial "Tightly coiled at the edge of the chasm is a hissing snake.",
life [; "The snake hisses angrily!"; ],
has animate;
\endtt
^^{animals}^^{coiled snake}^^{snake}^^{hissing snake}
\danger When writing general code to deal with |animate| creatures,
it's sometimes convenient to have a system worked out for printing
^{pronouns} such as ``her'' and ``He''. See \S 22 for one way to do this.
\noindent
Sometimes creatures should be ^|transparent|, sometimes not. Consider these
two cases of |animate| characters, for instance:
\smallskip
\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.
\smallskip\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}
\medskip
\noindent
When the player types in something like ``pilot, fly south'',
the result is called an `order': this is the corresponding idea to an
`action'. (Indeed, if the player types ``me, go south'' an
ordinary |Go s_obj| action is produced.)
The order is sent to the pilot's ^|orders| property, which may if
it wishes obey or react in some other way. Otherwise, the standard
game rules will simply print something like ``The pilot has better things
to do.'' The above priest is especially unhelpful:
\beginlines
| orders|
| [; Go: "~I must not leave the Shrine.~";|
| NotUnderstood: "~You speak in riddles.~";|
| default: "~It is not your orders I serve.~";|
| ];|
\endlines^^{Shrine}
(The ^|NotUnderstood| clause is run when the parser couldn't
understand what the player typed: e.g., ``priest, go onrth''.)
\danger Something to bear in mind is that because the library regards
the words ``yes'' and ``no'' as being verbs in Inform, it understands
^{``delores, yes''} as being a |Yes| order. (This can be a slight
nuisance, as ``say yes to delores'' is treated differently: it gets
routed through the |life| routine as an |Answer|.)
\ddanger If the |orders| property returns false (or if there wasn't
an |orders| property in the first place), the order is sent either
to the |Order:| part of the |life| property (if it's understood)
or to the |Answer:| part (if it isn't). (This is how all orders used to
be processed, and it's retained to avoid making reams of old Inform
code go wrong.) If these also return false, a message like ``X has
better things to do'' or ``There is no reply'' is finally printed.
\noindent
To clarify the various kinds of conversation:
\smallskip
\hrule
\smallskip
\settabs 8 \columns
\+ Command &&& rule & |action| & |noun| & |second| & consult\cr
\smallskip
\hrule
\smallskip
\+ ``orc, take axe'' &&& |order| & |Take| & |axe| & |0| &\cr
\+ ``orc, yes'' &&& |order| & |Yes| & |0| & |0| &\cr
\+ ``ask orc for the shield'' &&& |order| & |Give| & |shield| & |player| &\cr
\+ ``orc, troll'' &&& |order| & |NotU...| & |'troll'| & |orc| & 3\quad 1\cr
\+ ``say troll to orc'' &&& |life| & |Answer| & |'troll'| & |orc| & 2\quad 1\cr
\+ ``answer troll to orc'' &&& |life| & |Answer| & |'troll'| & |orc| & 2\quad 1\cr
\+ ``orc, tell me about coins'' &&& |life| & |Ask| & |orc| & |'coins'| & 6\quad 1\cr
\+ ``ask orc about the big troll'' &&& |life| & |Ask| & |orc| & |'big'| & 4\quad 3\cr
\+ ``ask orc about wyvern'' &&& |life| & |Ask| & |orc| & |0| & 4\quad 1\cr
\+ ``tell orc about lost troll'' &&& |life| & |Tell| & |orc| & |'lost'| & 4\quad 2\cr
\smallskip
\hrule
\smallskip
\noindent
where ``wyvern'' is a word not mentioned anywhere in the program,
which is why its value is |0|.
\exercise In some ways, |Answer| and |Tell| are just too much trouble.
How can you make attempts to use these produce a message saying
``To talk to someone, try
`someone, something'.''?^^{removing conversation actions}
^^{exercises: removing conversation actions}
\answer{^^{removing conversation actions}
^^{exercises: removing conversation actions}
Add the following lines, after the inclusion of |Grammar|:
\beginlines
|[ SayInsteadSub; "[To talk to someone, please type ~someone, something~|
|or else ~ask someone about something~.]"; ];|
|Extend "answer" replace * topic -> SayInstead;|
|Extend "tell" replace * topic -> SayInstead;|
\endlines
A slight snag is that this will throw out ``nigel,
tell me about the grunfeld defence'' (which the library will normally
convert to an |Ask| action, but can't if the grammar for ``tell'' is
missing). To avoid this, you could (instead of making the above
directives) |Replace| the |TellSub| routine (see \S 21)
by the |SayInsteadSub| one.}
\medskip
\noindent
Some objects are not alive as such, but can be spoken to: ^{microphones},
^{tape recorders}, ^{voice-activated computers} and so on.
It would be a nuisance to implement these as |animate|, since they have
none of the other characteristics of life: instead, they can be given
just the attribute ^|talkable| and |orders| and |life| properties to
deal with the resulting conversation.
\exercise (Cf. ^{`Starcross'}.) Construct a computer responding to
``computer, theta is 180''.^^{computer (voice-activated)}
^^{exercises: computer (voice-activated)}
\answer{^^{`Starcross'}^^{computer (voice-activated)}
^^{exercises: computer (voice-activated)}
There are several ways to do this. The easiest is to add more grammar
to the parser and let it do the hard work:
\beginstt
Object -> computer "computer"
with name "computer",
orders
[; Theta: print_ret "~Theta now set to ", noun, ".~";
default: print_ret "~Please rephrase.~";
],
has talkable;
..
[ ThetaSub; "You must tell your computer so."; ];
Verb "theta" * "is" number -> Theta;
\endtt}
\medskip\noindent
\danger The rest of this section starts to overlap much more with
Chapter V, and assumes a little familiarity with the parser.
\ninepoint
\danger The ^|NotUnderstood| clause of |orders| is run when the
parser has got stuck parsing an order like ``pilot, fly somersaults''.
The variable ^|etype| holds the parser error that would have been
printed out, had it been a command by the player himself. See \S 29:
for instance, |CANTSEE_PE| would mean ``the pilot can't see any such
object''.
\danger
When the player issues requests to an |animate| or |talkable| object,
they're normally parsed exactly as if they were commands by the
player himself (except that the |actor| is now the person being
spoken to). But sometimes one would rather they were parsed by
an entirely different grammar. For instance, consider ^{Zen}, the
flight computer of an alien spacecraft. It's inappropriate to
tell Zen to (say) pick up a teleport bracelet and the crew tend
to give commands more like:
\begindisplay
``Zen, set course for Centauro''\cr
``Zen, speed standard by six''\cr
``Zen, scan 360 orbital''\cr
``Zen, raise the force wall''\cr
``Zen, clear the neutron blasters for firing''\cr
\enddisplay^^{Blake's 7}^^{flight computer}
This could mostly be implemented by adding verbs like ``raise''
to the usual game grammar (see the `Starcross' computer exercise
above), or by carefully trapping the |Answer| rule. But this is
a nuisance, especially if about half the commands you want are
recognised as orders in the usual grammar but the other half aren't.
An |animate| or |talkable| object can therefore provide a ^|grammar|
routine (if it likes). This is called at a time when the parser has
worked out the object that is being addressed and has set the variables
|verb_num| and |verb_word| (to the number of the `verb' and its
dictionary entry, respectively: for example, in ``orac, operate the
teleport'' |verb_num| would be 3 (because the comma counts as a
word on its own) and |verb_word| would be |'operate'|). The |grammar|
routine can reply by returning:
\item{0.}The parser carries on as usual.
\item{1.}The |grammar| routine is saying it has done all the parsing necessary
itself, by hand (i.e., using |NextWord|, |TryNumber|, |NounDomain| and
the like): the variables |action|, |noun| and |second| must be set up
to contain the resulting order.
\item{|'verb'|}The parser ignores the usual grammar and instead works
through the grammar lines for the given verb (see below).
\item{|-'verb'|}Ditto, except that if none of those grammar lines work
then the parser goes back and tries the usual grammar as well.
\smallskip\noindent In addition, the |grammar| routine is free to
do some partial parsing of the early words provided it moves on
|verb_num| accordingly to show how much it's got through.^^|verb num|
\dangerexercise Implement Charlotte, a little girl who's playing
^{Simon Says} (a game in which she only follows your instructions
if you remember to say ``Simon says'' in front of them: so she'll
disobey ``charlotte, wave'' but obey
``charlotte, simon says wave'').^^{girl playing Simon Says}
^^{Charlotte's game}^^{exercises: Charlotte playing Simon Says}
\answer{^^{Simon Says}^^{Charlotte's game}^^{girl playing Simon Says}
^^{exercises: Charlotte playing Simon Says}
Obviously, a slightly wider repertoire of actions might be a good idea,
but:
\beginlines
|Object -> Charlotte "Charlotte"|
| with name "charlotte" "charlie" "chas",|
| grammar|
| [; give self ~general;|
| wn=verb_wordnum;|
| if (NextWord()=='simon' && NextWord()=='says')|
| { give self general;|
| verb_wordnum=verb_wordnum+2;|
| }|
| ],|
| orders|
| [ i; if (self hasnt general) "Charlotte sticks her tongue out.";|
| WaveHands: "Charlotte waves energetically.";|
| default: "~Don't know how,~ says Charlotte.";|
| ],|
| initial "Charlotte wants to play Simon Says.",|
| has animate female proper;|
\endlines
(The variable |i| isn't needed yet, but will be used by the
code added in the answer to the next exercise.)}
\dangerexercise Another of Charlotte's rules is that if you say a
number, she has to clap that many times. Can you
play?^^{clapping game}^^{exercises: Charlotte's clapping game}
\answer{^^{clapping game}^^{exercises: Charlotte's clapping game}
First add a |Clap| verb (this is easy). Then
give Charlotte a |number| property (initially 0, say) and add
these three lines to the end of Charlotte's |grammar| routine:
\beginlines
| self.number=TryNumber(verb_wordnum);|
| if (self.number~=-1000)|
| { action=##Clap; noun=0; second=0; rtrue; }|
\endlines
Her |orders| routine now needs a local variable called |i|, and
the new clause:
\beginlines
| Clap: if (self.number==0) "Charlotte folds her arms.";|
| for (i=0:i<self.number:i++)|
| { print "Clap! ";|
| if (i==100)|
| print "(You must be regretting this by now.) ";|
| if (i==200)|
| print "(What a determined girl she is.) ";|
| }|
| if (self.number>100)|
| "^^Charlotte is a bit out of breath now.";|
| "^^~Easy!~ says Charlotte.";|
\endlines}
\dangerexercise Regrettably, ^{Dyslexic Dan} has always mixed up the
words ``take'' and ``drop''. Implement him
anyway.^^{exercises: Dyslexic Dan}
\answer{^^{exercises: Dyslexic Dan}
The interesting point here is that when the |grammar| property
finds the word ``take'', it accepts it and has to move |verb_wordnum|
on by one to signal that a word has been parsed succesfully.
\beginlines
|Object -> Dan "Dyslexic Dan"|
| with name "dan" "dyslexic",|
| grammar|
| [; if (verb_word == 'take') { verb_wordnum++; return 'drop'; }|
| if (verb_word == 'drop') { verb_wordnum++; return 'take'; }|
| ],|
| orders|
| [ i;|
| Take: "~What,~ says Dan, ~ you want me to take ",|
| (the) noun, "?~";|
| Drop: "~What,~ says Dan, ~ you want me to drop ",|
| (the) noun, "?~";|
| Inv: "~That I can do,~ says Dan. ~I'm empty-handed.~";|
| No: "~Right you be then.~";|
| Yes: "~I'll be having to think about that.~";|
| default: "~Don't know how,~ says Dan.";|
| ],|
| initial "Dyslexic Dan is here.",|
| has animate proper;|
\endlines^^{Dyslexic Dan}}
\danger It's useful to know that if the player types a comma or a
full stop, then the parser cuts these out as separate words. Because
of this, a dictionary word containing up to 7 letters and
then a comma or a full stop can never be matched by what the player
types. Such a word is called an ``untypeable verb'', and it's useful
to help a |grammar| routine to shunt parsing into a piece of game
grammar which the player can never use.
For instance, here's a way to implement the ^{`Starcross'}
computer which doesn't involve creating foolish new actions. We
create grammar:
\beginlines
|[ Control;|
| switch(NextWord())|
| { 'theta': parsed_number=1; return 1;|
| 'phi': parsed_number=2; return 1;|
| 'range': parsed_number=3; return 1;|
| default: return -1;|
| }|
|];|
|Verb "comp," * Control "is" number -> SetTo;|
\endlines
And the computer itself needs properties
\beginlines
| grammar [; return 'comp,'; ],|
| orders|
| [; SetTo:|
| switch(noun)|
| { 1: print "~Theta"; 2: print "~Phi"; 3: print "~Range"; }|
| print_ret " set to ", second, ".~";|
| default: "~Does not compute!~";|
| ];|
\endlines
This may not look easier, but it's much more flexible, as the exercises
below will hopefully demonstrate.
\ddanger Another use for ^{untypeable verbs} is to create what might be
called `^{fake fake actions}'. Recall that a fake action is one which
is never generated by the parser, and has no action routine. Sometimes
(very rarely) you want a proper action but which still can't be
generated by the parser: the following example creates three.
\beginlines
|Verb "actions." * -> Prepare * -> Simmer * -> Cook;|
\endlines
The parser never uses ``actions.'' in its ordinary grammar, so this
definition has the sole effect of creating three new actions:
|Prepare|, |Simmer| and |Cook|.
\ddangerexercise How can you make a grammar extension to an ordinary
verb that will apply only to
Dan?^^{extensions for one actor only}
^^{exercises: extensions for one actor only}
\answer{^^{exercises: extensions for one actor only}
Suppose Dan's grammar (but nobody else's) for the ``examine''
verb is to be extended. His grammar routine should also contain:
\beginlines
| if (verb_word == 'examine' or 'x')|
| { verb_wordnum++; return -'danx,'; }|
\endlines^^{extensions for one actor only}^^{cow pie}
(Note the crudity of this: it looks at the actual verb word, so you
have to check any synonyms yourself.) The verb ``danx,'' must be
declared later:
\beginlines
|Verb "danx," * "conscience" -> Inv;|
\endlines
and now ``Dan, examine conscience'' will send him an |Inv| order:
but ``Dan, examine cow pie'' will still send |Examine cow_pie| as usual.}
\dangerexercise Make an alarm clock responding to ``alarm, off'',
``alarm, on'' and ``alarm, half past seven'' (the latter to
set its alarm time).^^{alarm clock}^^{exercises: alarm clock}
\answer{^^{alarm clock}^^{exercises: alarm clock}
\beginlines
|[ PrintTime x; print (x/60), ":", (x%60)/10, (x%60)%10; ];|
|Object -> alarm_clock "alarm clock"|
| with name "alarm" "clock",|
| number 480,|
| description|
| [; print "The alarm is ";|
| if (self has general) print "on, "; else print "off, but ";|
| "the clock reads ", (PrintTime) the_time,|
| " and the alarm is set for ", (PrintTime) self.number, ".";|
| ],|
| react_after|
| [; Inv: if (self in player) { new_line; <<Examine self>>; }|
| Look: if (self in location) { new_line; <<Examine self>>; }|
| ],|
| daemon|
| [; if (the_time >= self.number && the_time <= self.number+3|
| && self has general) "^Beep! Beep! The alarm goes off.";|
| ],|
| grammar [; return 'alarm,'; ],|
| orders|
| [; SwitchOn: give self general; StartDaemon(self); "~Alarm set.~";|
| SwitchOff: give self ~general; StopDaemon(self); "~Alarm off.~";|
| SetTo: self.number=noun; <<Examine self>>;|
| default: "~Commands are on, off or a time of day only, pliz.~";|
| ],|
| life|
| [; Ask, Answer, Tell:|
| "[Try ~clock, something~ to address the clock.]";|
| ],|
| has talkable;|
\endlines
and add a new verb to the grammar:
\beginlines
|Verb "alarm," * "on" -> SwitchOn|
| * "off" -> SwitchOff|
| * TimeOfDay -> SetTo;|
\endlines
(using the \cstok{TimeOfDay} token from the exercises of \S 27). Note
that since the word ``alarm,'' can't be matched by anything the player types,
this verb is concealed from ordinary grammar. The orders we produce here
are not used in the ordinary way (for instance, the action |SwitchOn| with
no |noun| or |second| would never ordinarily be produced by the parser) but this
doesn't matter: it only matters that the grammar and the |orders| property
agree with each other.}
\dangerexercise Implement a ^{tricorder} (from
Star Trek) which analyses nearby objects on a request like
``tricorder, the quartz stratum''.^^{exercises: tricorder}
\answer{^^{Star Trek: The Next Generation}^^{tricorder}
^^{exercises: tricorder}
\beginlines
|Object -> tricorder "tricorder"|
| with name "tricorder",|
| grammar [; return 'tc,'; ],|
| orders|
| [; Examine: if (noun==player) "~You radiate life signs.~";|
| print "~", (The) noun, " radiates ";|
| if (noun hasnt animate) print "no ";|
| "life signs.~";|
| default: "The tricorder bleeps.";|
| ],|
| life|
| [; Ask, Answer, Tell: "The tricorder is too simple.";|
| ],|
| has talkable;|
|...|
|Verb "tc," * noun -> Examine;|
\endlines}
\dangerexercise And, for good measure, a ^{replicator}
responding to commands like ``replicator, tea earl grey''
and ``replicator, aldebaran brandy''.^^{Earl Grey tea}
^^{Aldebaran brandy}^^{exercises: replicator}
\answer{^^{Star Trek: The Next Generation}^^{replicator}
^^{exercises: replicator}
\beginlines
|Object replicator "replicator"|
| with name "replicator",|
| grammar [; return 'rc,'; ],|
| orders|
| [; Give:|
| if (noun in self)|
| "The replicator serves up a cup of ",|
| (name) noun, " which you drink eagerly.";|
| "~That is not something I can replicate.~";|
| default: "The replicator is unable to oblige.";|
| ],|
| life|
| [; Ask, Answer, Tell: "The replicator has no conversation skill.";|
| ],|
| has talkable;|
|Object -> "Earl Grey tea" with name "earl" "grey" "tea";|
|Object -> "Aldebaran brandy" with name "aldebaran" "brandy";|
|Object -> "distilled water" with name "distilled" "water";|
|...|
|Verb "rc," * held -> Give;|
\endlines
The point to note here is that the \cstok{held} token means `held by the
replicator' here, as the |actor| is the replicator, so this is a neat way of
getting a `one of the following phrases' token into the grammar.}
\ddangerexercise And a ^{communications badge} in contact with the ship's
computer, which answers questions like
``computer, where is Admiral Lebling''.^^{P. David Lebling}
^^{Star Trek: The Next Generation}^^{exercises: communications badge}
\answer{^^{Star Trek: The Next Generation}^^{communications badge}
^^{exercises: communications badge}
This is similar to the previous exercises. One creates an attribute called
|crewmember| and gives it to the crew objects: the |orders| property is
\beginlines
| orders|
| [; Examine:|
| if (parent(noun)==0)|
| "~", (name) noun,|
| " is no longer aboard this demonstration game.~";|
| "~", (name) noun, " is in ", (name) parent(noun), ".~";|
| default: "The computer's only really good for locating the crew.";|
| ],|
\endlines
and the |grammar| simply returns |'stc,'| which is defined as
\beginlines
|[ Crew i;|
| switch(scope_stage)|
| { 1: rfalse;|
| 2: objectloop (i has crewmember) PlaceInScope(i); rtrue;|
| }|
|];|
|Verb "stc," * "where" "is" scope=Crew -> Examine;|
\endlines
An interesting point is that the scope routine doesn't need to do anything
at stage 3 (usually used for printing out errors) because the normal
error-message printing system is never reached. Something like ``computer,
where is Comminder Doto'' causes a |##NotUnderstood| order.}
\ddangerexercise Finally, construct the formidable flight computer
Zen.^^{exercises: Zen flight computer}
\answer{^^{Zen}^^{flight computer}^^{Blake's 7}
^^{exercises: Zen flight computer}
\beginlines
|Object Zen "Zen" Flight_Deck|
| with name "zen" "flight" "computer",|
| initial "Square lights flicker unpredictably across a hexagonal|
| fascia on one wall, indicating that Zen is on-line.",|
| grammar [; return -'zen,'; ],|
| orders|
| [; Show: "The main screen shows a starfield,|
| turning through ", noun, " degrees.";|
| Go: "~Confirmed.~ The ship turns to a new bearing.";|
| SetTo: if (noun==0) "~Confirmed.~ The ship comes to a stop.";|
| if (noun>12) "~Standard by ", (number) noun,|
| " exceeds design tolerances.~";|
| "~Confirmed.~ The ship's engines step to|
| standard by ", (number) noun, ".";|
| Take: if (noun~=force_wall) "~Please clarify.~";|
| "~Force wall raised.~";|
| Drop: if (noun~=blasters) "~Please clarify.~";|
| "~Battle-computers on line.|
| Neutron blasters cleared for firing.~";|
| NotUnderstood: "~Language banks unable to decode.~";|
| default: "~Information. That function is unavailable.~";|
| ],|
| has talkable proper static;|
|Object -> force_wall "force wall" with name "force" "wall" "shields";|
|Object -> blasters "neutron blasters" with name "neutron" "blasters";|
|...|
|Verb "zen," * "scan" number "orbital" -> Show|
| * "set" "course" "for" Planet -> Go|
| * "speed" "standard" "by" number -> SetTo|
| * "raise" held -> Take|
| * "clear" held "for" "firing" -> Drop;|
\endlines
Dealing with |Ask|, |Answer| and |Tell| are left to the reader.}
\medskip\par\noindent
The next two exercises really belong to \S 28, but are too useful
(for the ``someone on the other end of a phone'' situation) to
bury far away. Note that an alternative to these scope-hacking
tricks, if you just want to implement something like ``michael,
tell me about the crystals'' (when Michael is at the other end of the
line), is to make the phone a |talkable| object and make the word
|'michael'| refer to the phone (using a |parse_name| routine).
For more on scope hacking, see \S 28. Note that the variable |scope_reason|
is always set to the constant value |TALKING_REASON| when the game is trying
to work out who you wish to talk to: so it's quite easy to make the
scope different for conversational
purposes.^^|TALKING REASON|^^|scope reason|
\dangerexercise Via the main ^{screen} of the
^{Starship Enterprise}, ^{Captain Picard} wants to see and talk to
^{Noslen Maharg}, the notorious tyrant, who is down on the planet
^{Mrofni}. Make it so.^^{Star Trek: The Next Generation}
^^{exercises: Picard and Maharg}
\answer{^^{screen}^^{Starship Enterprise}^^{Captain Picard}^^{Noslen Maharg}
^^{Star Trek: The Next Generation}^^{Mrofni}^^{exercises: Picard and Maharg}
\beginstt
[ InScope;
if (action_to_be == ##Examine or ##Show or ##ShowR)
PlaceInScope(noslen_maharg);
if (scope_reason == TALKING_REASON)
PlaceInScope(noslen_maharg);
];
\endtt
Note that ^|ShowR| is a variant form of |Show| in which the parameters
are `the other way round': thus ``show maharg the phaser'' generates
|ShowR maharg phaser| internally, which is then converted to the more
usual |Show phaser maharg|.}
\ddangerexercise Put the player in ^{telepathic contact} with
^{Martha}, who is in a ^{sealed room} some distance away, but who has
a talent for ^{telekinesis}. Martha should respond well to
``martha, look'', ``ask martha about...'', ``say yes to martha'',
``ask martha for red ball'', ``martha, give me the red ball'' and
the like.^^{exercises: Martha the telepath}
\answer{^^{telepathic contact}^^{Martha}^^{sealed room}^^{telekinesis}
^^{exercises: Martha the telepath}
Martha and the sealed room are defined as follows:
\beginlines
|Object sealed_room "Sealed Room"|
| with description|
| "I'm in a sealed room, like a squash court without a door,|
| maybe six or seven yards across",|
| has light;|
|Object -> ball "red ball" with name "red" "ball";|
|Object -> martha "Martha"|
| with name "martha",|
| orders|
| [ r; r=parent(self);|
| Give:|
| if (noun notin r) "~That's beyond my telekinesis.~";|
| if (noun==self) "~Teleportation's too hard for me.~";|
| move noun to player;|
| "~Here goes...~ and Martha's telekinetic talents|
| magically bring ", (the) noun, " to your hands.";|
| Look:|
| print "~", (string) r.description;|
| if (children(r)==1) ". There's nothing here but me.~";|
| print ". I can see ";|
| WriteListFrom(child(r),CONCEAL_BIT+ENGLISH_BIT);|
| ".~";|
| default: "~Afraid I can't help you there.~";|
| ],|
| life|
| [; Ask: "~You're on your own this time.~";|
| Tell: "Martha clucks sympathetically.";|
| Answer: "~I'll be darned,~ Martha replies.";|
| ],|
| has animate female concealed proper;|
\endlines
but the really interesting part is the ^|InScope| routine to fix
things up:
\beginlines
|[ InScope actor;|
| if (actor==martha) PlaceInScope(player);|
| if (actor==player && scope_reason==TALKING_REASON)|
| PlaceInScope(martha);|
| rfalse;|
|];|
\endlines
Note that since we want two-way communication, the player has to
be in scope to Martha too: otherwise Martha won't be able to
follow the command ``martha, give me the fish'', because ``me''
will refer to something beyond her scope.}
\tenpoint
\refs
A much fuller example of a `non-player character' is given in
the example game ^{`The Thief'}, by ^{Gareth Rees} (though it's
really an implementation of the gentleman in ^{`Zork'}, himself
an imitation of the pirate in ^{`Advent'}). The thief is
capable of walking around, being followed, stealing things,
picking locks, opening doors and so on.
\nextref Other good definitions of |animate| objects to look at
are Christopher in ^{`Toyshop'}, who will stack up building blocks
on request; the kittens in ^{`Alice Through The Looking-Glass'}; the
barker in ^{`Balances'}, and the cast of ^{`Advent'}: the little
bird, the snake, bear and dragon, the pirate and of course the
threatening little dwarves.
\nextref Following people means being able to refer to them after
they've left the room: see ^{`Follow my leader'}, also by Mr Rees,
or the library extension ^{``follower.h''} by ^{Andrew Clover}.
\nextref See the Inform home page for a way round the |Yes|
awkwardness.
\nextref For parsing topics of conversation in advanced ways,
see the example game ^{`Encyclopaedia Frobozzica'}
by ^{Gareth Rees}.
\nextref To see how much a good set of characters can do for a
game, try playing the prologue of ^{`Christminster'}.
\newpage
\section{17}{The light and the dark}
\noindent^^{light}^^{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 versus darkness is
tricky to get right, and 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. because it is outdoors in day-time.
If you simply never want to have darkness, a
sneaky way of doing it is to put the line
\begintt
give player light;
\endtt^^{darkness: abolition of}
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.\medskip
\noindent{\bf Definition.}\quad^^{darkness: when it occurs}
^^{light: when it occurs}
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;\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, {\bf or}\cr
any of the things it ``adds to scope'' (see Chapter V) have light.\cr
\enddisplay
The process of checking this stops as soon as light is discovered. The
routines
\begindisplay
|OffersLight(object)| and |HasLightSource(object)|
\enddisplay^^|OffersLight|^^|HasLightSource|
return true or false 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$\ldots$
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$\ldots$ so that the troll will
be as happy with a ^{goldfish bowl} containing a ^{fluorescent jellyfish} as he
would be with a lamp?^^{exercises: troll afraid of the dark}
\answer{^^{exercises: troll afraid of the dark}
Just test if |HasLightSource(gift)==1|.}
\noindent
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|^^{darkness: moving through}
and if you do then it will be called when the player goes from one dark
room into another dark one (just before the room description for the new
dark room, probably ``Darkness'', is printed). 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).
\danger When the player is in darkness, the current |location| becomes
|thedark|, a special object which acts like a room and has the short name
``Darkness''. You can change the |initial|, |description| or |short_name|
properties for this. For example, your |Initialise| routine might set
\beginstt
thedark.short_name = "Creepy, nasty darkness";
\endtt^^{darkness: special object}
See \S 18 for how `Ruins' makes darkness menacing.
\dangerexercise Implement a ^{pet moth} which escapes if it's ever
taken into darkness.^^{exercises: pet moth escapes in the dark}
\answer{^^{pet moth}^^{exercises: pet moth escapes in the dark}
We could solve this using a daemon, but for the
sake of demonstrating a feature of |thedark| we won't.
In |Initialise|, write |thedark.initial = GoMothGo;|
and add the routine:
\beginstt
[ GoMothGo;
if (moth in player)
{ remove moth;
"As your eyes try to adjust, you feel a ticklish sensation
and hear a tiny fluttering sound.";
}
];
\endtt}
\refs For a |DarkToDark| routine which discourages wandering about caves
in the dark, see ^{`Advent'}.
\newpage
\section{18}{Daemons and the passing of time}
\widequote
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} ({\oldstyle1898}--{\oldstyle1963})}{The Discarded Image}
\widequote
A great Daemon$\ldots$ Through him subsist all
divination, and the science of sacred things as it relates
to sacrifices, and expiations, and disenchantments, and
prophecy, and magic$\ldots$ he who is wise in the science
of this intercourse is supremely happy$\ldots$\
\tlwidequoteby{^{Plato} (c.{\oldstyle427}--{\oldstyle347} BC),
{\it The Symposium}}{translated by ^{Percy Bysshe Shelley}
({\oldstyle1792}--{\oldstyle1822})}
\noindent
In medieval ^{neo-Platonist philosophy}, daemons are the intermediaries
of God, hovering invisibly over the world and interfering with it.
They may be guardian spirits of places or people. So, here, a daemon is
a meddling spirit, associated with a particular game object, which
gets a chance to interfere once per turn while it is `active'.
The classic example is of the dwarves of ^{`Advent'}, who
appear in the cave from time to time: a daemon routine attached to
the dwarf object moves it about, throws knives at the player and
so on.^^{daemons}\
Each object can have a ^|daemon| routine of its own. This is set
going, and stopped again, by calling the (library) routines
\begintt
StartDaemon(object);
StopDaemon(object);
\endtt^^{daemons: starting and stopping}
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 sometimes remain active throughout. For instance, a lamp-battery
daemon might do something every turn, while others may hide for many
turns before pouncing: such as the daemon in ^{`Advent'} which waits
until the player has found all the treasures.^^|StartDaemon|^^|StopDaemon|
\danger In particular, a daemon doesn't stop running just because the player
has moved on to somewhere else. (Indeed, the library never stops a daemon
unless told to.) 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.
\exercise Many games contain ^{`wandering monsters'}, characters who walk
around the map. Use a daemon
to implement one who wanders as freely as the player, like the
gentleman ^{thief in `Zork'}^^{`Zork'}.^^{gentleman thief}
^^{exercises: thief who wanders}
\answer{^^{exercises: thief who wanders}
This is a crude implementation, for brevity (the real Zork
thief has an enormous stock of attached messages). A |life| routine
is omitted, and of course this particular thief steals
nothing. See ^{`The Thief'} for a much fuller,
annotated implementation.^^{thief in `Zork'}^^{gentleman thief}
\beginlines
|Object -> thief "thief"|
| with name "thief" "gentleman" "mahu" "modo",|
| 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 ofclass 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 ofclass 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;|
| }|
| }|
| ],|
| has animate;|
\endlines
(Not forgetting to |StartDaemon(thief)| at some point, for instance
in the game's |Initialise| routine.) So the thief walks at random but
never via 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. As for the |name|, note that `The ^{Prince of darkness} is
a gentleman. ^{Modo} he's called, and ^{Mahu}'
(^{William Shakespeare}, {\it King Lear} III iv).}
\dangerexercise
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.^^{exercises: weight--watching daemon}
\answer{^^{exercises: weight--watching daemon}
We shall use a new property called |weight| and decide that
any object which doesn't provide any particular weight will weigh
10 units. Clearly, an object which contains other objects will
carry their weight too, so:
\beginlines
|[ WeightOf obj t i;|
| if (obj provides weight) t = obj.weight; else t = 10;|
| objectloop (i in obj) t = t + WeightOf(i);|
| return t;|
|];|
\endlines
Once every turn we shall check how much the player is carrying
and adjust a measure of the player's fatigue accordingly. There
are many ways we could choose to calculate this: for the sake of
example we'll define two constants:
\beginlines
|Constant CARRYING_STRENGTH = 500;|
|Constant HEAVINESS_THRESHOLD = 100;|
\endlines
Initially the player's strength will be the maximum possible,
which we'll set to 500. Each turn the amount of weight being
carried is substracted from this, but 100 is also added on
(without exceeding the maximum value). So if the player carries
more than 100 units, then her strength declines, but by dropping
things to get the weight below 100 she can allow it to recover.
If she drops absolutely everything, her entire strength will
recuperate in at most 5 turns. Exhaustion sets in if her strength
reaches 0, and at this point she is forced to drop something,
which gives her strength a slight boost. Anyway, here's an
implementation of all this:^^{fatigue daemon}
\beginlines
|Object weight_monitor|
| with players_strength,|
| warning_level 5,|
| activate|
| [; self.players_strength = CARRYING_STRENGTH; StartDaemon(self);|
| ],|
| daemon|
| [ w s b bw;|
| if (location ~= Weights_Room) { StopDaemon(self); return; }|
| s = self.players_strength|
| - WeightOf(player) + HEAVINESS_THRESHOLD;|
| if (s<0) s=0; if (s>CARRYING_STRENGTH) s=CARRYING_STRENGTH;|
| self.players_strength = s;|
| if (s==0)|
| { bw=-1;|
| objectloop(b in player)|
| if (WeightOf(b) > bw) { bw = WeightOf(b); w=b; }|
| self.players_strength = self.players_strength + bw;|
| print "^Exhausted with carrying so much, you decide |
| to discard ", (the) w, ": "; <<Drop w>>;|
| }|
| w=s/100; if (w==self.warning_level) return;|
| self.warning_level = w;|
| switch(w)|
| { 3: "^You are feeling a little tired.";|
| 2: "^You possessions are weighing you down.";|
| 1: "^Carrying so much weight is wearing you out.";|
| 0: "^You're nearly exhausted enough to drop everything|
| at an inconvenient moment.";|
| }|
| ];|
\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}.) Finally, of course, at some point
the weight monitor has to be sent an |activate| message to get things
going.}
\medskip
\noindent
A `timer' (these are traditionally called `^{fuses}') can also
be attached to an object. A timer is started with
\begintt
StartTimer(object, time);
\endtt^^{timers}^^|StartTimer|
^^{daemons: clash with timers}^^{timers: clash with daemons}
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, once and once only, when the time comes.
The timer can be deactivated (so that it will never go off) by calling
\begintt
StopTimer(object);
\endtt^^|StopTimer|^^{timers: starting and stopping}
A timer is required to provide a |time_left| property, to hold the
amount of time left. (If it doesn't, an error message is printed
at run-time.) You can alter |time_left| yourself: a value of 0 means `will
go off at the end of this turn', so setting |time_left| to 0 triggers
immediate activation.
\danger Normally, you can only have 32 timers or daemons active at the same
time as each other (plus 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.^^{daemons: maximum number active}
^^{timers: maximum number active}
\medskip\noindent
There is yet a third form of timed event. If a room provides an |each_turn|
routine, then this will be called at the end of each turn while the player
is there; if an object provides |each_turn|, this is called while 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.^^{stream running through forest}\
'Each turn' is especially useful to run creatures which stay
in one room and are only active when the player is nearby.
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 |scope_reason| variable
(see \S 28). 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'}.
^^|scope reason|^^{audibility}^^{earshot}^^{thief in `Zork'}
\exercise (Why the ^{`Ruins'} are claustrophobic.) Make
``the ^{sound of scuttling claws}'' approach the player in darkness and,
after 4 consecutive turns in darkness, kill him.^^{scuttling claws}
^^{exercises: scuttling claws}
\answer{^^{exercises: scuttling claws}See the next answer.}
\dangerexercise A little harder: implement the scuttling claws in a single
object definition, with no associated code anywhere else in the program
(not even a line in |Initialise|) and without running its daemon all the
time.
\answer{^^{scuttling claws}^^{sound of scuttling claws}^^{`Ruins'}
\beginlines
|Object tiny_claws "sound of tiny claws" thedark|
| with article "the",|
| name "tiny" "claws" "sound" "of" "scuttling" "scuttle"|
| "things" "creatures" "monsters" "insects",|
| initial "Somewhere, tiny claws are scuttling.",|
| before|
| [; Listen: "How intelligent they sound, for mere insects.";|
| Touch, Taste: "You wouldn't want to. Really.";|
| Smell: "You can only smell your own fear.";|
| Attack: "They easily evade your flailing about in the dark.";|
| default: "The creatures evade you, chittering.";|
| ],|
| each_turn [; StartDaemon(self); ],|
| number 0,|
| daemon|
| [; if (location~=thedark) { self.number=0; StopDaemon(self); rtrue; }|
| switch(++(self.number))|
| { 1: "^The scuttling draws a little nearer, and your breathing|
| grows loud and hoarse.";|
| 2: "^The perspiration of terror runs off your brow. The|
| creatures are almost here!";|
| 3: "^You feel a tickling at your extremities and kick outward,|
| shaking something chitinous off. Their sound alone|
| is a menacing rasp.";|
| 4: deadflag=1;|
| "^Suddenly there is a tiny pain, of a hypodermic-sharp fang|
| at your calf. Almost at once your limbs go into spasm,|
| your shoulders and knee-joints lock, your tongue swells...";|
| }|
| ];|
\endlines}
\bigskip
\noindent
The library also has the (limited) ability to keep track of ^{time of day}
as the game goes on. The current time is held in the variable |the_time|
and runs on a 24-hour clock: this variable holds minutes since midnight,
so it has values between 0 and 1439. The time can be set by
\begindisplay
|SetTime(| 60$\times$\<hours>$+$\<minutes>|,| \<rate> |);|
\enddisplay^^|SetTime|
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, while a negative |rate| means that many turns pass between each
minute. (It's usual for a timed game to start off the clock by calling
|SetTime| in its ^|Initialise| routine.)
The time only (usually) appears on the game's status line if you set
\begintt
Statusline time;
\endtt^^|Statusline|
as a directive somewhere in your code.
\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?^^{exercises: midnight}
\answer{^^{exercises: midnight}
Either set a daemon to watch for |the_time| suddenly dropping, or
put such a watch in the game's |TimePasses| routine.}
\dangerexercise (Cf. ^{Sam Hulick}'s ^{vampire} game, ^{`Knight of Ages'}.)
Make the lighting throughout the game change at
^{sunrise and sunset}.^^{daylight}^^{light: daylight}
^^{nightfall}^^{darkness: nightfall}^^{exercises: nightfall and daybreak}
\answer{^^{sunrise and sunset}^^{daylight}^^{nightfall}^^{darkness: nightfall}
^^{light: daylight}^^{exercises: nightfall and daybreak}
A minimal solution is as follows:
\beginlines
|Constant SUNRISE 360; ! i.e., 6 am|
|Constant SUNSET 1140; ! i.e., 7 pm|
|Attribute outdoors; ! Give this to external locations|
|Attribute lit; ! And this to artificially lit ones|
|Global day_state = 2;|
|[ TimePasses f obj;|
| if (the_time >= SUNRISE && the_time < SUNSET) f=1;|
| if (day_state == f) rfalse;|
| objectloop (obj)|
| { if (obj has lit) give obj light;|
| if (obj has outdoors && obj hasnt lit)|
| { if (f==0) give obj ~light; else give obj light;|
| }|
| }|
| if (day_state==2) { day_state = f; return; }|
| day_state = f; if (location hasnt outdoors) return;|
| if (f==1) "^The sun rises, illuminating the landscape!";|
| "^As the sun sets, the landscape is plunged into darkness.";|
|];|
\endlines
In the |Initialise| routine, set the time (using |SetTime|)
and then call |TimePasses| to set all the |light| attributes
accordingly. Note that with this system, there's no need to
set |light| at all: that's automatic.}
\ninepoint
\danger Exactly what happens at the end of each turn is:^^{time sequence}
\smallskip
\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\smallskip\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}
^^{exercises: mid-air location}
\answer{^^{exercises: mid-air location}
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.^^{daemons: 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?^^{exercises: long time-scale game}
\answer{^^{exercises: long time-scale game}
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.}
\refs Daemons abound in most games. ^{`Advent'} uses them to run
down the lamp batteries, make the bear follow you, animate the
dwarves and the pirate and watch for the treasure all being found.
See also the flying tortoise from ^{`Balances'} and the chiggers
from ^{`Adventureland'}. For more ingenious uses of |daemon|,
see the helium balloon, the matchbook and (particularly cunning)
the pair of white gloves in ^{`Toyshop'}.
\nextref
Classic timers include the burning match and the hand grenade
from ^{`Toyshop'}, the endgame timer from ^{`Advent'} and the
^{`Balances'} cyclops (also employing |each_turn|).
\nextref
^{`Adventureland'} makes much use of |each_turn|: see the
golden fish, the mud, the dragon and the bees.
\nextref
The library extension ^{`timewait.h'} by ^{Andrew Clover}
thoroughly implements time of day, allowing the player to ``wait until
quarter past three''.
\section{19}{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} ({\oldstyle1645}--{\oldstyle1696})}
\poem
Life's but a walking shadow, a poor player
That struts and frets his hour upon the stage
And then is heard no more; it is a tale
Told by an idiot, full of sound and fury,
Signifying nothing.
\poemby{^{William Shakespeare} ({\oldstyle1564}--{\oldstyle1616})}{^{Macbeth} V. v}
\noindent
The only compulsory task for a game's |Initialise| routine is to
set the |location| variable to the place where the player should begin.
This is usually a room (and is permitted to be one that's in darkness)
but could instead be an object inside a room, such as a chair or a bed.
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}
Games with a long opening sequence might want to start by offering the player
a chance to restore a saved game at once. They can do so by writing the
following in their |Initialise| routines:
\beginstt
print "Would you like to restore a game? >";
if (YesOrNo()) <Restore>;
\endtt
(If you want to make the status line invisible during an opening sequence, see
\S 33.) |Initialise| normally returns 0 or 1 (it doesn't matter which), but
if it returns 2 then no game banner will be printed at once. (This is for
games which, like ^{`Sorcerer'}, delay their banners until after the prologue.)
^{`Ruins'}, however, opens in classical fashion:
\beginlines
|[ Initialise;|
| TitlePage();|
| location = Forest;|
| move food_ration to player;|
| move sodium_lamp to player;|
| move dictionary to player;|
| thedark.description = "The darkness of ages presses in on you, and you|
| feel claustrophobic.";|
| "^^^^^Days of searching, days of thirsty hacking through the briars of|
| the forest, but at last your patience was rewarded. A discovery!^";|
|];|
\endlines
\medskip\noindent
(The ^|TitlePage| routine will be an exercise in \S 33: `Ruins' is really
too small a game to warrant one, but never mind.)
The ^|location| variable needs some explanation. It holds either the current
room, if there's light to see by, or the special value ^|thedark| (the
``Darkness'' object) if there isn't. In the latter case (but only in the
latter case) the actual current room is held in the variable |real_location|,
should you need to know it. Neither of these is necessarily the same as
the parent of the |player| object. For instance, if the player sits in a
jeep parked in a dark garage, then |location| is |thedark|, |real_location|
is |Garage| and |parent(player)| is |jeep|.^^|real location|\
Because of this, one shouldn't simply |move| the player object by hand.
Instead, to move the player about (for ^{teleportation} of some kind),
use the routine |PlayerTo(place);| (which automatically takes care of
printing the new room's description if there's enough light there to see
by).^^|PlayerTo|\
\danger |PlayerTo| can also be used to move the player to a |place| inside
a room (e.g., a cage, or a traction engine).
\danger Calling |PlayerTo(place, 1);| moves the player but prints
nothing (in particular, prints no room description).
\danger Calling |PlayerTo(place, 2);| will |Look| as if the player had
arrived in the room by walking in as usual, so only a short description
appears if the room is one that has been seen before.
\danger In a process called `scoring arrival', a room which the player has entered
for the first time is given the |visited| attribute. If it was listed
as |scored|, points are awarded. (See \S 14.)
\ddanger When a |Look| action takes place, or a call to |PlayerTo(place,1)|,
the library `notes arrival' as well as `scores arrival'.
`Noting arrival' consists of checking to see if the room has changed
since last time (darkness counting as a different room for this purpose).
If so, the following happens:
\ruleson
\item{1.} If the new location has an ^|initial| property, this is printed
if it's a string, or run if it's a routine.
\item{2.} The entry point ^|NewRoom| is called (if it exists).
\item{3.} Any `^{floating objects}', such as drifting mist, which are |found_in|
many places at once, are moved into the room.^^|found in|^^{moving room}^^{changing room}
\rulesoff
\medskip
\noindent
The player's whole persona can easily be changed, because the player object
can itself have an |orders| routine, just as the object for any non-player
character can. To replace the |orders| routine for the standard |player|
object, set
\beginstt
player.orders = MyNewRule;
\endtt^^{changing the player}^^{persona of player}^^|orders|
where |MyNewRule| is a new |orders| rule. Note that this is applied to
every action or order issued by the player. The variable |actor| holds the
person being told to do something, which may well be the player himself,
and the variables |action|, |noun| and |second| are set up as usual.
For instance, if a cannon goes off right next to the player,
a period of partial deafness might ensue:
\beginstt
[ MyNewRule;
if (actor~=player) rfalse;
Listen: "Your hearing is still weak from all that cannon-fire.";
];
\endtt^^{cannon-fire}^^{deafness, a period of}
The |if| statement needs to be there to prevent commands like
``helena, listen'' from being ruled out -- after all, the player
can still speak.
\dangerexercise Why not achieve the same effect by giving the player
a |react_before| rule instead?^^{exercises: player reacting before}
\answer{^^{exercises: player reacting before}
Two reasons. Firstly, there are times when we want to be able
to trap orders to other people, which |react_before| does not.
Secondly, the player's |react_before| rule is not necessarily
the first to react. In the case of the player's deafness, a ^{cuckoo}
may have already used |react_before| to sing. But it would have been
safe to use |GamePreRoutine|, if a little untidy (because a rule about
the player would not be part of the player's definition, which makes
for confusing source code). See \S 9 for the exact sequence of events
when actions are processed.}
\exercise (Cf. ^{`Curses'}.) Write an |orders| routine for the player
so that wearing the ^{gas mask} will prevent him from
talking.^^{silence, imposition on player}
^^{talking, preventing player from}
^^{exercises: silencing player}
\answer{^^{gas mask}^^{`Curses'}^^{silence, imposition on player}
^^{talking, preventing player from}^^{exercises: silencing player}
\beginlines
| orders|
| [; if (gasmask hasnt worn) rfalse;|
| if (actor==self && action~=##Answer or ##Tell or ##Ask) rfalse;|
| "Your speech is muffled into silence by the gas mask.";|
| ],|
\endlines}
\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}
\danger Calling |ChangePlayer(object,1);| will do the same but make the
game print ``(as Whoever)'' during room descriptions.
\ddanger When the person to be changed into has an |orders| routine,
things start to get complicated. It may be useful to arrange such a
routine as follows:
\beginlines
| orders|
| [; if (player==self)|
| { ! I am the player object...|
| if (actor==self)|
| { ! ...giving myself an order, i.e., trying an action.|
| }|
| else|
| { ! ...giving someone else, the "actor", an order.|
| }|
| }|
| else|
| { ! The player is the "actor" and is giving me an order.|
| }|
| ],|
\endlines
\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}.^^{exercises: the player's wayhel}
\answer{^^{exercises: the player's wayhel}
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.",|
| orders|
| [; Go, Look, Examine, Eat, Smell, Taste, Touch: rfalse;|
| default: "Warthogs can't do anything as tricky as that!";|
| ],|
| has animate proper;|
\endlines^^{warthog}^^{nagual}
and we just |ChangePlayer(warthog);|. Note that the same |orders|
routine applies to the player-as-human typing ``warthog, listen''
as to the player-as-warthog typing just ``listen''.}
\ddangerexercise Write an |orders| routine for a ^{Giant with a conscience},
who will refuse to attack a mouse, but so that a player who becomes
the Giant can be as cruel as he likes.^^{exercises: Giant with conscience}
\answer{^^{Giant with a conscience}^^{exercises: Giant with conscience}
\beginlines
| orders|
| [; if (player==self)|
| { if (actor~=self)|
| "You only become tongue-tied and gabble.";|
| rfalse;|
| }|
| Attack: "The Giant looks at you with doleful eyes.|
| ~Me not be so bad!~";|
| default: "The Giant is unable to comprehend your instructions.";|
| ],|
\endlines}
\medskip\noindent^^{death}
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}^^{death: and 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.
\refs
The magic words ``xyzzy'' and ``plugh'' in ^{`Advent'} make use of
|PlayerTo|.
\nextref
^{`Advent'} has an amusing |AfterLife| routine: for instance,
try collapsing the bridge by leading the bear across, then returning
to the scene after resurrection. ^{`Balances'} has one which only
slightly penalises death.
\newpage
\section{20}{Miscellaneous constants and scoring}
\poem
For when the One Great Scorer comes
To write against your name,
He marks -- not that you won or lost --
But how you played the game.
\poemby{^{Grantland Rice} ({\oldstyle1880}--{\oldstyle1954})}{Alumnus Football}
\noindent
Some game rules can be altered by defining `constants' at the start of
the program. Two constants you {\it must} provide (and before including
any of the library files) are the strings |Story| and |Headline|:
\beginstt
Constant Story "ZORK II";
Constant Headline "^An Interactive Plagiarism^
Copyright (c) 1995 by Ivan O. Ideas.^";
\endtt^^{plagiarism}^^{Ivan O. Ideas}
All the rest are optional, but should be defined before |Verblib|
is included if they're to take effect.
\medskip\noindent
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
nearly removes the rule. In fact you can change this during play,
since it is actually the |capacity| of the |player| 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. For instance,
the following code appears (in between inclusion of |Parser|
and |Verblib|) in ^{`Toyshop'}:
\beginstt
Object satchel "satchel"
with description "Big and with a smile painted on it.",
name "satchel", article "your",
when_closed "Your satchel lies on the floor.",
when_open "Your satchel lies open on the floor.",
has container open openable;
Constant SACK_OBJECT satchel;
\endtt^^{satchel}^^|SACK OBJECT|
^{`Ruins'} isn't going to provide this feature, because there
are few portable objects and those there are would be incongruous
if described as being in a rucksack.
\medskip\noindent
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, though the ``fullscore'' verb might
then not fully account for what's happened.
One scores points for getting certain
items or reaching certain places; the other for completing certain
actions. These 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
Array task_scores -> t1 t2 ... tn;
\endtt^^|task scores|^^|MAX SCORES|^^|NUMBER TASKS|^^|OBJECT SCORE|^^|ROOM SCORE|
As this is a byte array, the task scores must be between 0 and 255.
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|\
The entry point ^|PrintTaskName| prints the name of a game task (but, of
course, is only ever called in a game with |TASKS_PROVIDED| defined).
For instance, (^{`Toyshop'} again)
\beginstt
[ PrintTaskName ach;
switch(ach)
{ 0: "eating a sweet";
1: "driving the car";
2: "shutting out the draught";
3: "building a tower of four";
4: "seeing which way the mantelpiece leans";
}
];
\endtt
\noindent
Another entry point, called ^|PrintRank|, gets the chance to print
something additional to the score (traditionally, though not
necessarily, rankings). For instance, we bid farewell to the
^{`Ruins'} with the following:
\beginstt
[ PrintRank;
print ", earning you the rank of ";
switch(score)
{ 0 to 9: "humble rainforest Tourist.";
10 to 19: "Investigator.";
20 to 29: "Acquisitor.";
30 to 49: "Archaeologist.";
50: "Master Archaeologist.";
}
];
\endtt
\medskip
\noindent
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|
\medskip
\noindent
The verbs ``objects'' and ``places'' are usually provided, so the player
can get a list of all handled objects (and where they now are), and all
places visited. If you don't want these to be present, define the constant
|NO_PLACES| before inclusion of the
library.^^|NO PLACES|^^{``objects'' verb}^^{``places'' verb}
\dangerexercise Suppose one single room object is used internally for the
64 squares of a gigantic ^{chessboard}, each of which is a different location
to the player. Then ``places'' is likely to result in only the last-visited
square being listed. Fix this.^^{exercises: chessboard of rooms}
\answer{^^{exercises: chessboard of rooms}
Give the ``^{chessboard}'' room a |short_name| routine (it probably
already has one, to print names like ``Chessboard d6'') and make it change
the short name to ``the gigantic Chessboard'' if and only if |action| is
currently set to |##Places|.}
\refs `Advent' contains ranks and an |Amusing| reward (but doesn't use
either of these scoring systems, instead working by hand).
\nextref
`Balances' uses |scored| objects (for its cubes).
\nextref
`Toyshop' has tasks, as above.
\nextref
`Adventureland' uses its |TimePasses| entry point to recalculate the
score every turn (and watch for victory).
\section{21}{Extending and redefining the Library}
\quote
A circulating library in a town is as an ever-green
tree of diabolical knowledge! It blossoms through the year!
\poemby{^{R. B. Sheridan} ({\oldstyle1751}--{\oldstyle1816})}{The Rivals}
\noindent
Most large games will need to enrich the `model world': for
instance, by creating a new concept such as ``magic amulets''. The game
might contain a dozen of these, each with the power to cast a different
spell. So it will need routines which can tell whether or not a given
object is an amulet, and what to do when the spell is cast.
To do this, a game should make a class definition for amulets:
called |Amulet|, say. Then
\beginstt
if (noun ofclass Amulet) ...
\endtt
will test to see if |noun| is one of the amulets, for instance.
The amulet's spell will be represented by the property |amulet_spell|.
Typical values for this might be:
\beginstt
amulet_spell "The spell fizzles out with a dull phut! sound.",
amulet_spell
[; if (location == thedark)
{ give real_location light;
"There is a burst of magical light!";
}
],
amulet_spell HiddenVault,
amulet_spell
[; return random(LeadRoom, SilverRoom, GoldRoom);
],
\endtt
Then the process of casting the spell for amulet |X| is a matter of
sending the message
\beginstt
X.amulet_spell();
\endtt
which will reply with either: false, meaning nothing has happened;
true, meaning that something did happen; or an object, a room to
teleport the player to. Here is a routine which deals with it all:
\beginstt
[ CastSub destination;
if (noun ofclass Amulet)
{ if (~~(noun provides amulet_spell))
"[Ooops. Forgot to program this amulet_spell.]";
destination = noun.amulet_spell();
switch(destination)
{ false: "Nothing happens.";
true: ;
default: print "You are magically teleported to...^";
PlayerTo(destination);
}
}
else "You only know how to cast spells with amulets.";
];
\endtt
\bigskip\noindent
An elaborate library extension will end up defining many classes,
grammar, actions and verb definitions. These may neatly be packaged
up into an |Include| file and placed with the other library
files.^^{Modular extensions}^^{extensions of the library}\
\ddanger If this file contains the directive |System_file;| then it will
even be possible for games to |Replace| routines from it
(see below).^^|System file|\
\danger The ordinary Library's own properties, such as |description|
or |e_to|, are called ``common properties''. They are special for the
following reason: if an object |O| does not give any value for common
property |P|, then |O.P| can still be looked up, though it can't be
set to something else. (If you tried this with a property of your
own invention, such as |amulet_spell| above, an error would be printed
out at run-time.) The value of |O.P| is just the ``default value''
provided by the Library for property |P|: for example, the default
value of |cant_go| is ``You can't go that way.''
\danger But you can change this default value during play, using the
library's |ChangeDefault| routine. For instance, at a late stage
in the game:
\beginstt
ChangeDefault(cant_go, "You're a Master Adventurer now, and still
you walk into walls!");
\endtt^^|ChangeDefault|^^{walking into walls}
Of course this cannot change defaults for properties of your own
invention, because they haven't got default values.
\ddanger Common properties are also slightly faster to perform
calculations with: the down side is that there's a strictly limited
supply of them (63 in all), of which the library uses up half
already. To indicate that a property needs to be a common property,
use the |Property| directive. For example:
\beginstt
Property door_to;
Property capacity 100;
Property cant_go "You can't go that way.";
\endtt^^{properties: defining new common}
In the latter cases we are giving default values: in the former case,
the default value will just be 0.
\bigskip
\noindent
Major library extensions are rarely needed.
More often, one would like simply to change the stock of
standard messages, such as the ``Nothing is on sale.'' which tends
to be printed when the player asks to buy something, or the ``Taken.''
printed when something is picked up.
This facility is available as follows. Provide a special
object called |LibraryMessages|, which must be defined {\sl between}
the inclusion of the ``Parser" and ``VerbLib" library files.
This object should have just one property, a |before| rule. For
example:
\begintt
Object LibraryMessages
with before
[; Jump: "You jump and float uselessly for a while in
the zero gravity here on Space Station Alpha.";
SwitchOn:
if (lm_n==3)
{ print "You power up ", (the) lm_o, "."; }
];
\endtt^^|LibraryMessages|^^{changing library messages}
The object never physically appears in the game, of course. The idea
is that the |before| rule is consulted before any message is printed:
if it returns false, the standard message is printed; if true, then
nothing is printed, as it's assumed that this has already happened.
The |Jump| action only ever prints one message (usually ``You jump on
the spot.''), but more elaborate actions such as |SwitchOn| have
several (the extreme case is |Take|, with 13). |lm_n| holds the
message number, which counts upwards from 1. The messages and
numbers are given in \S A9. New ^{message numbers} may possibly be
added in future, but old ones will not be renumbered.
An especially useful library message to change is the prompt, normally
set to |"^>"| (new-line followed by |>|). This is printed under the
action |Prompt| (actually a fake action existing for exactly this
purpose). In this way, the game's prompt can be made context-sensitive,
or the ``skipped line on screen each turn'' convention can be removed.
\danger
This prompt is only used in ordinary game play, and not at such keyboard
inputs as yes/no questions or the RESTART/RESTORE/QUIT game over
choice.^^{Game Over choice}\
\exercise Infocom's game ^{`The Witness'} has the prompt ``What should you,
the detective, do next?'' on turn one and ``What next?'' subsequently.
Implement this.^^{`Witness'}^^{prompt}^^{changing the prompt}
^^{``What next?''}^^{exercises: varying the prompt}
\answer{^^{`Witness'}^^{prompt}^^{changing the prompt}^^{``What next?''}
^^{exercises: varying the prompt}
Put the following definition between inclusion of ``Parser'' and
``Verblib'':
\begintt
Object LibraryMessages
with before
[; Prompt: if (turns==1)
print "What should you, the detective, do now?^>";
else
print "What next?^>";
rtrue;
];
\endtt}
\noindent
\ddanger An amusing way to see the system in action is to put
\begintt
Object LibraryMessages
with before
[; print "[", sw__var, ", ", lm_n, "] ";
];
\endtt
into your game (arcane note: |sw__var|, the ``switch variable'', in
this case holds the action number). Another amusing effect is to
simply write |rtrue;| for the |before| routine, which results in an
alarmingly silent game -- ^{blindfold Adventure}, perhaps.
\ddanger
Note that |LibraryMessages| can be used as a sneaky way to add extra
rules onto the back of actions, since there's nothing to stop you
doing real processing in a call to it; or, more happily,
to make messages more sensitive to game context, so that ``Nothing is
on sale.'' might become ``That's not one of the goods on sale.''
inside a ^{shopping mall}.
\ddangerexercise
Write an Inform game in ^{Occitan} (a dialect of ^{medieval French}
spoken in Provence).^^{foreign languages}
^^{translating Inform to foreign languages}
\answer{See the {\it Inform Translator's Manual}. One must provide
a new grammar file (generating the same actions but from different
syntax), tables showing how pronouns, possessives and articles work
in the new language, a sheaf of translated library messages and
so on. But it can be done.}
\medskip\noindent
The Library is itself written in Inform, and with experience it's not
too hard to alter it if need be. But this is an inconvenience and an
inelegant way to carry on. So here is the ^{last resort} in library
modification: work out which routine is giving trouble, and |Replace|
it. 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.
It would be normal to copy the definition of |BurnSub| out of the
library files into your own code, and then modify that copy as needed.
The most popular routine to replace is |DrawStatusLine|: see \S 33 for
several examples.
\ddanger
Inform even allows you to |Replace| ``hardware'' functions like |random|,
which would normally be translated directly to machine opcodes. Obviously,
replacing something like |child| with a software routine will impose an
appreciable speed penalty and slightly increase object code size. Replacing
|random| may however be useful when fixing the random number generator for
game-testing purposes.
\tenpoint
\refs
^{`Balances'} contains a section of code (easily extractable to
other games) implementing the ^{`Enchanter' trilogy}'s magic
system by methods like the above.
\nextref
There are several formal library extension files in existence,
mostly small: see the ^{Inform home page} on the WWW.
\nextref ^{``pluralobj.h''}
by ^{Andrew Clover} makes large-scale use of |LibraryMessages|
to ensure that the library always uses words like ``those''
instead of ``that'' when talking about objects with names like
``a heap of magazines''.
\chapter{Chapter V: Describing and Parsing}
\vskip 0.5in
\quote
Language disguises thought$\ldots$ The tacit conventions on which
the understanding of everyday language depends are enormously
complicated.
\poemby{^{Ludwig Wittgenstein} ({\oldstyle1889}--{\oldstyle1951})}{Tractatus}
\section{22}{Describing objects and rooms}
\poem
And we were angry and poor and happy,
And proud of seeing our names in print.
\poemby{^{G. K. Chesterton} ({\oldstyle1874}--{\oldstyle1936})}{A Song of Defeat}
\noindent
Talking to the player about the state of the world is much easier
than listening to his intentions for it. Despite this, the business of
description takes up a fair part of Chapter V since the
designer of a really complex game will eventually need to know almost
every rule involved. (Whereas nobody would want to know everything
about the parser.)
To begin, the simplest description is the ``short name'' given to a single
object. For instance
\beginstt
print (a) brass_lamp;
\endtt
may result in ``an old brass lamp'' being printed. There are four such
forms of |print|:
\smallskip{
\settabs 8 \columns
\+ &^|print (the) obj| &&& Print the object with its definite article\cr
\+ &^|print (The) obj| &&& The same, but capitalised\cr
\+ &^|print (a) obj| &&& Print the object with indefinite article\cr
\+ &^|print (name) obj| &&& Print the object's short name alone\cr
}
\smallskip\par\noindent^^{objects: short names of}
and these can be freely mixed into lists of things to |print| or
|print_ret|, as for example:
\beginstt
print_ret "The ogre declines to eat ", (the) noun, ".";
\endtt
\exercise (By ^{Gareth Rees}.) When referring to ^|animate| objects, one
usually needs to use ^{pronouns} such as ^{``his''}. Define new
^{printing routines} so that, say,
|print "You throw the book at ", (PronounAcc) obj, "!";| will insert
the right ^{accusative pronoun}.^^{nominative pronoun}
^^{exercises: printing pronouns}
\answer{^^{accusative pronoun}^^{nominative pronoun}^^{pronouns}
^^{exercises: printing pronouns}Simply
define the following (for accusative, nominative and capitalised
nominative pronouns, respectively):
\beginlines
|[ PronounAcc i;|
| if (i hasnt animate) print "it";|
| else { if (i has female) print "her"; else print "him"; } ];|
|[ PronounNom i;|
| if (i hasnt animate) print "it";|
| else { if (i has female) print "she"; else print "he"; } ];|
|[ CPronounNom i;|
| if (i hasnt animate) print "It";|
| else { if (i has female) print "She"; else print "He"; } ];|
\endlines}
\ddanger There is also a special syntax ^|print object| for printing object
names, but {\it do not use it without good reason}: it doesn't understand
some of the features below and is not protected against crashing if you
mistakenly try to print the name for an out of range object number.
\medskip
\noindent
Inform tries to work out the right ^{indefinite article} for
any object automatically. In English-language games, it uses
`an' when the short name starts with a vowel and `a' when it
does not (unless the name is plural, when `some' is used
in either case). You can override this by setting ^|article|
yourself. Here are some possibilities:
\begindisplay
a / platinum bar, an / orange balloon, your / Aunt Jemima,\cr
some bundles of / reeds, far too many / marbles, The / London Planetarium\cr
\enddisplay^^{objects: indefinite articles of}
If the object is given the attribute |proper| then its name is treated as
a ^{proper noun} with no indefinite article, so the value of |article| is
ignored.
\danger The |article| property can also hold a routine to print
one.^^{changing articles}
\noindent
Definite articles are always ``the'' (except for |proper| nouns). Thus
\begindisplay
the platinum bar, Benjamin Franklin, Elbereth\cr
\enddisplay^^{objects: definite articles of}
are all printed by |print (the) ...|; the latter two objects
being ^|proper|.
\danger There's usually no need to worry about definite and indefinite
articles for room objects, as Inform never has cause to print them.
A single object whose name is plural, such as ``grapes'' or
``marble pillars'', should be given the attribute ^|pluralname|.
As a result the library might say, e.g., "You can't open those"
instead of "You can't open that". It also affects the pronoun
``them'' and makes the usual indefinite article ``some''.
\danger You can give |animate| objects the attributes ^|male|,
^|female| or ^|neuter| to help the parser understand pronouns properly.
|animate| objects are assumed to be male if you set neither
alternative.^^{gender in parsing}
\noindent
The short name of an object is normally the text given in double-quotes
at the head of its definition. This is very inconvenient to change
during play when, for example, ``blue liquid'' becomes
``purple liquid'' as a result of a
^{chemical reaction}.^^{changing short names}\ A more flexible way
to specify an object's short name is with the |short_name|
property.^^|short name|\
To print the name of such an object, Inform does the following:
\ruleon
\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 text given in the header of the object definition is printed.
\ruleoff
\par\noindent For example, the ^{dye} might be given:
\beginstt
short_name
[; switch(self.colour)
{ 1: print "blue ";
2: print "purple ";
3: print "horrid sludge"; rtrue;
}
],
\endtt
with |"liquid"| as the short name in its header. According to whether
its |colour| property is 1, 2 or 3, the printed result is ``^{blue liquid}'',
``^{purple liquid}'' or ``^{horrid sludge}''.
\danger Alternatively, define the dye with |short_name "blue liquid"| and then
simply execute |dye.short_name = "purple liquid";| when the time comes.
\danger Rooms can also be given a |short_name| routine, which is
useful to code, say, a grid of four hundred similar locations called
``Area 1" up to ^{``Area 400"}. (They can be represented by just one
object in the program.)
\bigskip\noindent
For many objects the indefinite article and short name will most often be
seen in inventory lists, such as
\beginstt
>i
You are carrying:
a leaf of mint
a peculiar book
your satchel (which is open)
a green cube
\endtt^^{objects: inventory entries of}
Some objects, though, ought to have fuller entries in an inventory:
a wine bottle should say how much wine is left, for instance. The |invent|
property is designed for this.
The simplest way to use ^|invent| is as a string. For instance, declaring
a ^{peculiar book} with
\beginstt
invent "that harmless old book of Geoffrey's",
\endtt^^{Geoffrey's book}
will make this the inventory line for the book. In the light of events, it
could later be changed to
\beginstt
geoffreys_book.invent = "that lethal old book of Geoffrey's";
\endtt
\danger Note that this string becomes the whole inventory entry: if the
object were an open container, its contents wouldn't be listed, which might
be unfortunate. In such circumstances it's better to write an |invent|
routine, and that's also the way to append text like ``(half-empty)''.
\danger Each line of an inventory is produced in two stages.
{\bf First}, the basic line:
\ruleson
\item{1a.} The global variable |inventory_stage| is set to 1.
\item{1b.} The |invent| routine is called (if there is one).
If it returns true, stop here.
\item{1c.} The object's indefinite article and short-name are printed.
\rulesoff
\ninepoint\noindent
{\bf Second}, little informative messages like ``(which is open)"
are printed, and ^{inventories} are given for the contents of open
containers:
\ruleson
\item{2a.} The global variable |inventory_stage| is set to 2.
\item{2b.} The |invent| routine is called (if there is one).
If it returns true, stop here.
\item{2c.} A message such as ``(closed, empty and providing light)''
is printed, as appropriate.
\item{2d.} If it is an |open container|, its contents are inventoried.
\rulesoff^^|inventory stage|\ninepoint
After each line is printed, linking text such as a new-line or a comma
is printed, according to the current ``list style''.
\medskip\noindent
For example, here is the |invent| routine used by the ^{matchbook} in
^{`Toyshop'}:
\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
\ddangerexercise Suppose you want to change the whole inventory line for
an ^{ornate box} but you can't use an |invent| string, or return true from
stage 1, because you still want stage 2d to happen properly (so that its
contents will be listed). How can you achieve
this?^^{exercises: ornate box (inventory inside)}
\answer{^^{ornate box}^^{exercises: ornate box (inventory inside)}
Use the |invent| routine to signal to |short_name|
and |article| routines to change their usual habits:
\beginlines
| invent|
| [; if (inventory_stage==1) give self general;|
| else give self ~general;|
| ],|
| short_name|
| [; if (self has general) { print "box"; rtrue; } ],|
| article|
| [; if (self has general) { print "that hateful"; rtrue; }|
| else print "a"; ],|
\endlines}
\tenpoint\bigskip\noindent
The largest and most complicated messages Inform ever prints on its own
initiative are ^{room descriptions}, printed when the ^|Look| action is carried
out (for instance, when the statement |<Look>;| triggers a room description).
What happens is: the room's short name is printed (usually in bold-face)
on a line of its own, then its |description|, followed by a list of the objects
residing there which aren't |concealed| or |scenery|.
Chapter IV mentioned many different properties -- |initial|, |when_on|,
|when_off| and so on -- giving descriptions of what an object looks like
when in the same room as the player; some apply to doors, others to
switchable objects and so on. All of them can be routines to print text,
instead of being strings to print. The precise rules are given below.
But the whole system can be bypassed using the ^|describe| property. If an
object gives a |describe| routine then this takes priority over everything:
if it returns true, the library assumes that the object has already been
described, and prints nothing further. For example,
\beginstt
describe
[; "^The platinum pyramid catches the light beautifully.";
];
\endtt^^{platinum pyramid}
means that even when the pyramid has been |moved| (i.e. held by the player
at some stage) it will always have its own line of room description.
\danger Note the initial |^| (new-line) character. The library doesn't print
a skipped line itself before calling |describe| because it doesn't know
yet whether the routine will want to say anything. A |describe| routine
which prints nothing and returns true makes an object invisible, as if
it were |concealed|.
\bigskip\ninepoint
\ddanger The |Look| action does three things: it `notes arrival', prints
the room description then `scores arrival'. Only the printing rules are given
here (see \S 20 for the others), but they're given in full. In what follows,
the word `location' means the room object if there's light to see by,
and the special ``Darkness'' object otherwise. First the top line:
\ruleon
\item{1a.} A new-line is printed. The location's short name is printed
(in bold-face, if possible).
\item{1b.} If the player is on a |supporter|, then
`` (on \<something>)'' is printed; if inside anything else, then
`` (in \<something>)''.
\item{1c.} `` (as \<something>)'' is printed if this was requested
by the game's most recent call to ^|ChangePlayer| (for instance,
`` (as a werewolf)'').
\item{1d.} A new-line is printed.
\ruleoff\ninepoint%
Now the `^{long description}'. This step is skipped if the player has just
moved of his own will into a location already visited, unless the game is
in ^{``verbose"} mode.
\ruleon
\item{2.} If the location has a ^|describe| property, then run it. If not,
look at the location's |description| property: if it's a string, print it;
if it's a routine, run it.
\ruleoff\ninepoint%
All rooms must provide {\sl either} a |describe| property {\sl or} a
|description| of themselves. Now for items nearby:
\ruleon
\item{3a.} List any objects on the floor.
\item{3b.} If the player is in or on something, list the other
objects in that.
\ruleoff\ninepoint%
The library has now finished, but your game gets a chance to add a
postscript:
\ruleon
\item{4.} Call the entry point ^|LookRoutine|.
\ruleoff
\danger The |visited| attribute is only given to a room after its description
has been printed for the first time (it happens during `scoring arrival').
This is convenient for making the description different after the first time.
\danger
`Listing objects' (as in 3a and 3b) is a complicated business. Some objects
are given a line or paragraph to themselves, others are lumped together
in a list at the end. The following objects are not mentioned at all:
the player, what the player is in or on (if anything) and
anything which is ^|scenery| or ^|concealed|.^^{objects: listed in room
descriptions}\ The remaining objects are looked through (eldest first) as
follows:
\ruleon
\item{1.} If the object has a |describe| routine, run it. If it returns true,
stop here and don't mention the object at all.
\item{2.} Work out the ``description property'' for the object:
\itemitem{a.} For a |container|, this is |when_open| or |when_closed|;
\itemitem{b.} Otherwise, for a |switchable| object this is |when_on| or |when_off|;
\itemitem{c.} Otherwise, for a |door| this is |when_open| or |when_closed|;
\itemitem{d.} Otherwise, it's |initial|.
\item{3.} If {\ninebf either} the object doesn't have this property
{\ninebf or} the object has been held by the player before (i.e., has |moved|)
and the property isn't |when_off| or |when_closed| {\ninebf then} then
the object will be listed at the end.
\item{4.} Otherwise a new-line is printed and the property is printed
(if it's a string) or run (if it's a routine).
\ruleoff
\danger A |supporter| which is |scenery| won't be mentioned,
but anything on top of it which is not |concealed| will
be.^^{supporting scenery}\
\danger Objects which have just been pushed into a new room are not listed
in that room's description on the turn in question. This is not because of
any rule about room descriptions, but because the pushed object is moved
into the new room only after the room description is made. This means
that when a wheelbarrow is pushed for a long distance, the player does not
have to keep reading ``You can see a wheelbarrow here.'' every move, as
though that were a surprise.
\danger You can use a library routine called ^|Locale| to perform
`object listing'. See \S A7 for details: suffice to say here that
the process above is equivalent to executing
\beginstt
if (Locale(location, "You can see", "You can also see"))
print " here.^";
\endtt
|Locale| is useful for describing areas of a room which are sub-divided
off, such as the stage of a theatre.
\tenpoint
\ddangerexercise The library implements ``superbrief'' and ``verbose''
modes for room description (one always omits long room descriptions,
the other never does). How can ^{verbose mode} automatically print
room descriptions every turn? (Some of the later Infocom games did
this.)^^{very verbose mode}^^{exercises: very verbose mode}
\answer{^^{exercises: very verbose mode}
This answer is cheating, as it needs to know about the library's
|lookmode| variable (set to 1 for normal, 2 for verbose or 3 for
superbrief). Simply include:
\beginlines
|[ TimePasses;|
| if (action~=##Look && lookmode==2) <Look>;|
|];|
\endlines^^{very verbose mode}}
\refs ^{`Balances'} often uses |short_name|, especially for
the white cubes (whose names change) and lottery tickets
(whose numbers are chosen by the player). ^{`Adventureland'}
uses |short_name| in simpler ways: see the bear and the
bottle, for instance.
\nextref The scroll class of ^{`Balances'} uses |invent|.
\nextref See the |ScottRoom| class of ^{`Adventureland'} for a radically
different way to describe rooms (in ^{pidgin English}, like
^{telegraphese}).^^{Scott Adams}
\section{23}{Listing and grouping objects}
\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} ({\oldstyle1836}--{\oldstyle1911})}{The Mikado}
\noindent
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 the duller items in 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 available to the public. The routine to call is:
\beginstt
WriteListFrom(object, style);
\endtt^^|WriteListFrom|^^{objects: printing lists of}
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 some of the following constants:^^{style of list}^^{list style}
\smallskip
\settabs 8\columns
\+& |NEWLINE_BIT| && New-line after each entry\cr
\+& |INDENT_BIT| && Indent each entry according to 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
\+& |ISARE_BIT| && Prints `` is " or `` are " before list\cr
\+& |CONCEAL_BIT| && Misses out |concealed| or |scenery| objects\cr
\smallskip
\noindent The best way to use this is to experiment. For example, a `tall'
inventory is produced by:
\beginstt
WriteListFrom( child(player),
FULLINV_BIT + INDENT_BIT + NEWLINE_BIT + RECURSE_BIT );
\endtt^^{narrow inventory}
and a `wide' one by:
\beginstt
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.
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.
\ddanger |WORKFLAG_BIT| and |CONCEAL_BIT| specify conflicting rules. If
they're both given, then what happens is: at the top level, but not below,
everything with |workflag| is included; on lower levels, but not at the
top, everything without |concealed| or |scenery| is included.
\exercise Write a |DoubleInvSub| action routine to produce an inventory
like so:^^{double inventory}^^{exercises: 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{^^{exercises: double inventory}
\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}}
\danger Finally, there is a neat way to customise the grouping together
of non-identical items in lists, considerably enhancing the
presentation of the game. If a collection of game objects -- say,
all the edible items in the game -- have a common non-zero value of the
property |list_together|, in the range 1 to 1000, they will always
appear adjacently in inventories, room descriptions and the
like.^^{objects: grouping of in lists}
\ninepoint
Alternatively, instead of being a small number the common value can be
a string such as |"foodstuffs"|. If so then lists will cite, e.g.,
\begindisplay
three foodstuffs (a scarlet fish, some lemmas and an onion)\cr
\enddisplay
in running text, or
\begindisplay
three foodstuffs:\cr
\qquad a scarlet fish\cr
\qquad some lemmas\cr
\qquad an onion\cr
\enddisplay^^{foodstuffs}^^{grouping of non-identical items in lists}
in indented lists. This only happens when two or more are gathered
together.
Finally, the common value can be a routine, such as:
\beginstt
list_together
[; if (inventory_stage==1) print "heaps of food, notably ";
else print ", which would do you no good";
],
\endtt^^|inventory stage|^^|c style|^^{heaps of food}
Typically this might be part of a class definition from which all the
objects in question inherit. A |list_together| routine
will be called twice: once, with |inventory_stage| set to 1, as
a preamble to the list of items, and once (with 2) to print any
postscript required. It is allowed to change |c_style| (the current
list style) without needing to restore the old value and may, by
returning 1 from stage 1, signal the list-maker not to print a list at
all. The simple example above results in
\begindisplay
heaps of food, notably a scarlet fish, some lemmas\cr
and an onion, which would do you no good\cr
\enddisplay
Such a routine may want to make use of the variables |parser_one| and
|parser_two|, which respectively hold the first object in the group
and the depth of recursion in the list (this might be needed to keep
indentation going properly). Applying |x=NextEntry(x,parser_two);|
moves |x| on from |parser_one| to the next item in the group.
Another helpful variable is |listing_together|, set up to the first
object of a group being listed or to 0 whenever no group is being listed.
The following list of 24 items shows some possible effects (see the
example game ^{`List Property'}):
\begindisplay
You can see a plastic fork, knife and spoon, three hats (a fez, a Panama\cr
and a sombrero), the letters X, Y, Z, P, Q and R from a Scrabble set, a\cr
defrosting Black Forest gateau, Punch magazine, a recent issue of the\cr
Spectator, a die and eight coins (four silver, one bronze and three gold)\cr
here.\cr
\enddisplay
\dangerexercise Implement the ^{Scrabble pieces}.^^{exercises: Scrabble pieces}
\answer{^^{Scrabble pieces}^^{exercises: Scrabble pieces}
\beginlines
|Class Letter|
| with list_together|
| [; if (inventory_stage==1)|
| { print "the letters ";|
| if (~~(c_style & ENGLISH_BIT)) c_style = c_style + ENGLISH_BIT;|
| if (~~(c_style & NOARTICLE_BIT)) c_style = c_style + NOARTICLE_BIT;|
| if (c_style & NEWLINE_BIT) c_style = c_style - NEWLINE_BIT;|
| if (c_style & INDENT_BIT) c_style = c_style - INDENT_BIT;|
| }|
| else print " from a Scrabble set";|
| ],|
| short_name|
| [; if (listing_together ofclass Letter) rfalse;|
| print "letter ", (object) self, " from a Scrabble set"; rtrue;|
| ],|
| article "the";|
\endlines
and then as many letters as desired, along the lines of
\beginlines
|Letter -> "X" with name "x";|
\endlines}
\ddangerexercise Implement the
^{three denominations of coin}.^^{coins (listed together)}
^^{exercises: three denominations of coin}
\answer{^^{coins (listed together)}^^{three denominations of coin}
^^{exercises: three denominations of coin}
\beginlines
|Class Coin|
| with name "coin" "coins//p",|
| description "A round unstamped disc, presumably local currency.",|
| list_together "coins",|
| plural|
| [; print (string) (self.&name)-->0;|
| if (~~(listing_together ofclass Coin)) print " coins";|
| ],|
| short_name|
| [; if (listing_together ofclass Coin)|
| { print (string) (self.&name)-->0; rtrue; }|
| ],|
| article|
| [; if (listing_together ofclass Coin) print "one"; else print "a";|
| ];|
|Class Gold_coin class Coin with name "gold";|
|Class Silver_coin class Coin with name "silver";|
|Class Bronze_coin class Coin with name "bronze";|
|SilverCoin -> "silver coin";|
|... and so on|
\endlines}
\ddangerexercise Implement the ^{I Ching} in the form of six coins,
three gold (goat, deer and chicken), three silver (robin, snake
and bison) which can be thrown to reveal gold and silver
^{trigrams}.^^{coins (in I Ching trigrams)}^^{exercises: I Ching coins}
\answer{^^{I Ching}^^{trigrams}^^{exercises: I Ching coins}
^^{coins (in I Ching trigrams)}
Firstly, a printing rule to print the state of coins. Coin-objects
will have a property called |way_up| which is always either 1 or 2:
\beginlines
|[ Face x; if (x.way_up==1) print "Heads"; else print "Tails"; ];|
\endlines
There are two kinds of coin but we'll implement them with three
classes: |Coin| and two sub-categories, |GoldCoin| and |SilverCoin|.
Since the coins only join up into trigrams when present in groups
of three, we need a routine to detect this:
\beginlines
|[ CoinsTogether cla i x y;|
| objectloop (i ofclass cla)|
| { x=parent(i);|
| if (y==0) y=x; else { if (x~=y) return 0; }|
| }|
| return y;|
|];|
\endlines
Thus |CoinsTogether(cla)| decides whether all objects of class |cla|
are in the same place. (|cla| will always be either |GoldCoin| or
|SilverCoin|.) We must now write the class definitions:
\beginlines
|Class Coin|
| with name "coin" "coins//p",|
| way_up 1, article "the",|
| after|
| [; Drop, PutOn:|
| self.way_up = random(2); print (Face) self;|
| if (CoinsTogether(self.which_class))|
| { print ". The ";|
| if (self.which_class == GoldCoin)|
| print "gold"; else print "silver";|
| " trigram is now ", (Trigram) self.which_class;|
| }|
| ".";|
| ];|
|[ CoinLT k i c;|
| if (inventory_stage==1)|
| { if (self.which_class == GoldCoin)|
| print "the gold"; else print "the silver";|
| print " coins ";|
| k=CoinsTogether(self.which_class);|
| if (k==location || k has supporter)|
| { objectloop (i ofclass self.which_class)|
| { print (name) i;|
| switch(++c)|
| { 1: print ", "; 2: print " and ";|
| 3: print " (showing the trigram ",|
| (Trigram) self.which_class, ")";|
| }|
| }|
| rtrue;|
| }|
| if (~~(c_style & ENGLISH_BIT)) c_style = c_style + ENGLISH_BIT;|
| if (~~(c_style & NOARTICLE_BIT)) c_style = c_style + NOARTICLE_BIT;|
| if (c_style & NEWLINE_BIT) c_style = c_style - NEWLINE_BIT;|
| if (c_style & INDENT_BIT) c_style = c_style - INDENT_BIT;|
| }|
| rfalse;|
|];|
|Class GoldCoin class Coin|
| with name "gold", which_class GoldCoin,|
| list_together [; return CoinLT(); ];|
|Class SilverCoin class Coin|
| with name "silver", which_class SilverCoin,|
| list_together [; return CoinLT(); ];|
\endlines
(There are two unusual points here. Firstly, the |CoinsLT| routine
is not simply given as the common |list_together| value in the |coin|
class since, if it were, all six coins would be grouped together:
we want two groups of three, so the gold and silver coins have to have
different |list_together| values. Secondly, if a trigram is together
and on the floor, it is not good enough to simply append text like
``showing Tails, Heads, Heads (change)'' at |inventory_stage| 2 since the
coins may be listed in a funny order: for example, in the order snake,
robin, bison. In that event, the order the coins are listed in
doesn't correspond to the order their values are listed in, which is
misleading. So instead |CoinsLT| takes over entirely at
|inventory_stage| 1 and prints out the list of three itself, returning
true to stop the list from being printed out by the library as well.)
To resume: whenever coins are listed together, they are grouped
into gold and silver. Whenever trigrams are visible they are to be
described by either |Trigram(GoldClass)| or |Trigram(SilverClass)|:
\beginlines
|Array gold_trigrams --> "fortune" "change" "river flowing" "chance"|
| "immutability" "six stones in a circle"|
| "grace" "divine assistance";|
|Array silver_trigrams --> "happiness" "sadness" "ambition" "grief"|
| "glory" "charm" "sweetness of nature"|
| "the countenance of the Hooded Man";|
|[ Trigram cla i k state;|
| objectloop (i ofclass cla)|
| { print (Face) i; if (k++<2) print ","; print " ";|
| state=state*2 + (i.way_up-1);|
| }|
| if (cla == GoldCoin) i=gold_trigrams; else i=silver_trigrams;|
| print "(", (string) i-->state, ")";|
|];|
\endlines
(These interpretations of the coins are quite bogus.) Finally,
we have to make the six actual coins:
\beginlines
|GoldCoin -> "goat" with name "goat";|
|GoldCoin -> "deer" with name "deer";|
|GoldCoin -> "chicken" with name "chicken";|
|SilverCoin -> "robin" with name "robin";|
|SilverCoin -> "snake" with name "snake";|
|SilverCoin -> "bison" with name "bison";|
\endlines}
\tenpoint
\refs A good example of |WriteListFrom| in action is the definition
of |CarryingClass| from the example game ^{`The Thief'}, by
^{Gareth Rees}. This alters the examine description of a character
by appending a list of what that person is carrying and wearing.
\nextref Denominations of coin are also in evidence in ^{`Balances'}.
\section{24}{How nouns are parsed}
\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} ({\oldstyle1888}--{\oldstyle1965})}{The Naming of Cats}
\quote
Bulldust, coolamon, dashiki, fizgig, grungy, jirble, pachinko,
poodle-faker, sharny, taghairm^^{catachrestic words}
\quoteby{Catachrestic words from ^{Chambers English Dictionary}}
\noindent\tenpoint
Suppose we have a tomato defined with
\beginstt
name "fried" "green" "tomato",
\endtt^^{fried green tomato}^^{tomato}
but which is going to redden later and need to be referred to as ``red
tomato''. It's perfectly straightforward to alter the ^|name| property of
an object, which is a ^{word array} of dictionary words. For example,
\beginstt
[ Names obj i;
for (i=0:2*i<obj.#name:i++) print (address) (obj.&name)-->i, "^";
];
\endtt^^{treating {\tt name} as a word array}^^{array of {\tt name}s}
prints out the list of dictionary words held in |name| for a given
object. It's perfectly possible to write to this, so we could just set
\beginstt
(tomato.&name)-->1 = 'red';
\endtt^^{objects: names of}
but this is not a flexible or elegant solution, and it's time to
begin delving into the parser.
\danger Note that we can't change the size of the |name| array.
To simulate this, we could define the object with
|name| set to, say, 30 copies of an `untypeable word' (see below)
such as |'blank.'|.
\bigskip
\noindent
The Inform ^{parser} is designed to be as ``open-access'' as possible,
because a parser cannot ever be general enough for every game without
being highly modifiable. The first thing it does
is to read in text from the keyboard and break it up into a
^{stream of words}^^{word stream}:
so the text ``wizened man, eat the grey bread'' becomes
\begindisplay
|wizened| / |man| / |,| / |eat| / |the| / |grey| / |bread|\cr
\enddisplay^^{wizened man}^^|NextWord|^^{word breaking}
^^{parser: breaking up text into word stream}
and these words are numbered from 1. At all times the parser keeps
a ``word number'' marker to keep its place along this line, and this
is held in the variable |wn|. The routine |NextWord()| returns
the word at the current position of the marker, and moves it forward,
i.e. adds 1 to |wn|. For instance, the parser may find itself at
word 6 and trying to match ``grey bread'' as the name of an object.
Calling |NextWord()| gives the value |'grey'| and calling it again
gives |'bread'|.
Note that if the player had mistyped ``grye bread'', ``grye'' being a word
which isn't mentioned anywhere in the program or created by the library,
|NextWord()| returns 0 for `misunderstood word'. Writing something like
|if (w=='grye') ...| somewhere in the program makes Inform put ``grye''
into the dictionary automatically.
\danger Remember that the game's dictionary only has 9-character
^{resolution}. (And only 6 if Inform has been
told to compile an early-model story file: see \S 31.)
Thus the values of |'polyunsaturate'| and
|'polyunsaturated'| are equal.^^{case sensitivity of dictionary}\
Also, upper case and lower case letters are considered the same.
Words are permitted to contain numerals or symbols (but not at
present to contain accented
characters).^^{dictionary: characters which can be part of words in}
\ddanger A dictionary word can even contain spaces, full stops or commas.
If so it is `untypeable'. For instance, |'in,out'| is an untypeable
word because if the player does type it then the parser cuts it into
three, never checking the dictionary for the entire word. Thus the
constant |'in,out'| can never be anything that |NextWord| returns.
This can actually be useful (as it was in \S
16).^^{untypeable words}^^{punctuation in dictionary words}
^^{dictionary: untypeable words in}
\danger It can also be useful to check for numbers. The library
routine |TryNumber(wordnum)|^^|TryNumber|\ 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 else the number. Values exceeding 10000 are rounded
down to 10000.
\ddanger Sometimes there is no alternative but to actually look at
the player's text one character at a time (for instance, to check
a 20-digit ^{phone number}). The routine |WordAddress(wordnum)|
returns a byte array of the characters in the word, and
|WordLength(wordnum)| tells you how many characters there are in it.
Thus in the above example,
\beginstt
thetext = WordAddress(4);
print WordLength(4), " ", (char) thetext->0, (char) thetext->2;
\endtt^^|WordAddress|^^|WordLength|^^{command buffer}
^^{text buffer (of buffer)}^^{parsing: text buffer holding commands}
^^{keyboard buffer}^^{text of a command}
prints the text ``3 et''.
\noindent
An object can affect how its name is parsed by giving a |parse_name|
routine. This is expected to try to match as many words as possible
starting from the current position of |wn|, reading them in one at
a time using the |NextWord()| routine. Thus it must not stop just because
the first word makes sense, but must keep reading and find out how many
words in a row make sense.^^|parse name|\
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 tell the parser it doesn't want to decide after all.\cr
\enddisplay
The word marker |wn| can be left anywhere afterwards. For example:
\beginstt
Object -> thing "weird thing"
with parse_name
[ i; while (NextWord()=='weird' or 'thing') i++;
return i;
];
\endtt^^{weird thing}
This definition duplicates (very nearly) the effect of having defined:
\beginstt
Object -> thing "weird thing"
with name "weird" "thing";
\endtt
Which isn't very useful. But the tomato can now be coded up with
\beginstt
parse_name
[ i j; if (self has general) j='red'; else j='green';
while (NextWord()=='tomato' or 'fried' or j) i++;
return i;
],
\endtt
so that ``green" only applies until its |general| attribute has
been set, whereupon ``red'' does.
\exercise Rewrite this to insist that the adjectives
must come before the noun, which must be
present.^^{exercises: tomato in red or green}
\answer{^^{exercises: tomato in red or green}
\beginlines
|parse_name|
|[ i j w; if (self has general) j='red'; else j='green';|
| w=NextWord();|
| while (w==j or 'fried')|
| { w=NextWord(); i++;|
| }|
| if (w=='tomato') return i+1;|
| return 0;|
|],|
\endlines}
\exercise Create a musician called ^{Princess} who, when kissed,
is transformed into ``|/?%?/| (the
^{artiste formerly known as Princess})''.^^{exercises: the artiste formerly known as Princess}
\answer{^^{Princess}^^{artiste formerly known as Princess}
^^{exercises: the artiste formerly known as Princess}
\beginlines
|Object -> "/?%?/ (the artiste formally known as Princess)"|
| with name "princess" "artiste" "formally" "known" "as",|
| short_name|
| [; if (self hasnt general) { print "Princess"; rtrue; }|
| ],|
| react_before|
| [; Listen: print_ret (name) self, " sings a soft siren song.";|
| ],|
| initial|
| [; print_ret (name) self, " is singing softly.";|
| ],|
| parse_name|
| [ x n; if (self hasnt general)|
| { if (NextWord()=='princess') return 1;|
| return 0;|
| }|
| x=WordAddress(wn);|
| if ( x->0 == '/' && x->1 == '?' && x->2 == '%'|
| && x->3 == '?' && x->4 == '/')|
| { while (wn<=parse->1 && WordAddress(wn++)<x+5) n++;|
| return n;|
| }|
| return -1;|
| ],|
| life|
| [; Kiss: give self general; self.life = NULL;|
| "In a fairy-tale transformation, the Princess |
| steps back and astonishes the world by announcing |
| that she will henceforth be known as ~/?%?/~.";|
| ],|
| has animate proper female;|
\endlines}
\exercise (Cf. ^{`Caf\'e Inform'}.) Construct a drinks machine capable
of serving cola, coffee or tea, using only one object for the buttons
and one for the possible drinks.^^{exercises: drinks machine}
\answer{^^{exercises: drinks machine}
Something to note here is that the button can't be called just ``coffee''
when the player's holding a cup of coffee: this means the game responds sensibly
to the sequence ``press coffee'' and ``drink coffee''. Also note the way |itobj|
is set to the delivered drink, so that ``drink it'' works nicely.
\beginlines
|Object -> drinksmat "drinks machine",|
| with name "drinks" "machine",|
| initial|
| "A drinks machine here has buttons for Cola, Coffee and Tea.",|
| has static;|
|Object -> thebutton "drinks machine button"|
| has scenery|
| with parse_name|
| [ i flag type;|
| for (: flag == 0: i++)|
| { flag = 1;|
| switch(NextWord())|
| { 'button', 'for': flag = 0;|
| 'coffee': if (type == 0) { flag = 0; type = 1; }|
| 'tea': if (type == 0) { flag = 0; type = 2; }|
| 'cola': if (type == 0) { flag = 0; type = 3; }|
| }|
| }|
| if (type==drink.number && i==2 && type~=0 && drink in player)|
| return 0;|
| self.number=type; return i-1;|
| ],|
| number 0,|
| before|
| [; Push, SwitchOn:|
| if (self.number == 0)|
| "You'll have to say which button to press.";|
| if (parent(drink) ~= 0) "The machine's broken down.";|
| drink.number = self.number; move drink to player; itobj = drink;|
| print_ret "Whirr! The machine puts ", (a) drink, " into your \|
| glad hands.";|
| Attack: "The machine shudders and squirts cola at you.";|
| Drink: "You can't drink until you've worked the machine.";|
| ];|
|Object drink "drink"|
| with parse_name|
| [ i flag type;|
| for (: flag == 0: i++)|
| { flag = 1;|
| switch(NextWord())|
| { 'drink', 'cup', 'of': flag = 0;|
| 'coffee': if (type == 0) { flag = 0; type = 1; }|
| 'tea': if (type == 0) { flag = 0; type = 2; }|
| 'cola': if (type == 0) { flag = 0; type = 3; }|
| }|
| }|
| if (type ~= 0 && type ~= self.number) return 0;|
| return i-1;|
| ],|
| short_name|
| [; print "cup of ";|
| switch (self.number)|
| { 1: print "coffee"; 2: print "tea"; 3: print "cola"; }|
| rtrue;|
| ],|
| number 0,|
| before|
| [; Drink: remove self;|
| "Ugh, that was awful. You crumple the cup and responsibly \|
| dispose of it.";|
| ];|
\endlines}
\danger |parse_name| is also used to spot plurals: see \S 25.
\noindent
Suppose that an object doesn't have a |parse_name| routine, or that
it has but it returned $-1$. The parser then looks at the |name|
words. It recognises any arrangement of some or all of these words
as a match (the more words, the better). Thus ``fried green tomato'' is
understood, as are ``fried tomato'' and ``green tomato''. On the other
hand, so are ``fried green'' and ``green green tomato green fried green''.
This method is quick and good at understanding a wide variety of
sensible inputs, though bad at throwing out foolish ones.
However, you can affect this by using the ^|ParseNoun| entry point.
This is called with one argument, the object in question, and should
work exactly as if it were a |parse_name| routine: i.e., returning
$-1$, 0 or the number of words matched as above. Remember that it
is called very often and should not be horribly slow. For example,
the following duplicates what the parser usually does:
\beginstt
[ ParseNoun obj n;
while (IsAWordIn(NextWord(),obj,name) == 1) n++; return n;
];
[ IsAWordIn w obj prop k l m;
k=obj.∝ l=(obj.#prop)/2;
for (m=0:m<l:m++)
if (w==k-->m) rtrue;
rfalse;
];
\endtt^^{{\tt IsAWordIn} (example)}
In this example |IsAWordIn| just checks to see if |w| is one of the
entries in the word array |obj.&prop|.
\dangerexercise Many adventure-game parsers split object names into
`^{adjectives}' and `nouns', so that only the pattern
\<0 or more adjectives> \<1 or more nouns>
is recognised. Implement this.^^{exercises: parsing adjectives}
\answer{^^{exercises: parsing adjectives}
Create a new property |adjective|, and move names which are
^{adjectives} to it: for instance,
\beginstt
name "tomato" "vegetable", adjective 'fried' 'green' 'cooked',
\endtt
(Recall that dictionary words can only be written in |"| quotes for
the |name| property.) Then (using the same |IsAWordIn| routine),
\beginstt
[ ParseNoun obj n m;
while (IsAWordIn(NextWord(),obj,adjective) == 1) n++; wn--;
while (IsAWordIn(NextWord(),obj,noun) == 1) m++;
if (m==0) return 0; return n+m;
];
\endtt}
\dangerexercise During debugging it sometimes helps to
be able to refer to objects by their internal numbers, so that
``put ^{object 31} on object 5'' would work. Implement
this.^^{objects: referred to by number}
^^{debugging: referring to objects by number}
^^{exercises: referring to objects by number}
\answer{^^{debugging: referring to objects by number}
^^{exercises: referring to objects by number}
\beginstt
[ ParseNoun obj;
if (NextWord() == 'object' && TryNumber(wn) == obj) return 2;
wn--; return -1;
];
\endtt^^{objects: referred to by number}}
\dangerexercise How could the word ``|#|'' be made a ^{wild-card},
meaning ``match any single object''?^^{``{\tt \#}''}
^^{exercises: wild-card for a single object}
\answer{^^{``{\tt \#}''}^^{wild-card}
^^{exercises: wild-card for a single object}
\beginstt
[ ParseNoun;
if (WordLength(wn)==1 && WordAddress(wn)->0 == '#') return 1;
return -1;
];
\endtt}
\ddangerexercise And how could ``|*|'' be a wild-card for
``match any collection of objects''?^^{``{\tt *}''}
^^{exercises: wild-card for multiple objects}
\answer{^^{``{\tt *}''}^^{wild-card}
^^{exercises: wild-card for multiple objects}
\beginstt
[ ParseNoun;
if (WordLength(wn)==1 && WordAddress(wn)->0 == '#') return 1;
if (WordLength(wn)==1 && WordAddress(wn)->0 == '*')
{ parser_action = ##PluralFound; return 1; }
return -1;
];
\endtt}
\ddangerexercise There is no problem with calling a container
``^{hole in wall}'', because the parser will understand
``put apple in hole in wall'' as ``put (apple) in (hole in wall)''.
But create a ^{fly in amber}, so that ``put fly in amber in
hole in wall'' works properly and isn't misinterpreted as
``put (fly) in (amber in hole in wall)''.
(Warning: you may need to know about the |BeforeParsing| entry
point (see \S 26) and the format of the |parse| buffer (see
\S 27).)^^{exercises: ``fly in amber''}
\answer{^^{fly in amber}The trick is to convert ``fly in amber''
into ``fly fly amber'' (a harmless name) before the parser gets
under way.^^{exercises: ``fly in amber''}
\beginlines
|[ BeforeParsing i j;|
| for (i=parse->1,j=2:j<i:j++)|
| { wn=j-1;|
| if (NextWord()=='fly' && NextWord()=='in' && NextWord()=='amber')|
| parse-->(j*2-1) = 'fly';|
| }|
|];|
\endlines}
\refs Straightforward |parse_name| examples are the chess-pieces object
and the kittens class of ^{`Alice Through The Looking-Glass'}. Lengthier
ones are found in ^{`Balances'}, especially in the white cubes class.
\section{25}{Plural names for duplicated objects}
\poem
Abiit ad plures.
\poemby{Petronius (?--c. {\oldstyle66})}{Cena Trimalchionis}
\noindent
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}^^{objects: duplicate and plural}\
Two problems must 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 GoldCoin
with name "gold" "coin",
short_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;
GoldCoin ->;
GoldCoin ->;
GoldCoin ->;
SilverCoin ->;
SilverCoin ->;
BronzeCoin ->;
\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:
\smallskip
\item{(a)} have a ^|plural| set,
\item{(b)} are ^{`indistinguishable'} from each other.
\smallskip\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 but 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 a |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 would be doing a lot of work comparing all their names, but you
can make the decision much faster.
\bigskip
\noindent
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:
\beginstt
> drop all of the crowns except green
> drop the three other crowns
\endtt
Putting the word |"crowns"| in their |name| lists is not quite
right, because the parser will still think that ``crowns'' might
refer to a specific item. Instead, put in the word |"crowns//p"|.
The ^|//p| marks out the dictionary word ``crowns'' as one that
can refer to more than one game object at once. (So that
you shouldn't set this for the word ``grapes'' if a bunch of
grapes was a single game object; you should give that object
the |pluralname| attribute instead.) For example the |GoldCoin|
class would read:
\beginstt
Class GoldCoin
with name "gold" "coin" "coins//p",
short_name "gold coin",
plural "gold coins";
\endtt^^{plural markings on words}
and now when the player types ``take coins'', the parser
interprets this as ``take all the coins within reach''.
\ddanger The only snag is that now the word |"coins"| is marked as
|//p| everywhere in the game, in all circumstances. Here is
a more complicated way to achieve the same result, but
strictly in context of these objects alone. We need 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
with parse_name
[ i j;
for (::)
{ j=NextWord();
if (j=='crown' or self.name) i++;
else
{ if (j=='crowns')
{ parser_action=##PluralFound; i++; }
else return i;
}
}
];
\endtt
This code assumes that the crown objects have just one |name| each,
their colours.
\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}^^{exercises: cherubim plural}
\answer{^^{exercises: cherubim plural}
\beginlines
|Global c_warned = false;|
|Class Cherub|
| with parse_name|
| [ i j flag;|
| for (flag=true:flag:flag=false)|
| { j=NextWord();|
| if (j=='cherub' or j==self.name) flag=true;|
| if (j=='cherubs' && (~~c_warned))|
| { c_warned=true;|
| parser_action=##PluralFound; flag=true;|
| print "(I'll let this go once, but the plural of cherub is cherubim.)^";|
| }|
| if (j=='cherubim')|
| { parser_action=##PluralFound; flag=true; }|
| i++;|
| }|
| return i-1;|
| ];|
\endlines
Then again, Shakespeare even wrote ``cherubins'' in `Twelfth Night',
so who are we to censure?^^{cherubim}^^{William Shakespeare}}
\refs See the coinage of ^{`Balances'}.
\section{26}{How verbs are parsed}
\poem
Grammar, which can govern even kings.
\poemby{^{Moli\`ere} ({\oldstyle1622}--{\oldstyle1673})}{Les Femmes savantes}
\noindent
The parser's fundamental method is simple. Given a stream of text like
\begindisplay
|saint| / |peter| / |,| / |take| / |the| / |keys| / |from| / |paul|\cr
\enddisplay^^{St Peter}
it first calls the entry point ^|BeforeParsing| (in case you want to
meddle with the text stream before it gets underway). It then
works out who is being addressed, if anyone, by looking for
a comma, and trying out the text up to there as a noun (anyone |animate|
or anything |talkable| will do): in this case St Peter. This person
is called the ``actor'', since he is going to perform the action, and
is usually the player himself (thus, typing ``myself, go north'' is
equivalent to typing ``go north'').
The next word, in this case |'take'|, is the ``verb word''. An
Inform verb usually has several ^{English verb words} attached, which
are called ^{synonyms} of each other: for instance, the library
is set up with^^{verbs (Inform and English)}
$$ \hbox{``take''} = \hbox{``carry''} = \hbox{``hold''} $$
all referring to the same Inform verb.
\danger The parser sets up global variables ^|actor| and |verb_word|
while working. (In the example above, their values would
be the St Peter object and |'take'|, respectively.)^^|verb word|\
\ddanger It isn't quite that simple: names of direction objects are
treated as implicit ``go'' commands, so that ``n'' is acceptable as
an alternative to ``go north''. There are also ``again'', ``oops'' and
``undo'' to grapple with.
\danger Also, a major feature (the |grammar| property for the person
being addressed) has been missed out of this description: see the latter
half of \S 16 for details.
\noindent
Teaching the parser a new synonym is easy. Like all of the directives
in this section, the following must appear {\sl after} the inclusion
of the library file |Grammar|:
\beginstt
Verb "steal" "acquire" "grab" = "take";
\endtt
This creates another three synonyms for ``take''.
\danger One can also prise synonyms apart, as will appear later.
\noindent
The parser is now up to word 5; i.e., it has ``the keys from paul'' left
to understand. Apart from a list of English verb-words which refer to
it, an Inform verb also has a ``^{grammar}''. This is a list of
1 or more ``^{lines}'', each a pattern which the rest of the text might
match. The parser tries the first, then the second and so on, and
accepts the earliest one that matches, without ever considering later
ones.
A line is itself a row of ``^{tokens}''. Typical tokens might mean
`the name of a nearby object', `the word |from|' or `somebody's name'.
To match a line, the parser must match against each token in sequence.
For instance, the line of 3 tokens
\begindisplay
\<a noun> \<the word |from|> \<a noun>\cr
\enddisplay^^{actions: how the parser chooses}^^{grammar: lines of}
matches the text. Each line has an action attached, which in this
case is |Remove|: so the parser has ground up the original
text into just four numbers, ending up with
\beginstt
actor = st_peter
action = Remove noun = gold_keys second = st_paul
\endtt
What happens then is that the St Peter's |orders| routine (if any)
is sent the action, and may if it wishes cooperate. If the actor
had been the player, then the action would have been processed in
the usual way.
\danger The action for the line which is currently being worked through
is stored in the variable |action_to_be|; or, at earlier stages when the
verb hasn't been deciphered yet, it holds the value |NULL|.^^|action to be|
\bigskip\noindent
The ^|Verb| directive creates Inform verbs, giving them some English verb
words and a grammar. The library's |Grammar| file consists almost
exclusively of |Verb| directives: here is an example simplified from one
of them.^^{``take'' verb}^^{directives: Verb}
\beginlines
|Verb "take" "get" "carry" "hold"|
| * "out" -> Exit|
| * multi -> Take|
| * multiinside "from" noun -> Remove|
| * "in" noun -> Enter|
| * multiinside "off" noun -> Remove|
| * "off" held -> Disrobe|
| * "inventory" -> Inv;|
\endlines^^{grammar: definition of verbs}
(You can look at the grammar being used in a game with the
debugging verb ^{``showverb''}: see \S 30 for details.)
Each line of grammar begins with a |*|, gives a list of tokens as far
as |->| and then the action which the line produces. The first line
can only be matched by something like ``get out'', the second might
be matched by
\begindisplay
take the banana\cr
get all the fruit except the apple\cr
\enddisplay
and so on. A full list of tokens will be given later: briefly,
\cstok{"out"} means the literal word ``out'', \cstok{multi} means
one or more objects nearby, \cstok{noun} means just one and
\cstok{multiinside} means one or more objects inside the second
noun. In this book, grammar tokens are written in the style
\cstok{noun} to prevent confusion (as there is also a variable
called |noun|).
\ddanger Since this book was first written, the library has been
improved so that ``take'' and ``get'' each have their own
independent grammars. But for the sake of example,
suppose they share the grammar written out above.
Sometimes this has odd results: ``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 might avoid this by using |Extend only|
to separate them into different grammars, or you could fix the |Enter|
action to see if the variable |verb_word=='take'| or |'get'|.
\danger Some verbs are ^|meta| - they are not really part of the game:
for example, ``save'', ``score'' and ``quit''. These are declared using
|Verb meta|, as in
\beginstt
Verb meta "score"
* -> Score;
\endtt^^{``score'' verb}\ninepoint
and any debugging verbs you create would probably work better this way,
since meta-verbs are protected from interference by the game and take
up no game time.\tenpoint
\noindent
After the ^|->| in each line is the name of an action. Giving a name
in this way is what creates an action, and if you give the name of one
which doesn't already exist then you must also write a routine
to execute the action, even if it's one which doesn't do very much.
The name of the routine is always the name of the action with |Sub|
appended. For instance:
\beginstt
[ 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.^^{``xyzzy'' verb}\
|Xyzzy| is now an action just as good as all the standard ones:
|##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|.
\danger
Finally, the line can end with the word ^|reverse|.
This is only useful if there are objects and numbers
in the line which occur in the wrong order. An example from the
library's grammar:
\beginstt
Verb "show" "present" "display"
* creature held -> Show reverse
* held "to" creature -> Show;
\endtt
The point is that the |Show| action expects the first
parameter to be an item, and the second to be a person.
When the text ``show him the shield'' is typed in, the
parser must reverse the two parameters ``him'' and
``the shield'' before causing a |Show| action. On the other
hand, in ``show the shield to him'' the parameters are in
the right order already.
\bigskip\noindent
The library defines grammars for the 100 or so English verbs most
often used by adventure games. However, in practice you very often
need to alter these, usually to add extra lines of grammar but
sometimes to remove existing ones. For example, consider an
array of ^{676 labelled buttons}, any of which could be pushed:
it's hardly convenient to define 676 button objects. It would be
more sensible to create a grammar line which understands things like
\begindisplay
``button j16",\quad ``d11",\quad ``a5 button"
\enddisplay
(it's easy enough to write code for a token to do this), and then
to add it to the grammar for the ``press'' verb.
The ^|Extend| directive is provided for exactly this purpose:
\beginstt
Extend "push" * Button -> PushButton;
\endtt^^{grammar: extension of}^^{directives: Extend}
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 Another method would be to create a single button object
with a |parse_name| routine which carefully remembers what it was last
called, so that the object always knows which button it represents.
See ^{`Balances'} for an example.
\noindent
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
\beginstt
* 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:
\beginstt
* edible -> Eat
\endtt
(\cstok{edible} being a token matching anything which has the
attribute |edible|) 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
\beginstt
Extend "take" first
* edible -> Eat;
\endtt
You might even want to over-ride the old grammar completely, not
just add a line or two. For this, use^^{replacing grammar}
\beginstt
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\medskip\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
\medskip}\par\noindent^^{grammar: replacement of}
with |last| being the default (which doesn't need to be said explicitly).
\danger In library grammar, some verbs have many synonyms: for instance,
\beginstt
"attack" "break" "smash" "hit" "fight" "wreck" "crack"
"destroy" "murder" "kill" "torture" "punch" "thump"
\endtt
are all treated as identical. But you might want to distinguish between
murder and lesser crimes. For this, try
\beginstt
Extend only "murder" "kill" replace * animate -> Murder;
\endtt
The keyword ^|only| tells Inform to extract the two verbs ``murder" and
``kill". These then become a new verb which is initially an identical copy
of the old one, but then |replace| tells Inform to throw that away in favour
of an entirely new grammar. Similarly,
\beginstt
Extend only "get" * "with" "it" -> Sing;
\endtt
makes ``get" behave exactly like ``take" (as usual) except that it also
recognises ``with it", so that ``get with it" makes the player sing but
``take with it" doesn't. Other good pairs to separate might be ``cross''
and ``enter'', ``drop'' and ``throw'', ``give'' and ``feed'', ``swim''
and ``dive'', ``kiss'' and ``hug'', ``cut'' and
``prune''.^^{pairs of verbs to separate}
\ddanger Bear in mind that once a pair has been split apart like this, any
subsequent extension made to one will not be made to the other.
\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, or even by restocking
the compass object with new directions in each room -- 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:
\beginstt
[ 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 ``shazam 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.^^{parser: tidying up questions asked by}
\ddangerexercise Implement the ^{Crowther and Woods} feature
of moving from one room to another by typing its name, using a
dummy verb.^^{named rooms}^^{`Advent'}
^^{exercises: moving to a room by typing its name}
\answer{^^{named rooms}
^^{exercises: moving to a room by typing its name}
The scheme will work like this: any room that ought to have a name
should have a |place_name| property set to a dictionary word;
say, the Bedquilt cave could be called |'bedquilt'|. Clearly
you should only be allowed to type this from adjacent rooms.
So we'll implement the following: you can only move by name to
those rooms listed in the current room's |to_places| property.
For instance, the Soft Room might have |to_places| set to
\beginlines
|to_places Bedquilt Slab_Room Twopit_Room;|
\endlines
Now the code: if the player's verb is not otherwise understood,
we'll check it to see if it's a place name of a nearby room,
and if so store that room's object number in |goto_room|, converting
the verb to |'go#room'| (which we'll deal with below).
\beginlines
|Global goto_room;|
|[ 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 ", (name) 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.'' in reply to, say, ``bedquilt the nugget''.) It remains
only to create 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'.}
\bigskip
\dangerexercise Implement a lamp which, when rubbed, produces a
^{genie} who casts a spell over the player to make him confuse the
words ^{``white'' and ``black''}.^^{``black'' and ``white''}
^^{lamp (of genie)}^^{exercises: genie muddling black and white}
\answer{^^{``white'' and ``black''}^^{``black'' and ``white''}
^^{genie}^^{lamp (of genie)}^^{exercises: genie muddling black and white}
\beginlines
|Object -> genies_lamp "brass lamp"|
| with name "brass" "lamp",|
| before|
| [; Rub: if (self hasnt general) give self general;|
| else give self ~general;|
| "A genie appears from the lamp, declaring:^^|
| ~Mischief is my sole delight:^|
| If white means black, black means white!~^^|
| She vanishes away with a vulgar wink.";|
| ];|
|Object -> white_stone "white stone" with name "white" "stone";|
|Object -> black_stone "black stone" with name "black" "stone";|
|...|
|[ BeforeParsing;|
| if (genies_lamp hasnt general) return;|
| for (wn=1::)|
| { switch(NextWordStopped())|
| { 'white': parse->(wn*2-3) = 'black';|
| 'black': parse->(wn*2-3) = 'white';|
| -1: return;|
| }|
| }|
|];|
\endlines^^|BeforeParsing|}
\refs ^{`Advent'} makes a string of simple |Verb| definitions;
^{`Alice Through The Looking-Glass'} uses |Extend| a little.
\nextref ^{`Balances'} has a large extra grammar and also
uses the |UnknownVerb| and |PrintVerb| entry points.
\section{27}{Tokens of grammar}
\noindent
The complete list of grammar tokens is as
follows:^^{grammar: tokens of}^^{tokens}
{\smallskip
%$-1
\baselineskip=7 true mm
\settabs 8\columns
\+& \rstok{|"|\<word>|"|} && that literal word only\cr
\+& \cstok{noun} && any object in scope\cr
\+& \cstok{held} && object held by the player\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
\+& \rstok{\<attribute>} && any object in scope which has the attribute\cr
\+& \cstok{creature} && an object in scope which is |animate|\cr
\+& \rstok{|noun = |\<Routine>} && any object in scope passing the given test\cr
\+& \rstok{|scope = |\<Routine>} && an object in this definition of scope\cr
\+& \cstok{number} && a number only\cr
\+& \rstok{\<Routine>} && any text accepted by the given routine\cr
\+& \cstok{topic} && any text at all\cr
\+& \cstok{special} && any single word or number\cr
\smallskip\par\noindent}^^{noun token}^^{held token}
^^{multiheld token}^^{multiexcept token}
^^{creature token}^^{special token}^^{number token}
These tokens are all described in this section except for
\rstok{|scope = |\<Routine>}, which is postponed to the next.
\bigskip\noindent\rstok{|"|\<word>|"|}\qquad
This matches only the literal word given, normally a preposition such
as |"into"|. Whereas most tokens produce a ``parameter'' (an object
or group of objects, or a number), this token doesn't. There can therefore
be as many or as few of them on a grammar line as desired.
It often happens that several prepositions really mean
the same thing for a given verb: "in", "into" and "inside"
are often equally sensible. As a convenient shorthand
you can write a series of prepositions with slash marks |/|
in between, to mean "one of these words". For example:
\beginstt
* noun "in"/"into"/"inside" noun -> Insert|
\endtt^{prepositions}
(Note that ^|/| can only be used with prepositions.)
\danger Prepositions like this are unfortunately sometimes called `adjectives'
inside the parser source code, and in Infocom hackers' documents: the usage
is traditional but has been avoided in this manual.
\bigskip\noindent\cstok{noun}\qquad
The definition of ``in scope'' will be given in the next section. Roughly,
it means ``visible to the player at the moment''.
\bigskip\noindent\cstok{held}\qquad
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
\beginstt
Verb "eat"
* held -> Eat;
\endtt
and the player types ``eat the banana''
while the ^{banana} is, say, in plain view on a shelf. It would be
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. This is called ``^{implicit taking}''.
\bigskip\noindent
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. A single grammar line can only
contain one \cstok{multi-} token: so ``hit everything with everything"
can't be parsed (straightforwardly, that is: you can parse {\sl anything}
with a little more effort). The reason not all nouns can be multiple
is that too helpful a parser makes too easy a game. You probably don't
want to allow ``unlock the mystery door with all the keys''
-- you want the player to suffer having to try them one at a time,
or else to be thinking.
\bigskip\noindent\cstok{multiexcept}\qquad
Provided to make commands like ``put everything in the rucksack''
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.
\bigskip\noindent\cstok{multiinside}\qquad
Similarly, this matches anything inside the other parameter on
the line, and is good for parsing commands like
``remove everything from the cupboard''.
\bigskip\noindent\rstok{\<attribute>}\qquad
This allows you to sort out objects according to attributes that they have:
\beginstt
Verb "use" "employ" "utilise"
* edible -> Eat
* clothing -> Wear
...and so on...
* enterable -> Enter;
\endtt^^{``use'' verb}^^{``employ'' verb}
though the library grammar does not contain such an
^{appallingly convenient verb}! Since you can define your own attributes,
it's easy to make a token matching only your own class of object.
\bigskip\noindent\cstok{creature}\qquad Same as \cstok{animate}
(a hangover from older editions of Inform).
\bigskip\noindent\rstok{|noun = |\<Routine>}\qquad
The last and most powerful of the ``a nearby object satisfying some condition''
tokens. When determining whether an object passes this test, the parser
sets the variable |noun| to the object in question and calls the routine.
If it returns true, the parser accepts the object, and otherwise it rejects it.
For example, the following should only apply to animals kept in a cage:
\beginstt
[ CagedCreature;
if (noun in wicker_cage) rtrue; rfalse;
];
Verb "free" "release"
* noun=CagedCreature -> FreeAnimal;
\endtt^^{``free'' verb}^^{caged animals}
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.
\bigskip\noindent\rstok{|scope = |\<Routine>}\qquad
An even more powerful token, which means ``an object in scope'' where
scope is redefined specially. See the next section.
\bigskip\noindent\cstok{number}\qquad 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. For example:
\beginstt
Verb "type"
* number -> TypeNum;
\endtt
causes actions like |Typenum 504| when the player types ``type 504''. Note
that |noun| is set to 504, not to an object.
\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.^^{exercises: footnotes}
\answer{^^{footnotes}^^{exercises: footnotes}
\beginlines
|Constant MAX_FOOTNOTES 10;|
|Array footnotes_seen -> 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)|
| "No footnote [", noun, "] has been mentioned.";|
| if (noun==0) "Footnotes count upward from 1.";|
| n=footnotes_seen->(noun-1);|
| print "[",noun,"] ";|
| switch(n)|
| { 0: "This is a footnote.";|
| 1: "D.G.REG.F.D is inscribed around English coins.";|
| 2: "~Jackdaws love my big sphinx of quartz~, for example.";|
| }|
|];|
|Verb "footnote" "note" * number -> Footnote;|
\endlines^^{jackdaws}^^{The quick brown fox jumped over the lazy dog}
And then you can code, for instance,
\beginlines
| print "Her claim to the throne is in every pocket ", (Note) 1,|
| ", her portrait in every wallet.";|
\endlines}
\danger
The entry point ^|ParseNumber| allows you to provide your own
^{number-parsing} routine, which opens up many sneaky possibilities --
Roman numerals, coordinates like ``J4", very long telephone numbers
and so on. This takes the form
\beginstt
[ 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|,
a row of characters of the given |length|. If you provide a |ParseNumber|
routine but return 0 from it, then the parser falls back on its usual
number-parsing mechanism to see if that does any better.
\ddanger Note that |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. (Sorry: this was a poor design decision made
too long ago to change now.)
\bigskip\noindent\rstok{\<Routine>}\qquad^^{general parsing routines}%
The most flexible token is simply the name of a ``general parsing routine''.
This looks at the word stream using |NextWord| and |wn| (see \S 24) and
should return:
\begindisplay
$-1$\quad if the text isn't understood,\cr
0\quad if it's understood but no parameter results,\cr
1\quad if a number results, or\cr
$n$\quad if the object $n$ results.\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 match 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. For example:
\beginstt
[ OnAtorIn w;
w=NextWord(); if (w=='on' or 'at' or 'in') return 0;
return -1;
];
\endtt^^{``on'', ``at'' or ``in''}
makes a token which accepts any of the words ``on", ``at" or ``in" as
prepositions (not translating into objects or numbers). Similarly,
\beginstt
[ Anything w; while (w~=-1) w=NextWordStopped(); return 0; ];
\endtt
accepts the entire rest of the line (ignoring it).
^|NextWordStopped| is a form of |NextWord| which returns $-1$ once the
original word stream has run out.
\bigskip\noindent\cstok{topic}\qquad^^{topic token}
This token matches as much text as possible.
It should either be at the end of its grammar line, or
be followed by a preposition. (The only way it can fail
to match is if it finds no text at all.) The library's
grammar uses this token for topics of conversation and
topics looked up in books (see \S\S 15, 16), hence the
name. The parser ignores the text for now (your own code
will have to think about it later), and simply sets
the variables |consult_from| to the number of the first word
of the matched text and |consult_words| to the number of words.
\bigskip
\noindent\cstok{special}\qquad Obsolete and best avoided.
\bigskip
\exercise Write a token to detect ^{low numbers in French}, ``un''
to ``cinq''.^^{French numbers}^^{exercises: low numbers in French}
\answer{^^{low numbers in French}^^{French numbers}
^^{exercises: low numbers in French}
The general parsing routine needed is:
\beginlines
|[ FrenchNumber n;|
| switch(NextWord())|
| { 'un', 'une': n=1;|
| 'deux': n=2;|
| 'trois': n=3;|
| 'quatre': n=4;|
| 'cinq': n=5;|
| default: return -1;|
| }|
| parsed_number = n; return 1;|
|];|
\endlines}
\dangerexercise Write a token to detect ^{floating-point numbers}
like ``$21$'', ``$5.4623$'', ``two point oh eight''
or ``$0.01$'', rounding off to two
^{decimal places}.^^{exercises: floating-point numbers}
\answer{^^{exercises: floating-point numbers}
First we must decide how to store ^{floating-point numbers}
internally: in this case we'll simply store $100x$ to represent
$x$, so that ``$5.46$'' will be parsed as $546$.
\beginlines
|[ DigitNumber n type x;|
| x = NextWordStopped(); if (x==-1) return -1; wn--;|
| if (type==0)|
| { x = WordAddress(wn);|
| if (x->n>='0' && x->n<='9') return (x->n) - '0';|
| return -1;|
| }|
| if (x=='nought' or 'oh') { wn++; return 0; }|
| x = TryNumber(wn++); if (x==-1000 || x>=10) x=-1; return x;|
|];|
|[ FloatingPoint a x b w d1 d2 d3 type;|
| a = TryNumber(wn++);|
| if (a==-1000) return -1;|
| w = NextWordStopped(wn); if (w==-1) return a*100;|
| x = NextWordStopped(wn); if (x==-1) return -1; wn--;|
| if (w=='point') type=1;|
| else|
| { if (WordAddress(wn-1)->0~='.' || WordLength(wn-1)~=1)|
| return -1;|
| }|
| d1 = DigitNumber(0,type);|
| if (d1==-1) return -1;|
| d2 = DigitNumber(1,type); d3 = DigitNumber(2,type);|
| b=d1*10; if (d2>=0) b=b+d2; else d3=0;|
| if (type==1)|
| { x=1; while (DigitNumber(x,type)>=0) x++; wn--;|
| }|
| else wn++;|
| parsed_number = a*100 + b;|
| if (d3>=5) parsed_number++;|
| return 1;|
|];|
\endlines}
\dangerexercise Write a token to match a phone number,
of any length from 1 to 30 digits, possibly broken up
with spaces or hyphens (such as ``01245 666
737'' or ``123-4567'').^^{phone number parsing}
^^{telephone number parsing}^^{exercises: phone numbers}
\answer{^^{exercises: phone numbers}
Again, the first question is how to store the
number dialled: in this case, into a |string| array. The token
is:^^{phone number parsing}^^{telephone number parsing}
\beginlines
|Constant MAX_PHONE_LENGTH = 30;|
|Array dialled_number string MAX_PHONE_LENGTH;|
|[ PhoneNumber f a l ch pp i;|
| pp=1; if (NextWordStopped()==-1) return 0;|
| do|
| { a=WordAddress(wn-1); l=WordLength(wn-1);|
| for (i=0:i<l:i++)|
| { ch=a->i;|
| if (ch<'0' || ch>'9')|
| { if (ch~='-') { f=1; if (i~=0) return -1; } }|
| else|
| { if (pp<MAX_PHONE_LENGTH)|
| dialled_number->(pp++)=ch-'0';|
| }|
| }|
| } until (f==1 || NextWordStopped()==-1);|
| if (pp==1) return -1;|
| dialled_number->0 = pp-1;|
| return 0;|
|];|
\endlines
To demonstrate this in use,
\beginlines
|[ DialPhoneSub i;|
| print "You dialled <";|
| for (i=1:i<=dialled_number->0:i++) print dialled_number->i;|
| ">";|
|];|
|Verb "dial" * PhoneNumber -> DialPhone;|
\endlines}
\ddangerexercise (Adapted from code in ^{Andrew Clover}'s
^{`timewait.h'} library extension.)
Write a token to match any description of a time of day,
such as ``quarter past five'', ``12:13 pm'', ``14:03'',
``six fifteen'' or ``seven o'clock''.^^{time of day (parsing)}
^^{exercises: parsing times of day}
\answer{^^{time of day (parsing)}
^^{exercises: parsing times of day}
The time of day will
be returned as a number in the usual Inform time format:
as hours times 60 plus minutes (on the 24-hour clock, so
that the `hour' part is between 0 and 23).
\beginlines
|Constant TWELVE_HOURS = 720;|
|[ NumericTime hr mn word x;|
| if (hr>=24) return -1;|
| if (mn>=60) return -1;|
| x=hr*60+mn; if (hr>=13) return x;|
| x=x%TWELVE_HOURS; if (word=='pm') x=x+TWELVE_HOURS;|
| if (word~='am' or 'pm' && hr==12) x=x+TWELVE_HOURS;|
| return x;|
|];|
|[ MyTryNumber wordnum i j;|
| i=wn; wn=wordnum; j=NextWordStopped(); wn=i;|
| switch(j)|
| { 'twenty-five': return 25;|
| 'thirty': return 30;|
| default: return TryNumber(wordnum);|
| }|
|];|
|[ TimeOfDay i j k flag loop ch hr mn;|
| i=NextWord();|
| switch(i)|
| { 'midnight': parsed_number=0; return 1;|
| 'midday', 'noon': parsed_number=TWELVE_HOURS; return 1;|
| }|
| ! Next try the format 12:02|
| j=WordAddress(wn-1); k=WordLength(wn-1);|
| flag=0;|
| for (loop=0:loop<k:loop++)|
| { ch=j->loop;|
| if (ch==':' && flag==0 && loop~=0 && loop~=k-1) flag=1;|
| else { if (ch<'0') flag=-1; if (ch>'9') flag=-1; }|
| }|
| if (k<3) flag=0; if (k>5) flag=0;|
| if (flag==1)|
| { for (loop=0:j->loop~=':':loop++, hr=hr*10)|
| hr=hr+j->loop-'0';|
| hr=hr/10;|
| for (loop++:loop<k:loop++, mn=mn*10)|
| mn=mn+j->loop-'0';|
| mn=mn/10;|
| j=NextWordStopped();|
| parsed_number=NumericTime(hr, mn, j);|
| if (parsed_number<0) return -1;|
| if (j~='pm' or 'am') wn--;|
| return 1;|
| }|
| ! Next the format "half past 12"|
| j=-1; if (i=='half') j=30; if (i=='quarter') j=15;|
| if (j<0) j=MyTryNumber(wn-1); if (j<0) return -1;|
| if (j>=60) return -1;|
| k=NextWordStopped();|
| if (k==-1)|
| { hr=j; if (hr>12) return -1; jump TimeFound; }|
| if (k=='o^clock' or 'am' or 'pm')|
| { hr=j; if (hr>12) return -1; jump TimeFound; }|
| if (k=='to' or 'past')|
| { mn=j; hr=MyTryNumber(wn);|
| if (hr<=0)|
| { switch(NextWordStopped())|
| { 'noon', 'midday': hr=12;|
| 'midnight': hr=0;|
| default: return -1;|
| }|
| }|
| if (hr>=13) return -1;|
| if (k=='to') { mn=60-mn; hr=hr-1; if (hr==-1) hr=23; }|
| wn++; k=NextWordStopped();|
| jump TimeFound;|
| }|
| hr=j; mn=MyTryNumber(--wn);|
| if (mn<0) return -1; if (mn>=60) return -1;|
| wn++; k=NextWordStopped();|
| .TimeFound;|
| parsed_number = NumericTime(hr, mn, k);|
| if (parsed_number<0) return -1;|
| if (k~='pm' or 'am' or 'o^clock') wn--;|
| return 1;|
|];|
\endlines}
\dangerexercise Code a spaceship control panel with five
sliding controls, each set to a numerical value, so that
the game looks like:^^{spaceship control panel}
^^{exercises: 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 one to the value 5.|
|>examine the first slide|
|Slide one currently stands at 5.|
|>set four to six|
|You set slide four to the value 6.|
\endlines
\answer{^^{exercises: spaceship control panel}
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) return -1;|
| w=NextWord(); if (w=='slide') w=NextWord();|
| switch(w)|
| { 'first', 'one': n=1;|
| 'second', 'two': n=2;|
| 'third', 'three': n=3;|
| 'fourth', 'four': n=4;|
| 'fifth', 'five': n=5;|
| default: return -1; ! Failure!|
| }|
| w=NextWord(); if (w~='slide') wn--; ! (Leaving word counter at the|
| ! first misunderstood word)|
| parsed_number=n;|
| return 1; ! Success!|
|];|
|Global slide_settings --> 5; ! A five-word array|
|[ 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}
\ddanger General parsing routines sometimes need to get at the ^{raw
text} originally typed by the player. Usually |WordAddress| and
|WordLength| (see \S 24) are adequate. If not, it's helpful to know
that the parser keeps a |string| array called ^|buffer| holding:
\begindisplay
|buffer->0| $=$ \<maximum number of characters which can fit in buffer>\cr
|buffer->1| $=$ \<the number $n$ of characters typed>\cr
|buffer->2|...|buffer->|$(n+1)$ $=$ \<the text typed>\cr
\enddisplay^^{text buffer (of parser)}
^^{parsing: text buffer holding commands}
and, in parallel with this, another one called ^|parse| holding:
\begindisplay
|parse->0| $=$ \<maximum number of words which can fit in buffer>\cr
|parse->1| $=$ \<the number $m$ of words typed>\cr
|parse->2|... $=$ \<a four-byte block for each word, as follows>\cr
\qquad |block-->0| $=$ \<the dictionary entry if word is known, 0 otherwise>\cr
\qquad |block->2| $=$ \<number of letters in the word>\cr
\qquad |block->3| $=$ \<index to first character in the ^|buffer|>\cr
\enddisplay
(However, for version 3 games the format is slightly different:
in |buffer| the text begins at byte 1, not at byte 2, and its end
is indicated with a zero terminator byte.) Note that the raw text
is reduced to lower case automatically, even if within quotation marks.
Using these buffers directly is perfectly safe but not recommended
unless there's no other way, as it tends to make code rather illegible.
\ddangerexercise Try to implement the parser's routines ^|NextWord|,
^|WordAddress| and ^|WordLength|.^^{exercises: implementing parser primitives}
\answer{^^{exercises: implementing parser primitives}
(See the |Parser| file.) ^|NextWord| roughly returns
|parse-->(w*2-1)| (but it worries a bit about commas and
full stops).
\beginlines
|[ WordAddress w; return buffer + parse->(w*4+1); ];|
|[ WordLength w; return parse->(w*4); ];|
\endlines^^|WordAddress|^^|WordLength|}
\ddangerexercise (Difficult.) Write a general parsing routine accepting
any amount of text (including spaces, full stops and commas)
between double-quotes as a single token.^^{parser: parsing quoted strings}
^^{exercises: parsing any quoted text}
\answer{^^{exercises: parsing any quoted text}
^^{parser: parsing quoted strings}
(Cf. the ^{blackboard} code in ^{`Toyshop'}.)
\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 0;|
| }|
| 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 text is treated as though it
were a preposition, and the positions where the quoted text starts and
finishes in the raw text ^|buffer| are recorded, 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}^^{tokenising}}
\exercise How would you code a general parsing routine which
never matches anything?^^{token never matching anything}
^^{exercises: tokens which never match}
\answer{^^{token never matching anything}
^^{exercises: tokens which never match}
\beginlines
|[ NeverMatch; return -1; ];|
\endlines}
\ddangerexercise Why would you code a general parsing routine which
never matches anything?
\answer{Perhaps to arrange better error messages when the text
has failed all the `real' grammar lines of a verb (see
^{`Encyclopaedia Frobozzica'} for an example).}
\dangerexercise An apparent restriction of the parser is that it only
allows two parameters (|noun| and |second|). Write a general parsing
routine to accept a |third|. (This final exercise with general parsing
routines is easier than it looks: see the specification of the |NounDomain|
library routine in \S A9.)^^{third parameter for parser}
^^{exercises: third noun for parser}
\answer{^^{third parameter for parser}
^^{exercises: third noun for parser}
(See the ^|NounDomain| specification in \S A9.) This routine passes
on any |REPARSE_CODE|, as it must, but keeps a matched object in
its own |third| variable, returning the `skip this text' code to
the parser. Thus the parser never sees any third parameter.
\beginlines
|Global third;|
|[ ThirdNoun x;|
| x=NounDomain(player,location,0);|
| if (x==REPARSE_CODE) return x; if (x==0) return -1; third = x;|
| return 0;|
|];|
\endlines^^|REPARSE CODE|}
\section{28}{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} ({\oldstyle1872}--{\oldstyle1956}), of ^{George Bernard Shaw}}
\poem
Wherefore are these things hid?
\poemby{^{William Shakespeare} ({\oldstyle1564}--{\oldstyle1616})}{Twelfth Night}
\noindent
Time to say what ``in scope" means. This definition is one of the most
important rules of play, because it decides what the player is allowed
to refer to. You can investigate this in practice by compiling any game
with the debugging suite of verbs included and typing ``scope'' in
different places: but here are the rules in full. The following are in
scope:^^{scope}^^{in scope}
\begindisplay
the player's immediate possessions;\cr
the 12 compass directions;\cr
if there is light (see \S 17), the objects in the same `enclosure'
as the player;\cr
if not, any objects in the |thedark| object;
if the player is inside a dark |container|, then that container.\cr
\enddisplay\noindent
The `enclosure' of the player is usually the current location. Formally,
it's the outermost object containing the player which remains visible --
for instance, if the player is in a transparent cabinet in a closed,
huge cupboard in the Stores Room, then the enclosure is the huge cupboard.
(Thus items in the huge cupboard are in scope, subject to the remaining
rules, but other items in the Stores Room are not.)
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\noindent
In addition, if an object is in scope then anything which
it ``adds to scope'' is also in scope.
\medskip
\danger The player's possessions are in scope in a dark room -- so the
player can still turn his lamp on. 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: affecting scope}
\danger Compass directions make sense as things. The player can
always type something like ``attack the south wall'' and the |before| rule
for the room could trap the action |Attack s_obj| to make something unusual
happen, if this is desired.
\danger The parser applies scope rules to all ^{actor}s, not just the
player. Thus ``dwarf, drop sword'' will be accepted if the dwarf can
see it, even if the player can't.
\danger The ^|concealed| attribute only hides objects from room
descriptions, and doesn't remove them from scope. If you want things to
be both concealed and unreferrable-to, put them somewhere else! Or
give them an uncooperative |parse_name| routine.^^|parse name|
\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
\noindent
Two library routines are provided to enable you to see what's in
scope and what isn't. The first, |TestScope(obj, actor)|, simply returns
true or false according to whether or not |obj| is in scope. The
second is |LoopOverScope(routine, actor)| and calls the given routine
for each object in scope. In each case the |actor| given is optional;
if it's omitted, scope is worked out for the player as
usual.^^{scope: looping over}^^{scope: testing}
\exercise Implement the debugging suite's ``scope'' verb,
which lists all the objects currently in
scope.^^{``scope'' verb exercise}^^{exercises: ``scope'' verb}
\answer{^^{``scope'' verb exercise}^^{exercises: ``scope'' verb}
\beginlines
|Global scope_count;|
|[ PrintIt obj; print_ret ++scope_count, ": ", (a) obj, " (", obj, ")"; ];|
|[ ScopeSub; LoopOverScope(PrintIt);|
| if (scope_count==0) "Nothing is in scope.";|
|];|
|Verb meta "scope" * -> Scope;|
\endlines}
\exercise Write a ``megalook'' verb, which looks around and
examines everything nearby.^^{``megalook'' verb}^^{exercises: ``megalook'' verb}
\answer{^^{``megalook'' verb}^^{exercises: ``megalook'' verb}
\beginlines
|[ MegaExam obj; print "^", (a) obj, ": "; <Examine obj>; ];|
|[ MegaLookSub; <Look>; LoopOverScope(MegaExam); ];|
|Verb meta "megalook" * -> MegaLook;|
\endlines}
\medskip
Formally, scope determines what you can talk about, which usually
means what you can see. But what can you touch? Suppose a locked
chest is inside a sealed glass cabinet. The Inform parser will
allow the command ``unlock chest with key'' and generate the
appropriate action, |Unlock chest key|, because the chest is in
scope, so the command at least makes sense.
But it's impossible to carry out, because the player can't reach
through the solid glass. So the library's routine for handling the
|Unlock| action needs to enforce this. The library does this
using a stricter rule called ``^{touchability}''. The rule is that
you can touch anything in scope unless there's a closed container
between you and it. This applies either if you're in the container,
or if it is.
Some purely visual actions don't require touchability -- |Examine|
or |LookUnder|, for instance. But most actions are tactile, and
so will many actions created by designers. If you want to make
your own action routines enforce touchability, you can call the
library routine ^|ObjectIsUntouchable(obj)|. This either returns
|false| if there's no problem in touching |obj|, or returns |true|
and prints a suitable message (such as ``The solid glass cabinet
is in the way.''). Thus, the first line of many of the library's
action routines is:
\beginstt
if (ObjectIsUntouchable(noun)) return;
\endtt^^{untouchability}
You can also call |ObjectIsUntouchable(obj, true)| to simply return
true or false, and print nothing, if you'd rather provide your
own failure message.
\noindent
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 work locally. To take a typical example: how do we allow the
player to ask questions like the traditional
^{``what is a grue''}^^{grues}^^{parser: parsing the player's questions}
^^{questions, parsing the player's}^^{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_ret (string) noun.description;|
|];|
|[ Topic i;|
| switch(scope_stage)|
| { 1: rfalse;|
| 2: objectloop (i in questions) PlaceInScope(i); rtrue;|
| 3: "At the moment, even the simplest questions confuse you.";|
| }|
|];|
\endlines
where the actual questions at any time are the current children of
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, as it will never appear;
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
asked ``what is the count''.
When the parser reaches \cstok{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 obliged to
tell the parser which objects are to be in scope. It can call two
parser routines to do this.
\beginstt
ScopeWithin(object)
\endtt
puts everything inside the object into scope, though not the object itself;
\beginstt
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
\smallskip
\item{0} (false) to carry on with the usual scope rules, so that everything
that would usually be in scope still is, or
\item{1} (true) to tell the parser not to put any more objects into scope.
\par\smallskip\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
the usual miscellany near the player.
This is enough to deal with ``what is the long count''. If on the other
hand the player typed ``what is the lgon cnout'', 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 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 on. 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.^^{exercises: putting everything in scope}
\answer{^^{exercises: putting everything in scope}
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.
But here's how it could be done:
\beginlines
|[ Anything i;|
| if (scope_stage==1) rfalse;|
| if (scope_stage==2)|
| { objectloop (i ofclass Object) 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\noindent
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}\
The global definition can be tampered with by providing the entry point
\beginstt
InScope(actor)
\endtt
where the ^|actor| is usually the player, but not always. If the routine
decides that a particular object should be in scope for the actor,
it should execute |PlaceInScope| 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 The token \rstok{|scope=|\<Routine>} takes precedence over
|InScope|, which will only be reached if the routine returns
false to signify `carry on'.
\ddanger There are seven reasons why |InScope| might be being
called; the |scope_reason| variable is set to the current
one:^^|scope reason|^^{reasons for scope searching}
\smallskip\ninepoint
\stepin=150pt
\block{PARSING\_REASON}^^|PARSING REASON|
The usual one. Note that |action_to_be| holds
|NULL| in the early stages (before the verb has been decided)
and later on the action which would result from a successful match.
\block{TALKING\_REASON}^^|TALKING REASON|
Working out which objects are in scope for being spoken to (see
the end of \S 16 for exercises using this).
\block{EACHTURN\_REASON}^^|EACHTURN REASON|
When running |each_turn| routines for anything nearby, at the end of
each turn.
\block{REACT\_BEFORE\_REASON}^^|REACT BEFORE REASON|
When running |react_before|.
\block{REACT\_AFTER\_REASON}^^|REACT AFTER REASON|
When running |react_after|.
\block{TESTSCOPE\_REASON}^^|TESTSCOPE REASON|
When performing a |TestScope|.
\block{LOOPOVERSCOPE\_REASON}^^|LOOPOVERSCOPE REASON|
When performing a |LoopOverScope|.
\stepin=60pt
\medskip\noindent
Here are some examples. Firstly, as promised, how to change the
rule that ``things you've just dropped disappear in the dark":
\beginlines
|[ InScope person i;|
| if (person==player && location==thedark)|
| objectloop (i near player)|
| if (i has moved)|
| PlaceInScope(i);|
| rfalse;|
|];|
\endlines
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.
\ddangerexercise Construct a long room divided by a ^{glass window}.
Room descriptions on either side should describe what's in view on
the other; the window should be lookable-through; objects on the far
side should be in scope, but not manipulable; and everything should
cope well if one side is in
darkness.^^{divided room}^^{room divided in half}
^^{exercises: room divided by glass window}
\answer{^^{divided room}^^{room divided in half}^^{glass window}
^^{exercises: room divided by glass window}
Note the sneaky way looking through the window is implemented, and that
the `on the other side' part of the room description isn't printed
in that case.
\beginlines
|Property far_side;|
|Class Window_Room|
| with description|
| "This is one end of a long east/west room.",|
| before|
| [; Examine, Search: ;|
| default:|
| if (inp1~=1 && noun~=0 && noun in self.far_side)|
| print_ret (The) noun, " is on the far side of|
| the glass.";|
| if (inp2~=1 && second~=0 && second in self.far_side)|
| print_ret (The) second, " is on the far side of|
| the glass.";|
| ],|
| after|
| [; Look:|
| if (ggw has general) rfalse;|
| print "^The room is divided by a great glass window";|
| if (location.far_side hasnt light) " onto darkness.";|
| print ", stretching from floor to ceiling.^";|
| if (Locale(location.far_side,|
| "Beyond the glass you can see",|
| "Beyond the glass you can also see")~=0) ".";|
| ],|
| has light;|
|Window_Room window_w "West of Window"|
| with far_side window_e;|
|Window_Room window_e "East of Window"|
| with far_side window_w;|
|Object ggw "great glass window"|
| with name "great" "glass" "window",|
| before|
| [ place; Examine, Search: place=location;|
| if (place.far_side hasnt light)|
| "The other side is dark.";|
| give self general;|
| PlayerTo(place.far_side,1); <Look>; PlayerTo(place,1);|
| give self ~general;|
| give place.far_side ~visited; rtrue;|
| ],|
| found_in window_w window_e,|
| has scenery;|
\endlines
A few words about ^|inp1| and ^|inp2| are in order. |noun| and
|second| can hold either objects or numbers, and it's sometimes useful
to know which. |inp1| is equal to |noun| if that's an object,
or 1 if that's a number; likewise for |inp2| and |second|. (In this
case we're just being careful that the action |SetTo eggtimer 35|
wouldn't be stopped if object 35 happened to be on the other side of
the glass.) We also need:
\beginlines
|[ InScope actor;|
| if (actor in window_w && window_e has light) ScopeWithin(window_e);|
| if (actor in window_e && window_w has light) ScopeWithin(window_w);|
| rfalse;|
|];|
\endlines}
\ddangerexercise Code the following puzzle.
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.^^{darkness: changing scope within}
^^{exercises: dwarf breathing in dark}
\answer{^^{exercises: dwarf breathing in dark}
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}
^^{darkness: changing scope within}
\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;|
||
|Object -> 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;|
||
|Object -> diamond "shiny diamond"|
| with name "shiny" "diamond"|
| has scored;|
||
|Object -> 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.}
\noindent
As mentioned in the definition above, each object has the ability
to drag other objects into scope whenever it is in scope. This is
especially useful for giving objects component parts: e.g., giving a
^{washing-machine} a ^{temperature dial}. (The dial can't be a child
object because that would throw it in with the clothes: and it ought to be
attached to the machine in case the machine is moved from place to place.)
For this purpose, the property |add_to_scope| may contain a list of
objects to add.
^^|add to scope|^^{scope: addition to}^^{component parts of objects}^^{sub-objects}
\danger Alternatively, it may contain a routine. This routine can then
call |AddToScope(x)| to put any object |x| into scope. It may not,
however, call |ScopeWithin| or any other scoping routines.
\ddanger Scope addition does {\it not} occur for an object moved
into scope by an explicit call to |PlaceInScope|, since this must allow
complete freedom in scope selections. But it does happen when objects
are moved in scope by calls to |ScopeWithin(domain)|.
\exercise (From the tiny example game ^{`A Nasal Twinge'}.) Give the
player a ^{nose}, which is always in scope and can be held, reducing
the player's carrying capacity.^^{exercises: nose attached to player}
\answer{^^{exercises: nose attached to player}
In the |Initialise| routine, move |newplay| somewhere and
|ChangePlayer| to it, where:
\beginlines
|Object newplay "yourself"|
| with description "As good-looking as ever.", number 0,|
| add_to_scope nose,|
| capacity 5,|
| before|
| [; Inv: if (nose has general) print "You're holding your nose. ";|
| Smell: if (nose has general)|
| "You can't smell a thing with your nose held.";|
| ],|
| has concealed animate proper transparent;|
||
|Object nose "nose"|
| with name "nose", article "your",|
| before|
| [; Take: if (self has general)|
| "You're already holding your nose.";|
| if (children(player) > 1) "You haven't a free hand.";|
| give self general; player.capacity=1;|
| "You hold your nose with your spare hand.";|
| Drop: if (self hasnt general) "But you weren't holding it!";|
| give self ~general; player.capacity=5;|
| print "You release your nose and inhale again. ";|
| <<Smell>>;|
| ],|
| has scenery;|
\endlines^^{`A Nasal Twinge'}^^{nose}}
\exercise (Likewise.) Create a portable ^{sterilising machine}, with a
``go'' button, a top which things can be put on and an inside to hold
objects for sterilisation. (Thus it is a container, a supporter
and a possessor of sub-objects all at
once.)^^{exercises: sterilising machine}
\answer{^^{exercises: sterilising machine}
\beginlines
|Object steriliser "sterilising machine"|
| with name "washing" "sterilising" "machine",|
| add_to_scope top_of_wm go_button,|
| before|
| [; PushDir: AllowPushDir(); rtrue;|
| Receive:|
| if (receive_action==##PutOn)|
| <<PutOn noun top_of_wm>>;|
| SwitchOn: <<Push go_button>>;|
| ],|
| after|
| [; PushDir: "It's hard work, but the steriliser does roll.";|
| ],|
| initial|
| [; print "There is a sterilising machine on casters here (a kind of|
| chemist's washing machine) with a ~go~ button. ";|
| if (children(top_of_wm)~=0)|
| { print "On top";|
| WriteListFrom(child(top_of_wm), ISARE_BIT + ENGLISH_BIT);|
| print ". ";|
| }|
| if (children(self)~=0)|
| { print "Inside";|
| WriteListFrom(child(self), ISARE_BIT + ENGLISH_BIT);|
| print ". ";|
| }|
| ],|
| has static container open openable;|
|Object top_of_wm "top of the sterilising machine",|
| with article "the",|
| has static supporter;|
|Object go_button "~go~ button"|
| with name "go" "button",|
| before [; Push, SwitchOn: "The power is off."; ],|
| has static;|
\endlines^^{`A Nasal Twinge'}^^{sterilising machine}}
\ddangerexercise Create a ^{red sticky label} which the player can affix
to any object in the game. (Hint: use |InScope|, not
|add_to_scope|.)^^{label, red sticky}^^{exercises: red sticky label}
\answer{^^{red sticky label}^^{label, red sticky}
^^{exercises: red sticky label}
The label object itself is not too bad:
\beginlines
|Object -> label "red sticky label"|
| with name "red" "sticky" "label",|
| number 0,|
| before|
| [; PutOn, Insert:|
| if (self.number~=0)|
| { print "(first removing the label from ",|
| (the) self.number, ")^"; self.number=0; move self to player;|
| }|
| if (second==self) "That would only make a red mess.";|
| self.number=second; remove self;|
| print_ret "You affix the label to ", (the) second, ".";|
| ],|
| react_after|
| [ x; x=self.number; if (x==0) rfalse;|
| Look: if (x in location)|
| print "^The red sticky label is stuck to ", (the) x, ".^";|
| Inv: if (x in player) |
| print "^The red sticky label is stuck to ", (the) x, ".^";|
| ],|
| each_turn|
| [; if (parent(self)~=0) self.number=0; ];|
\endlines
Note that |label.number| holds the object the label is stuck to, or
0 if it's unstuck: and that when it is stuck, it is removed from the
object tree. It therefore has to be moved into scope, so we need the
rule: if the labelled object is in scope, then so is the label.
\beginlines
|Global disable_self;|
|[ InScope actor i1 i2;|
| if (label.number==0) rfalse; if (disable_self==1) rfalse;|
| disable_self=1;|
| i1 = TestScope(label, actor);|
| i2 = TestScope(label.number, actor);|
| disable_self=0;|
| if (i1~=0) rfalse;|
| if (i2~=0) PlaceInScope(label);|
| rfalse;|
|];|
\endlines
This routine has two interesting points: firstly, it disables itself
while testing scope (since otherwise the game would go into an endless
recursion), and secondly it only puts the label in scope if it isn't
already there. This is just a safety precaution to prevent the label
reacting twice to actions (and isn't really necessary since the label
can't already be in scope, but is included for the sake of example).}
\refs ^{`Balances'} uses \rstok{|scope = |\<routine>} tokens
for legible spells and memorised spells.
\nextref See also the exercises at the end of \S 16 for further
scope trickery.
\newpage
\section{29}{Helping the parser out of trouble}
\danger
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. The ^|ParserError| entry point can change the rules even
at this last hurdle: it takes one argument, the error type, and should
return true to tell the parser to shut up, because a better error
message has already been printed, or false, to tell the parser to
print its usual message. The error types are all defined as
constants:
{\ninepoint\medskip
\settabs 8\columns
\+& |STUCK_PE| && I didn't understand that sentence.\cr
\+& |UPTO_PE | && I only understood you as far as$\ldots$\cr
\+& |NUMBER_PE| && I didn't understand that number.\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$\ldots$\cr
\+& |ITGONE_PE| && You can't see `it' (the {\it whatever}) 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
\+& |ASKSCOPE_PE| && {\it whatever the scope routine prints}\cr
\medskip\par\noindent\tenpoint}^^{error numbers used by parser}
^^{parser: error numbers}
Each unsuccessful grammar line ends in 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.
\danger The |VAGUE_PE| and |ITGONE_PE| apply to all pronouns
(in English, ``it'', ``him'', ``her'' and ``them'').
The variable |vague_word| contains
the dictionary address of which is involved
(|'it'|, |'him'|, etc.).^^|vague word|^^|vague obj|
You can find out the current setting of a pronoun using
the library's ^|PronounValue| routine: for instance,
|PronounValue('it')| would give the object which ``it''
currently refers to (possibly |nothing|). Similarly
|SetPronoun('it', magic_ruby)| would set ``it'' to mean
the magic ruby object. (When something like a magic ruby
suddenly appears in the middle of a turn, players will
habitually call it ``it''.) A better way to adjust the
pronouns is to call |PronounNotice(magic_ruby)|, which
sets whatever pronouns are appropriate. That is, it
works out if the object is a thing or a person, of what
number and gender, which pronouns apply to it in the parser's
current language, and so on. In code predating Inform 6.1
you may see variables called ^|itobj|, ^|himobj| and
^|herobj| holding the English pronoun values: these still
work properly, but please use the modern system in new
games.^^{pronouns}
\danger The Inform parser resolves ^{ambiguous inputs} with a
complicated algorithm based on practical experience. However,
it can't have any expertise with newly-created verbs: here is
how to provide it. If you define a routine
\beginstt
ChooseObjects(object, code)
\endtt^^|ChooseObjects|^^{ambiguity}^^{``all''}^^{resolving ambiguity}
then it's called in two circumstances. If |code| is 0 or 1,
the parser is considering including the given object in an ``all'':
0 means the parser has decided against, 1 means it has decided
in favour. The routine should reply
\begindisplay
0\qquad (or false) to say ``carry on'';\cr
1\qquad to force the object to be included; or\cr
2\qquad to force the object to be excluded.\cr
\enddisplay^^|verb word|^^|action to be|
It may want to decide using |verb_word| (the variable storing
the current verb word, e.g., |'take'|) and |action_to_be|, which
is the action which would happen if the current line of
grammar were successfully matched.
\ninepoint
The other circumstance is when |code| is 2. This means the parser
is sorting through a list of items (those in scope which best matched
the input), trying to decide which single
one is most likely to have been intended. If it can't choose a best
one, it will give up and ask the player. |ChooseObjects| should
then return a number from 0 to 9 (0 being the default) to give the
object a score for how appropriate it is.
For instance, some designers would prefer ^{``take all''} not to attempt
to take |scenery| objects (which Inform, and the parsers in most of the
Infocom games, will do). Let us code this, and also teach the parser that
edible things are more likely to be eaten than inedible ones:
\beginstt
[ ChooseObjects obj code;
if (code<2) { if (obj has scenery) return 2; rfalse; }
if (action_to_be==##Eat && obj has edible) return 3;
if (obj hasnt scenery) return 2;
return 1;
];
\endtt^^{scenery penalised}^^{eating edible things for preference}
Scenery is now excluded from ``all'' lists; and is further
penalised in that non-scenery objects are always preferred over
scenery, all else being equal. Most objects score 2 but
edible things in the context of eating score 3, so ``eat black''
will now always choose a ^{Black Forest gateau} in preference to
a black rod with a rusty iron star on the end.
\dangerexercise Allow ``lock'' and ``unlock'' to infer their second
objects without being told, if there's an obvious choice (because
the player's only carrying one key), but to issue a disambiguation
question otherwise. (Use |Extend|, not
|ChooseObjects|.)^^{``lock'' and ``unlock'' disambiguation}
^^{disambiguation}^^{exercises: ``lock'' and ``unlock'' inferring keys}
\answer{^^{``lock'' and ``unlock'' disambiguation}^^{disambiguation}
^^{exercises: ``lock'' and ``unlock'' inferring keys}
Firstly, create an attribute |is_key| and give it to all the keys in
the game. Then:
\beginlines
|Global assumed_key;|
|[ DefaultLockSub;|
| print "(with ", (the) assumed_key, ")^"; <<Lock noun assumed_key>>;|
|];|
|[ DefaultLockTest i count;|
| if (noun hasnt lockable) rfalse;|
| objectloop (i in player)|
| if (i has is_key) { count++; assumed_key = i; }|
| if (count==1) rtrue; rfalse;|
|];|
|Extend "lock" first * noun = DefaultLockTest -> DefaultLock;|
\endlines
(and similar code for ``unlock''). Note that ``lock strongbox''
is matched by this new grammar line only if the player only has one
key: the |DefaultLock strongbox| action is generated: which is
converted to, say, |Lock strongbox brass_key|.}
\tenpoint
\refs See ^{`Balances'} for a usage of |ParserError|.
\chapter{Chapter VI: Testing and Hacking}
\section{30}{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}
\noindent^^{debugging}
Infocom claimed to have fixed nearly 2000 bugs in the course of writing
^{`Sorcerer'}, which is a relatively simple game today. Adventure games are
exhausting programs to test and debug because of the huge number of states
they can get into, many of which did not occur to the author. (For
instance, if the player solves the ``last'' puzzle first, do the other
puzzles still work properly? Are they still fair?) The main source of
error is simply the designer not noticing that some states are possible. The
Inform library can't help with this, but it does contain features to help
the tester to quickly reproduce states (by moving objects around freely, for
instance) and to see what the current state actually is (by displaying the
tree of objects, for instance).
Inform provides a small suite of debugging verbs,
which will be added to any game compiled with the |-D| switch.
If you prefer, you can include them manually by writing
\beginstt
Constant DEBUG;
\endtt^|DEBUG|
somewhere in the program before the library files are included.
(Just in case you forget having done this, the letter |D| appears
in the game banner to stop you releasing such a version by accident.)
You then get the following verbs, which can be used at any time in play:
\beginstt
showobj <anything>
purloin <anything>
abstract <anything> to <anything>
tree tree <anything>
scope scope <anything>
showverb <verb>
goto <number> gonear <anything>
actions actions on actions off
routines routines on routines off
messages messages on messages off
timers timers on timers off
trace trace on trace off trace <1 to 5>
recording recording on recording off
replay
random
\endtt^^{debugging: suite of verbs}
``showobj'' is very informative about the current state of an object.
You can ``purloin" any item or items in your game at any time, wherever
you are. This clears |concealed| for anything it takes, if necessary.
You can likewise ``abstract" any item to any other item (meaning:
move it to the other item). To get a listing of the objects in the game
and how they contain each other, use ``tree", and to see the possessions of
one of them alone, use ``tree \<that>". The command ``scope'' prints a
list of all the objects currently in scope, and can optionally be given
the name of someone else you want a list of the scope for (e.g., ``scope
pirate''). ``showverb'' will display the grammar being used when the
given verb is parsed. Finally, you can go anywhere, but since rooms don't
have names understood by the parser, you have to give either the object number,
which you can find out from the ``tree'' listing, or the name of some object in
the room you want to go to (this is what ``gonear'' does).
^^{``actions'' verb}^^{``tree'' verb}^^{``purloin'' verb}^^{``routines'' verb}
^^{``trace'' verb}^^{``messages'' verb}
^^{``abstract'' verb}^^{``goto'' verb}^^{``gonear'' verb}
^^{``scope'' verb}^^{``showobj'' verb}^^{``showverb'' 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). It also describes all messages sent in the game, which is
why it can also be written as ``messages''.
Turning on ``timers'' shows the state of all active timers
and daemons each turn.^^{``timers'' verb}
^^{tracing routines, actions, daemons and timers}\
The commands you type can be transcribed to a file with the
^{``recording'' verb}, and run back through with the ^{``replay'' verb}.
(This may not work under some implementations of the ITF interpreter.)
If you're going to use such recordings, you will need to fix the random
number generator, and the ^{``random'' verb} should render this
deterministic: i.e., after any two uses of ``random'', the same stream
of random numbers results. Random number generation is poor on some
machines: you may want to |Replace| the random-number generator in
software instead.
\medskip\noindent
A ^{source-level debugger} for Inform, called ^{Infix}, has been planned
for some years, and may possibly be coming to fruition soon.
\danger For the benefit of such tools, Inform (if compiling with the
|-k| option set) produces a file of ``debugging information''
(cross-references of the game file with the source code),
and anyone interested in writing an Inform utility program may want
to know the format of this file: see the {\sl Technical Manual} for
details.^^{debugging: information file}^^{debugging: using Infix}
\noindent
On most interpreters, though, ^{run-time crashes} can be mysterious, since
the interpreters were written on the assumption that they would only ever
play Infocom game files (which are largely error-free). A Standard
interpreter is better here and will usually tell you why and where the
problem is; given a game file address you can work back to the problem
point in the source either with Mark Howell's ^{txd (disassembler)}
or by running Inform with the assembler trace option on.
Here are all the ways I know to crash an interpreter at run-time (with
high-level Inform code, that is; if you insist on using
assembly language or the ^|indirect| function you're raising the stakes),
arranged in decreasing order of likelihood:
^^{crashing the interpreter}
\smallskip
\item{$\bullet$} Writing to a property which an object 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 (use |print (name)|, |print (the)| etc., instead
as these are safeguarded);
\item{$\bullet$} Using |print (string)| or |print (address)| to
print from an address outside the memory map of the game file, or an address
at which no string is present (this will result in random text appearing,
possibly including unprintable characters, which might crash the
terminal);^^|print (string)|^^|print (address)|
\item{$\bullet$} Running out of stack space in a recursive loop.
\smallskip
\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.
More usefully you can declare a routine with an asterisk ^|*| as its first
local variable, which produces such tracing only for that one routine.
For example,
\beginstt
[ ParseNoun * obj n m;
\endtt
results in the game printing out lines like
\beginstt
[ParseName, obj=26, n=0, m=0]
\endtt
every time the routine is called.^^{tracing a routine}^^{routines: tracing calls to}
\refs A simple debugging verb called ``xdeterm'' is defined in the
|DEBUG| version of ^{`Advent'}, to make the game deterministic (i.e.,
not dependant on what the random number generator produces).
\newpage
\section{31}{Limitations on the run-time format}
\poem
How wide the limits stand
Between a splendid and an happy land.
\poemby{^{Oliver Goldsmith} ({\oldstyle1728}--{\oldstyle1774})}{The Deserted Village}
^^{limitations}\noindent
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 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.
Games can be compiled to several ``versions'' of the run-time format.
Unless told otherwise Inform compiled to what used to be called
^{Advanced games} (version 5). It can still compile ^{Standard games}
(version 3) but doing so imposes genuine restrictions, and there is little
point any more. Stepping up to the new version 8, on the other hand,
allows much larger games to be compiled. Other versions exist but
are not useful to present-day game designers, so the real decision
is V5 versus V8.
\medskip
\noindent
{\it Memory.}\quad This is the only serious restriction. The maximum size
of a game (in K) is given by:
$$ \matrix{ {\bf V3} & {\rm V}4 & {\bf V5} & {\rm V}6 & {\rm V}7 & {\bf V8}\cr
128 & 256 & 256 & 512 & 320 & 512\cr} $$
Because games are encoded in a very compressed form, and because the
centralised library of Inform is 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. The default format (V5) will hold a game as large
and complex as the final edition of `Curses', substantially bigger than any
Infocom game, with room to spare. V6, the late Infocom graphical format,
should be avoided for text games, as it is much more difficult to
interpret. The V8 format allows quite gargantuan games (one could implement,
say, a merging of the `Zork' and `Enchanter' trilogies in it) and is
recommended as the standard size for games too big to fit in V5.%
^^{memory: maximum size of game}^^{versions of the Z-machine}
\medskip
\noindent
{\it Grammar.}\quad The number of verbs is limited only by memory.
Each can have up to 20 grammar lines (one can recompile Inform with
|MAX_LINES_PER_VERB| defined to a higher setting to increase this)
and a line contains at most 6 tokens. (Using general parsing routines
will prevent either restriction from biting.)^^{grammar: limits on}
\medskip
\noindent
{\it Vocabulary.}\quad There is no theoretical limit. Typical games have
vocabularies of between 1000 and 2000 words, but doubling that would
pose no problem.^^{vocabulary size (limit)}^^{dictionary: maximum size of}
\medskip
\noindent
{\it Dictionary resolution.}\quad Dictionary words are truncated to their
first 9 letters (except that non-alphabetic characters, such as hyphens,
count as 2 ``letters'' for this purpose). They must begin with an
alphabetic character and upper and lower case letters are considered equal.
(In V3, the truncation is to 6
letters.)^^{dictionary: resolution and case sensitivity}
^^{case sensitivity of dictionary}^^{resolution}
\medskip
\noindent
{\it Attributes, properties, names.}\quad 48 attributes and 63 common properties
are available, and each property can hold 64 bytes of data. Hence, for
example, an object can have up to 32 names. These restrictions are harmless
in practice: except in V3, where the numbers in question are 32, 31, 8
and 4, which begins to bite. Note that the number of different individual
properties is unlimited.^^{attributes: maximum number of}
^^{properties: maximum number of common}
^^{names per object (limit)}
^^{objects: maximum number of names for}
\medskip
\noindent
{\it Special effects.}\quad V3 games cannot have special effects such
as bold face and underlining. (See the next two sections.)
\medskip
\noindent
{\it Objects.}\quad Limited only by memory: except in V3, where the limit
is 255.^^{objects: maximum number of}
\medskip
\noindent
{\it Memory management.}\quad The Z-machine does not allow dynamic allocation
or freeing of memory: one must statically define an array to a suitable maximum
size and live within it. This restriction greatly
increases the portability of the format, and the designer's confidence that
the game's behaviour is genuinely independent of the machine it's running on:
memory allocation at run-time is a fraught process
on many machines.^^{dynamic memory allocation}
^^{memory: dynamic allocation}
\medskip
\noindent
{\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 felt. An
unlimited number of |Array| statements is permitted and array entries do
not, of course, count towards the 240.^^{global variables: maximum number of}
\medskip
\noindent
{\it ``Undo''.}\quad No ^{``undo'' verb} is available in V3.
\medskip
\noindent
{\it Function calls.}\quad A function can be called with at most 7
arguments. (Or, in V3 and V4, at most
3.)^^{function arguments: maximum number of}
\medskip
\noindent
{\it Recursion and stack usage.}\quad The limit on this is rather
technical (see the {\sl Z-Machine Standards Document}). Roughly speaking,
recursion is permitted to a depth of 90 routines in almost all circumstances
(and often much deeper). Direct usage of the stack via assembly language
must be modest.^^{recursion (limit)}^^{stack usage (limit)}
^^{routines: maximum depth of recursion}
\bigskip
\danger 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} and then run the
compiler in its ``economy'' mode (using the switch |-e|). 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. When choosing abbreviations, avoid proper nouns and
instead pick on short combinations of a space and common two- or
three-letter blocks. Good choices include |" the "|, |"The"|, |", "|,
|"and"|, |"you"|, |" a "|, |"ing"|, |" to"|.
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.
\newpage
\section{32}{Boxes, menus and drawings}
\quote
Yes, all right, I won't do the menu$\ldots$ 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}}
\bigskip\noindent
One harmless effect, though not very special, is to ask the player
a yes/no question. To do this, print up the question and then
call the library routine ^|YesOrNo|, which returns true/false
accordingly.^^{questions, asking yes or no}\
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
has been written in the program, in which case the game's 24-hour clock is
displayed.
\danger If you want to change this, just |Replace| the parser's
private ^|DrawStatusLine| routine. This requires a little assembly
language: see the next section for numerous examples.
\noindent
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,
the spacing may then be wrong. The statement |font off| ensures that any
fancy font is switched off and that a fixed-pitch one is being used: after
this, |font on| restores the usual state.^^|font|^^{fixed-pitch font}
\warning Don't turn the |font| on and off in the middle of a line; this
doesn't look right on some machines.
\danger When trying to produce a character-graphics drawing, you sometimes
want to produce the |\| character, one of the four ``^{escape characters}''
which can't normally be included in text. A double |@| sign followed by
a number includes the character with that ASCII code; thus:
\begindisplay
|@@64| produces the literal character |@|\cr
|@@92| produces |\|\qquad |@@94| produces |^|
\qquad |@@126| produces |~|\cr
\enddisplay^^|@@|^^{at character}^^{literal characters}
^^{backslash character}^^|@|
\ddanger Some interpreters are capable of much better character graphics
(those equipped to run the Infocom game ^{`Beyond Zork'}, for instance).
There is a way to find out if this feature is provided and to make
use of it: see the {\sl Z-Machine Standards Document}.
\ddanger A single |@| sign is also an escape character. It must be
followed by a 2-digit decimal number between 0 and 31 (for instance,
|@05|). What this prints is the $n$-th `variable string'. This feature
is not as useful as it looks, since the only legal values for such
a variable string are strings declared in advance by a |LowString|
directive. The |String| statement then sets the $n$-th variable
string. For details and an example, see the answer to the east-west
reversal exercise in \S 10.
\medskip\noindent
A distinctive feature of later Infocom games was their use of ^{epigrams}.
The assembly language required to produce this effect is easy but a
nuisance, so there is an Inform statement to do it, ^|box|. For example,
\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 list of one or more 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. Inform
will automatically insert the boxed text into the ^{game transcript},
if one is being made.^^{transcript}\
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"}). 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}.
A snag with printing boxes is that if you do it in the middle of a turn
then it will probably scroll half-off the screen by the time the game
finishes printing for the turn. The right time to do so is just after
the prompt (usually |>|) is printed, when the screen will definitely
scroll no more. You could use the |Prompt:| slot in |LibraryMessages|
to achieve this, but a more convenient way is to put your box-printing
into the entry point ^|AfterPrompt| (called at this time each
turn).^^{scrolling screen}^^{prompt}
\exercise Implement a routine |Quote(n)| which will arrange for the
$n$-th quotation (where $0\leq n\leq 49$) to be displayed at the end
of this turn, provided it hasn't been quoted
before.^^{exercises: quotations in boxes}
\answer{^^{exercises: quotations in boxes}
\beginlines
|Array quote_done -> 50;|
|Global next_quote = -1;|
|[ Quote i;|
| if (quote_done->i==0) { quote_done->i = 1; next_quote = i; }|
|];|
|[ AfterPrompt;|
| switch(next_quote)|
| { 0: box "His stride is wildernesses of freedom:"|
| "The world rolls under the long thrust of his heel."|
| "Over the cage floor the horizons come."|
| ""|
| "-- Ted Hughes, ~The Jaguar~";|
| 1: ...|
| }|
| next_quote = -1;|
|];|
\endlines^^{Ted Hughes}}
\medskip
\noindent
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. By setting |pretty_flag=0| you
can make a simple text version instead; a good idea for machines
with very small screens.^^|pretty flag|\
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^",
HelpMenu, HelpInfo);
\endtt
Note the layout, and especially the carriage returns. The second and
third arguments are themselves routines. (Actually the first argument
can also be a routine to print a string instead of the string itself,
which might be useful for ^{adaptive hints}.) The |HelpMenu| routine
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).
In the case of item 0, the title should be that for the whole
menu.^^|menu item|^^|item name|^^|item width|\
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, and if the value 3 is returned
it automatically quits the menu as if Q had been pressed. This is useful
for juggling submenus about.
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.^^{exercises: Invisiclues hints}
\answer{^^{exercises: Invisiclues hints}
Note the magic line of assembly code here, which only works for
Advanced games:
\beginlines^^{``Invisiclues''}
|[ GiveHint hint keypress;|
| print (string) 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\noindent
Finally, you can change the ^{text style}. The statement 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, poor terminals may not be able to display these,
so you shouldn't hide crucial information in them.^^{boldface}^^{roman
text}^^{reverse video}^^{underlining}
\refs ^{`Advent'} contains a menu much like that above.
\nextref
The ^{``Infoclues''} utility program translates ^{UHS format hints}
(a standard, easy to read and write layout) into an Inform file of calls to
|DoMenu| which can simply be included into a game; this saves a good deal of
trouble.
\section{33}{Descending into assembly language}
\dddanger Some ^{dirty tricks} require bypassing all of Inform's higher levels
to program the Z-machine directly with ^{assembly language}. There is an
element of danger in this, in that some combinations of unusual opcodes
might look ugly on some incomplete or wrongly-written ^{interpreters}:
so if you're doing anything complicated, test it as widely as possible.
\bigskip\ninepoint\noindent
The best-researched and most reliable interpreters available by far are Mark
Howell's ^{Zip} and Stefan Jokisch's ^{Frotz}: they are also faster than their
only serious rival, the ^{InfoTaskForce}, a historically important work which
is fairly thorough (and should give little trouble in practice) but which was
written when the format was a little less well understood. In some ports,
ITF gets rarer screen effects wrong, and it lacks an ``undo'' feature, so the
Inform ^{``undo'' verb} 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'.)
Interpreters conforming to the Z-Machine Standard, usually but not always
derived from ^{Frotz} or ^{Zip}, are reliable and widely available.
But remember that one source of unportability is inevitable.
Your game may be running on a screen which is anything from a
64 characters by 9 pocket organiser LCD display, up to a 132 by 48 window
on a 21-inch monitor.
Anyone wanting to really push the outer limits (say, by implementing
^{Space Invaders} or ^{NetHack}) will need to refer to {\sl The Z-Machine
Standards Document}. This is much more detailed (the
definition of |aread| alone runs for two pages) and covers the whole range
of assembly language. However, this section does document all those features
which can't be better obtained with higher-level code.
\bigskip
\noindent
Lines of assembly language must begin with an |@| character and then the
name of the ``opcode'' (i.e., assembly language statement). A number of
arguments, or ``operands'' follow (how many depends on the opcode): these
may be any Inform constants, local or global variables or the stack pointer |sp|,
but may not be compound expressions. |sp| does not behave like a variable:
writing a value to it pushes that value onto the stack, whereas reading
the value of it (for instance, by giving it as an operand) pulls the top
value off the stack. Don't use |sp| unless you have to. After the operands,
some opcodes require a variable (or |sp|) to write a result into.
The opcodes documented in this section are as follows:
\beginlines
|@split_window lines|
|@set_window window|
|@set_cursor line column|
|@buffer_mode flag|
|@erase_window window|
|@set_colour foreground background|
|@aread text parse time function <result>|
|@read_char 1 time function <result>|
|@tokenise text parse dictionary|
|@encode_text ascii-text length from coded-text|
|@output_stream number table|
|@input_stream number|
|@catch <result>|
|@throw value stack-frame|
|@save buffer length filename <result>|
|@restore buffer length filename <result>|
\endlines
\vfill\eject
\beginlines
|@split_window lines|
\endlines^^|@split window|
Splits off an ^{upper-level window} of the given number of lines
in height from the main screen. This upper window usually holds the
status line and can be resized at any time: nothing visible happens
until the window is printed to. Warning: make the upper window
tall enough to include all the lines you want to write to it, as it
should not be allowed to scroll.
\beginlines
|@set_window window|
\endlines^^|@set window|
The text part of the screen (the lower window) is ``^{window 0}'',
the status line (the upper one) is window 1; this opcode selects
which one text is to be printed into. Each window has a ``cursor
position'' at which text is being printed, though it can only
be set for the upper window. Printing on the upper window
overlies printing on the lower, is always done in a fixed-pitch font
and does not appear in a printed ^{transcript} of the game.
Note that before printing to the upper window, it is wise
to use |@buffer_mode| to turn off word-breaking.
\beginlines
|@set_cursor line column|
\endlines^^|@set cursor|^^{text cursor}
Places the cursor inside the upper window,
where $(1,1)$ is the top left character.
\beginlines
|@buffer_mode flag|
\endlines^^|@buffer mode|^^{word breaking}
^^{formatted text}^^{text formatting}
This turns on (|flag=1|) or off (|flag=0|) word-breaking for the
current window (that is, the practice of printing new-lines only
at the ends of words, so that text is neatly formatted). It is
wise to turn off word-breaking while printing to the upper window.
\beginlines
|@erase_window window|
\endlines^^|@erase window|^^{clearing the screen}
This opcode is unfortunately incorrectly implemented
on some interpreters and so it can't safely be used to erase
individual windows. However, it can be used with |window=-1|,
and then clears the entire screen. Don't do this in
reverse video mode, as a bad interpreter may (incorrectly) wipe the
entire screen in reversed colours.
\beginlines
|@set_colour foreground background|
\endlines^^|@set colour|^^{colours}^^{foreground
colour}^^{background colour}
If coloured text is available, set text to be
foreground-against-background. The colour numbers are borrowed
from the IBM PC:
\beginlines
|2 = black, 3 = red, 4 = green, 5 = yellow,|
|6 = blue, 7 = magenta, 8 = cyan, 9 = white|
|0 = the current setting, 1 = the default.|
\endlines^^{IBM PC, ugliness of}
On many machines coloured text is not available: the opcode will
then do nothing.
\beginlines
|@aread text parse time function <result>|
\endlines^^|@aread|
The ^{keyboard} can be read in remarkably flexible ways. This opcode
reads a line of text from the keyboard, writing it into the |text|
string array and `^{tokenising}' it into a word stream, with
details stored in the |parse| string array (unless this is zero,
in which case no tokenisation happens). (See the end of \S 27 for
the format of |text| and |parse|.)
While it is doing this, it calls |function(time)|
every |time| tenths of a second while the user is thinking:
the process ends if ever this function returns true.
|<result>| is to be a variable, but the value
written in it is only meaningful if you're using a ``terminating
characters table''. 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}\
Warning: not every interpreter supports this real-time feature, and
most of those that do count in seconds instead of tenths of seconds.
\vfill\eject\noindent
\beginlines
|@read_char 1 time function <result>|
\endlines^^|@read char|
results in the ASCII value of a single keypress. Once again, the |function| is
called every |time| tenths of a second 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}\
The first operand must be 1 (used by Infocom as a device number to identify
the keyboard).
\beginlines
|@tokenise text parse dictionary|
\endlines^^|@tokenise|
This takes the text in the |text| buffer (in the format produced by |aread|)
and tokenises it (i.e. breaks it up into words, finds their addresses in the
dictionary) into the |parse| buffer in the usual way but using the given
|dictionary| instead of the game's usual one. (See the {\sl Z-Machine Standards
Document} for the dictionary format.)^^{dictionary: tokenisation using}
\beginlines
|@encode_text ascii-text length from coded-text|
\endlines^^|@encode text|^^{internal text format}^^{Z-encoded text}
Translates an ASCII word to the internal (Z-encoded) text format
suitable for use in a |@tokenise| dictionary. The text begins at
|from| in the |ascii-text| and is |length| characters long, which
should contain the right length value (though in fact the interpreter
translates the word as far as a 0 terminator). The result is 6 bytes
long and usually represents between 1 and 9 letters.
\beginlines
|@output_stream number table|
\endlines^^|@output stream|^^{streams of input/output}
Text can be output to a variety of different `streams',
possibly simultaneously. If |number| is 0 this does nothing.
$+n$ switches stream $n$ on, $-n$ switches it off.
The output streams are: 1 (the screen),
2 (the game ^{transcript}), 3 (memory) and 4 (^{script of
player's commands}). The |table| can be omitted except for stream
3, when it's a |table| array holding the text printed; printing
to this stream is never word-broken, whatever the state of
|@buffer_mode|.
\beginlines
|@input_stream number|
\endlines^^|@input stream|
Switches the `input stream' (the source of the player's commands).
0 is the keyboard, and 1 a command file (the idea is that a list of
commands produced by |output_stream 4| can be fed back in again).
\beginlines
|@catch <result>|
\endlines^^|@catch|
The opposite of |throw|, |catch| preserves the ``stack frame'' of the
current routine: meaning, roughly, the current position of which routine
is being run and which ones have called it so far.
\beginlines
|@throw value stack-frame|
\endlines^^|@throw|^^{stack frame}^^{long jump}
This causes the program to execute a return with |value|,
but as if it were returning from the routine which was running
when the |stack-frame| was caught (see |catch|). Any routines
which were called in the mean time and haven't returned yet
(because each one called the next) are forgotten about.
This is useful to get the program out of large recursive tangles
in a hurry.
\beginlines
|@save buffer length filename <result>|
\endlines^^|@save|^^{saving data}
Saves the byte array |buffer| (of size |length|) to a file,
whose (default) name is given in the |filename| (a |string|
array). Afterwards, |result| holds 1 on success, 0 on failure.
\vfill\eject\noindent
\beginlines
|@restore buffer length filename <result>|
\endlines^^|@restore|^^{restoring data}
Loads in the byte array |buffer| (of size |length|) from a file,
whose (default) name is given in the |filename| (a |string|
array). Afterwards, |result| holds the number of bytes successfully
read.
\warning
Some of these features may not work well on ^{obsolete interpreters}
which do not adhere to the Z-Machine Standard. Standard
interpreters are widely available, but if seriously worried
you can test whether your game is running on a good interpreter:
\beginstt
if (standard_interpreter == 0)
{ print "This game must be played on an interpreter obeying the
Z-Machine Standard.^";
@quit;
}
\endtt^^{Z-machine standard: testing}^^{Standard interpreters}
\exercise In a role-playing game campaign, you might want several
scenarios, each implemented as a separate Inform game. How could
the character from one be saved and loaded into another?^^{saving the character}
^^{role-playing games}^^{campaigns and scenarios}
^^{exercises: saving the character}
\answer{^^{saving the character}^^{role-playing games}
^^{campaigns and scenarios}^^{exercises: saving the character}
By encoding the character into a byte array and using |@save|
and |@restore|. The numbers in this array might contain the character's
name, rank and abilities, together with some coding system to show what
possessions the character has (a brass lamp, 50 feet of rope, etc.)}
\dangerexercise Design a ^{title page} for ^{`Ruins'}, displaying
a more or less apposite quotation and waiting for a key to be
pressed.^^{exercises: title page}
\answer{^^{title page}^^{`Ruins'}^^{exercises: title page}
Note that we wait for a space character
(32) or either kind of new-line which typical ASCII keyboards produce
(10 or 13), just to be on the safe side:
\beginlines
|[ TitlePage i;|
| @erase_window -1; print "^^^^^^^^^^^^^";|
| i = 0->33; if (i==0) i=80; i=(i-50)/2;|
| style bold; font off; spaces(i);|
| print " RUINS^";|
| style roman; print "^^"; spaces(i);|
| print " [Please press SPACE to begin.]^";|
| font on;|
| box "And make your chronicle as rich with praise"|
| "As is the ooze and bottom of the sea"|
| "With sunken wreck and sumless treasures."|
| ""|
| "-- William Shakespeare, ~Henry V~ I. ii. 163";|
| do { @read_char 1 0 0 i; } until (i==32 or 10 or 13);|
| @erase_window -1;|
|];|
\endlines^^{William Shakespeare}}
\dangerexercise Change the status line so that it has the usual
score/moves appearance except when a variable |invisible_status|
is set, when it's invisible.^^{invisible status line}
^^{exercises: status line invisible}
\answer{^^{invisible status line}^^{exercises: status line invisible}
First put the directive
|Replace DrawStatusLine;| before including the library; define
the global variable |invisible_status| somewhere. Then give
the following redefinition:
\beginlines
|[ DrawStatusLine i width posa posb;|
| if (invisible_status==1) return;|
| @split_window 1; @set_window 1; @set_cursor 1 1; style reverse;|
| width = 0->33; posa = width-26; posb = width-13;|
| spaces (width-1);|
| @set_cursor 1 2; PrintShortName(location);|
| if (width > 76)|
| { @set_cursor 1 posa; print "Score: ", sline1;|
| @set_cursor 1 posb; print "Moves: ", sline2;|
| }|
| if (width > 63 && width <= 76)|
| { @set_cursor 1 posb; print sline1, "/", sline2;|
| }|
| @set_cursor 1 1; style roman; @set_window 0;|
|];|
\endlines}
\dangerexercise Alter the ^{`Advent'} example game to display the number
of treasures found instead of the score and turns on the status
line.^^{treasures on status line}^^{exercises: status line showing treasure}
\answer{^^{exercises: status line showing treasure}
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^^|DrawStatusLine|^^{treasures on status line}^^{status line}}
\dangerexercise (From code by ^{Joachim Baumann}.) Put a ^{compass rose}
on the status line, displaying the directions in which the room can be
left.^^{exercises: status line with compass rose}
\answer{^^{compass rose}^^{exercises: status line with compass rose}
|Replace| with the following. (Note the use of
|@@92| as a string escape, to include a literal backslash character,
and |@@124| for a vertical line.)
\beginlines
|Constant U_POS 28; Constant W_POS 30; Constant C_POS 31;|
|Constant E_POS 32; Constant IN_POS 34;|
|[ DrawStatusLine i;|
| @split_window 3; @set_window 1; style reverse; font off;|
| @set_cursor 1 1; spaces (0->33)-1;|
| @set_cursor 2 1; spaces (0->33)-1;|
| @set_cursor 3 1; spaces (0->33)-1;|
| @set_cursor 1 2; print (name) location;|
| @set_cursor 1 51; print "Score: ", sline1;|
| @set_cursor 1 64; print "Moves: ", sline2;|
| if (location ~= thedark)|
| { ! First line|
| if (location.u_to ~= 0) { @set_cursor 1 U_POS; print "U"; }|
| if (location.nw_to ~= 0) { @set_cursor 1 W_POS; print "@@92"; }|
| if (location.n_to ~= 0) { @set_cursor 1 C_POS; print "@@124"; }|
| if (location.ne_to ~= 0) { @set_cursor 1 E_POS; print "/"; }|
| if (location.in_to ~= 0) { @set_cursor 1 IN_POS; print "I"; }|
| ! Second line|
| if (location.w_to ~= 0) { @set_cursor 2 W_POS; print "-"; }|
| @set_cursor 2 C_POS; print "o";|
| if (location.e_to ~= 0) { @set_cursor 2 E_POS; print "-"; }|
| ! Third line|
| if (location.d_to ~= 0) { @set_cursor 3 U_POS; print "D"; }|
| if (location.sw_to ~= 0) { @set_cursor 3 W_POS; print "/"; }|
| if (location.s_to ~= 0) { @set_cursor 3 C_POS; print "@@124"; }|
| if (location.se_to ~= 0) { @set_cursor 3 E_POS; print "@@92"; }|
| if (location.out_to ~= 0){ @set_cursor 3 IN_POS; print "O"; }|
| }|
| @set_cursor 1 1; style roman; @set_window 0; font on;|
|];|
\endlines}
\ddangerexercise (Cf.\ ^{`Trinity'}.)
Make the status line consist only of the name of the current
location, centred in the top line of the
screen.^^{centred status line}^^{exercises: status line with centred room}
\answer{^^{centred status line}
^^{exercises: status line with centred room}
The tricky part is working out the
number of characters in the location name, and this is where
|@output_stream| is so useful. This time |Replace| with:
\beginlines
|Array printed_text table 64;|
|[ DrawStatusLine i j;|
| i = 0->33; if (i==0) i=80;|
| font off;|
| @split_window 1; @buffer_mode 0; @set_window 1;|
| style reverse; @set_cursor 1 1; spaces(i);|
| printed_text-->0 = 64;|
| @output_stream 3 printed_text;|
| print (name) location;|
| @output_stream -3;|
| j=(i-(printed_text-->0))/2;|
| @set_cursor 1 j; print (name) location; spaces(j-1);|
| style roman;|
| @buffer_mode 1; @set_window 0; font on;|
|];|
\endlines
Note that the table can hold 128 characters (plenty for this purpose),
and that these are stored in |printed_text->2| to |printed_text->129|;
the length printed is held in |printed_text-->0|.
(^{`Trinity'} actually does this more crudely, storing away
the width of each location name.)}
\ddangerexercise Implement an Inform version of the standard `C'
routine |printf|, taking the form
\beginstt
printf(format, arg1, ...)
\endtt^^{exercises: printf routine}
to print out the format string but with escape sequences like
|%d| replaced by the arguments (printed in various ways). For
example,
\beginstt
printf("The score is %e out of %e.", score, MAX_SCORE);
\endtt^^{printf exercise}
should print something like ``The score is five out of ten.''
\answer{^^{printf exercise}^^{exercises: printf routine}
The following implementation is limited to a format
string $2\times 64 = 128$ characters long, and six subsequent arguments.
|%d| becomes a decimal number, |%e| an English one; |%c|
a character, |%%| a (single) percentage sign and |%s|
a string.
\beginlines
|Array printed_text table 64;|
|Array printf_vals --> 6;|
|[ Printf format p1 p2 p3 p4 p5 p6 pc j k;|
| printf_vals-->0 = p1; printf_vals-->1 = p2; printf_vals-->2 = p3;|
| printf_vals-->3 = p4; printf_vals-->4 = p5; printf_vals-->5 = p6;|
| printed_text-->0 = 64; @output_stream 3 printed_text;|
| print (string) format; @output_stream -3;|
| j=printed_text-->0;|
| for (k=2:k<j+2:k++)|
| { if (printed_text->k == '%')|
| { switch(printed_text->(++k))|
| { '%': print "%";|
| 'c': print (char) printf_vals-->pc++;|
| 'd': print printf_vals-->pc++;|
| 'e': print (number) printf_vals-->pc++;|
| 's': print (string) printf_vals-->pc++;|
| default: print "<** Unknown printf escape **>";|
| }|
| }|
| else print (char) printed_text->k;|
| }|
|];|
\endlines}
\refs The assembly-language connoisseur will appreciate ^{`Freefall'}
by ^{Andrew Plotkin} and ^{`Robots'} by ^{Torbj\o rn Andersson},
although the present lack of on-line hints make these difficult games
to win.
\chapter{Appendix: Tables and summaries}
\stepin=60pt
\ninepoint
\section{A1}{Inform operators}^^{operators: full table of}%
In the table, ``Level'' refers to precedence level: thus |*|, on level 6,
has precedence over |+|, down on level 5, but both subordinate to unary |-|,
up on level 8. The ``^{associativity}'' of an operator is the way it
brackets up if the formula doesn't specify this: for instance, |-| is left
associative because
\beginstt
a - b - c
\endtt
is understood as
\beginstt
(a - b) - c
\endtt^^{left/right associativity}
with brackets going on the left. With some Inform operators, you're not
allowed to be vague like this; these are the ones whose associative is
listed as ``none''. Thus
\beginstt
a == b == c
\endtt
will produce an error insisting that brackets be written into the program
to make clear what the meaning is. Given the table (and sufficient patience)
all expressions can be broken down into order: for instance
\beginstt
a * b .& c --> d / - f
\endtt
is calculated as
\beginstt
( a*((b.&c)-->d) ) / (-f)
\endtt
\newpage
$$ \vbox{\offinterlineskip
\hrule
\halign{&\vrule#&\strut\quad\hfil#\hfil\quad\cr
height2pt&\omit&&\omit&&\omit&&\omit&&\omit&\cr
& Level && Operator && Usage && Assoc. && Purpose &\cr
height2pt&\omit&&\omit&&\omit&&\omit&&\omit&\cr
\noalign{\hrule}
height2pt&\omit&&\omit&&\omit&&\omit&&\omit&\cr
& 0 && |,| && binary && left && separating values to work out &\cr
& 1 && |=| && binary && right && set equal to&\cr
& 2 && |&&| && binary && left && logical AND&\cr
& 2 &&\BAR\BAR&& binary && left && logical OR&\cr
& 2 && |~~| && unary && (pre) && logical NOT&\cr
& 3 && |==| && binary && none && equal to?&\cr
& 3 && |~=| && binary && none && not equal to?&\cr
& 3 && |>| && binary && none && greater than?&\cr
& 3 && |>=| && binary && none && greater than or equal to?&\cr
& 3 && |<| && binary && none && less than?&\cr
& 3 && |<=| && binary && none && less than or equal to?&\cr
& 3 && |has| && binary && none && object has this attribute?&\cr
& 3 && |hasnt| && binary && none && object hasn't this attribute?&\cr
& 3 && |in| && binary && none && first obj a child of second?&\cr
& 3 && |notin| && binary && none && first obj not a child of second?&\cr
& 3 && |ofclass| && binary && none && obj inherits from class?&\cr
& 3 && |provides| && binary && none && obj provides this property?&\cr
& 4 && |or| && binary && left && separating alternative values&\cr
& 5 && |+| && binary && left && 16-bit signed addition&\cr
& 5 && |-| && binary && left && 16-bit signed subtraction&\cr
& 6 && |*| && binary && left && 16-bit signed multiplication&\cr
& 6 && |/| && binary && left && 16-bit signed integer division&\cr
& 6 && |%| && binary && left && 16-bit signed remainder&\cr
& 6 && |&| && binary && left && bitwise AND&\cr
& 6 && \BAR && binary && left && bitwise OR&\cr
& 6 && |~| && unary && (pre) && bitwise NOT&\cr
& 7 && |->| && binary && left && byte array entry&\cr
& 7 && |-->| && binary && left && word array entry&\cr
& 8 && |-| && unary && (pre) && 16-bit (signed!) negation&\cr
& 9 && |++| && unary && (pre/post) && incrementd&\cr
& 9 && |--| && unary && (pre/post) && decrement&\cr
&10 && |.&| && binary && left && property address&\cr
&10 && |.#| && binary && left && property length&\cr
&11 && |(...)| && binary && left && function call on right hand side&\cr
&12 && |.| && binary && left && property value&\cr
&13 && |::| && binary && left && ``superclass'' operator&\cr
&14 && |(...)| && binary && left && function call on left hand side&\cr
height2pt&\omit&&\omit&&\omit&&\omit&&\omit&\cr}\hrule}$$
\newpage
\section{A2}{Inform statements}^^{statements: summary table of}%
\begindisplay
|box| \<line-1> \<line-2> ... \<line-n>\cr
|break|\cr
|continue|\cr
|do| \<code block> |until| \<condition>\cr
|font| |on| {\it or} |off|\cr
|for (|\<initial code>|:|\<condition to carry on>|:|\<update code>|)| \<code block>\cr
|give| \<object> \<attribute-1> ... \<attribute-n>\cr
|if| \<condition> \<code block>\cr
|if| \<condition> \<code block> |else| \<code-block>\cr
|inversion|\cr
|jump| \<label>\cr
|move| \<object> |to| \<destination>\cr
|new_line|\cr
|objectloop| \<condition choosing objects> \<code block>\cr
|print| \<list of printing specifications>\cr
|print_ret| \<list of printing specifications>\cr
|quit|\cr
|read| \<text-buffer> \<parsing-buffer>\cr
|remove| \<object>\cr
|restore| \<label>\cr
|return| \<optional value>\cr
|rfalse|\cr
|rtrue|\cr
|save| \<label>\cr
|spaces| \<number of spaces to print>\cr
|string| \<number> \<text>\cr
|style| |roman| {\it or} |bold| {\it or} |underline| {\it or} |reverse| {\it or} |fixed|\cr
|switch (|\<value>|)| \<block of cases>\cr
|while| \<condition> \<code-block>\cr
\enddisplay
\noindent Statements must be given in lower case. Code blocks consist of
either a single statement or a group of statements enclosed in braces
|{| and |}|. Print specifications are given as a list of one or more
items, separated by commas:
\begindisplay
|"|\<some literal text to print>|"|\cr
\<numerical quantity>\cr
|(char)| \<a character code>\cr
|(string)| \<a string address>\cr
|(address)| \<text held at this byte address>\cr
|(name)| \<object>\cr
|(a)| \<object>\cr
|(an)| \<object>\cr
|(the)| \<object>\cr
|(The)| \<object>\cr
|(property)| \<name of a property>\cr
|(object)| \<internal ``hardware'' object short name>\cr
\enddisplay\newpage
\section{A3}{Inform directives}^^{directives: summary table of}%
\begindisplay
|Abbreviate| \<word-1> ... \<word-n>\cr
|Array| \<new-name> \<type> \<initial values>\cr
|Attribute| \<new-name>\cr
|Class| \<new-name> \<body of definition>\cr
|Constant| \<new-name> |=| \<value>\cr
|Default| \<possibly-new-name>\cr
|End|\cr
|Endif|\cr
|Extend| \<grammar extension>\cr
|Global| \<new-name> |=| \<value>\cr
|Ifdef| \<symbol-name>\cr
|Ifndef| \<symbol-name>\cr
|Ifnot|\cr
|Iftrue| \<condition>\cr
|Iffalse| \<condition>\cr
|Import| \<list of imported goods>\cr
|Include| \<source code filename>\cr
|Link| \<module filename>\cr
|Lowstring| \<text>\cr
|Message| \<message-type> \<diagnostic-message>\cr
|Object| \<header> \<body of definition>\cr
|Property| \<new-name>\cr
|Release| \<number>\cr
|Replace| \<routine-name>\cr
|Serial| |"|\<serial number>|"|\cr
|Switches| \<list of switches>\cr
|Statusline| |score| {\it or} |time|\cr
|System_file|\cr
|Verb| \<verb-definition>\cr
\enddisplay
\medskip\noindent%
|Nearby|, much used in Inform 5 code, is still allowed but
in modern code the notation |Object ->| is preferable. A few
other directives, |Dictionary|, |Fake_action|, |Ifv3|,
|Ifv5|, |Stub|, |Trace| and |Version|, are obsolete or
for compiler maintenance.\newpage
\section{A4}{Grammar}^^{grammar: summary of rules about}^^{summary of grammar}
A `verb' is a set of possible initial words in keyboard command, which are
treated synonymously (for example, ``wear'' and ``don'') together with
a `grammar'. A grammar is a list of `lines' which the parser tries to match,
one at a time, and accepts the first one which matches. The directive
\begindisplay
Verb [|meta|] \<verb-word-1> $\ldots$ \<verb-word-$n$> \<grammar>
\enddisplay
creates a new verb. If it is said to be |meta| then it will count as `out
of the game': for instance ``score'' or ``save''. New synonyms can be added
to an old verb with:
\begindisplay
Verb \<new-word-1> $\ldots$ \<new-word-$n$> |=| \<existing-verb-word>
\enddisplay
An old verb can be modified with the directive
\begindisplay
Extend [|only|] \<existing-word-1> $\ldots$ \<existing-word-$n$> [\<priority>] \<grammar>
\enddisplay
If |only| is specified, the existing words given (which must all be from the same
existing verb) are split off into a new independent copy of the verb.
If not, the directive extends the whole existing verb.
The priority can be |first| (insert
this grammar at the head of the list), |last| (insert it at the end) or |replace|
(throw away the old list and use this instead); the default is |last|.
A line is a list of `tokens' together with the action generated if each
token matches so that the line is accepted. The syntax of a line is
\begindisplay
|*| \<token-1> \<token-2> $\ldots$\<token-$n$> |->| \<action>
\enddisplay
where $0\leq n\leq 31$. The action is named without initial |##| signs and if
an action which isn't in the standard library set is named then an action
routine (named with the action name followed by |Sub|) must be defined
somewhere in the game.
A grammar line can optionally be followed by the word
^|reverse|. This signals that the action to be generated has
two parameters, but which have been parsed in the wrong
order and need to swapped over. (Note that a |topic| is
not a parameter, and nor is a preposition.)
\medskip
\noindent%
A token matches a single particle of what has been typed. The possible
tokens are:
{\smallskip
%$-1
\baselineskip=7 true mm
\settabs 8\columns
\+& \rstok{|"|\<word>|"|} && that literal word only\cr
\+& \cstok{noun} && any object in scope\cr
\+& \cstok{held} && object held by the player\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
\+& \rstok{\<attribute>} && any object in scope which has the attribute\cr
\+& \cstok{creature} && an object in scope which is |animate|\cr
\+& \rstok{|noun = |\<Routine>} && any object in scope passing the given test\cr
\+& \rstok{|scope = |\<Routine>} && an object in this definition of scope\cr
\+& \cstok{number} && a number only\cr
\+& \rstok{\<Routine>} && refer to this general parsing routine\cr
\+& \cstok{topic} && any text at all\cr
\+& \cstok{special} && any single word or number\cr
\smallskip}
\par\noindent%
Two or more literal words (only) can be written with slash
signs |/| between them as alternatives. E.g., |"in"/"on"|
matches either the word ``in'' or the word ``on''.
For the \rstok{|noun = |\<Routine>} token,
the test routine must decide whether or not the
object in the |noun| variable is acceptable and return true or false.
For the \rstok{|scope = |\<Routine>} token,
the routine must look at the variable |scope_stage|.
If this is 1, then it must decide whether or not to allow a multiple object
(such as ``all'') here and return true or false. If 2, then the routine may
put objects into scope by calling either |PlaceInScope(obj)| to put just |obj|
in, or |ScopeWithin(obj)| to put the contents of |obj| into scope. It must
then return either true (to prevent any other objects from entering scope) or
false (to let the parser put in all the usual objects). If |scope_stage=3|,
it must print a suitable message to tell the player that this token was
misunderstood.
A general parsing routine can match any text it likes. It should use |wn|,
the variable holding the number of the word currently being parsed (counting
from the verb being word 1) and the routine |NextWord()| to read the next
word and move |wn| on by 1. The routine returns:
\begindisplay
$-1$\quad if the user's input isn't understood,\cr
0\quad if it's understood but doesn't refer to anything,\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. Otherwise it should be left pointing to the next
thing {\it after} what the routine understood.
\medskip
\section{A5}{Library attributes}%
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
\S\S 28 and 17 respectively. These rules are the result
of pragmatism and compromise, but are all easily
modifiable.^^{attributes: defined in library}
\bigskip
\block{absent}^^|absent|^^{floating objects}%
A `floating object' (one with a
|found_in| property, which can appear in many different rooms)
which is |absent| will in future no longer appear in the game. Note that
you cannot make a floating object disappear merely by giving it
|absent|, but must explicitly |remove| it as well.
\block{animate}^^|animate|%
``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'.
\block{clothing}^^|clothing|%
``Can be worn.''
\block{concealed}^^|concealed|%
``Concealed from view but present.''
The player 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.
\block{container}^^|container|%
Affects scope and light; 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$\ldots$''; |Search| only reveals
the contents of |container|s, otherwise saying ``You find nothing''.
\block{door}^^|door|
``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''), 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'' and otherwise the player actually moves to
the location.
\block{edible}^^|edible|
``Can be eaten'' (and thus removed from game).
\block{enterable}^^|enterable|
Affects scope and light; only an |enterable| on the floor can be
entered. If an |enterable| is also a |container| then it can
only be entered or exited if it is |open|.
\block{female}^^|female|
This object has a feminine name. In games written in English,
this makes her a female person, though in other languages it might
be inanimate. The parser uses this information when considering
pronouns like ``her''. (In English, anything |animate| is assumed
to be male unless |female| or |neuter| is set.)
\block{general}^^|general|
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''.
\block{light}^^|light|
``Is giving off light.'' (See \S 17.) 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.
\block{lockable}^^|lockable|
Can be locked or unlocked by a player
holding its key object, which is given by the property |with_key|;
if a |container| and also |locked|, may be called ``locked'' in
inventories.
\block{locked}^^|locked|
Can't be opened. If a |container|
and also |lockable|, may be called ``locked'' in inventories.
\block{male}^^|male|
This object has a masculine name. In games written in English,
this makes him a male person, though in other languages it might
be inanimate. The parser uses this information when considering
pronouns like ``him''. (In English, anything |animate| is assumed
to be male unless |female| or |neuter| is set.)
\block{moved}^^|moved|
``Has been or is being 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 un|moved|.
\block{neuter}^^|neuter|
This object's name is neither masculine nor feminine. (In English,
anything without |animate| is assumed neuter, because only people and
higher animals have gender. Anything |animate| is assumed male
unless |female| or |neuter| is set. A robot, for instance, might be
an |animate| object worth making |neuter|.)
\block{on}^^|on|
``Switched on.'' A |switchable| object with this
is described by |with_on| in room descriptions; it will be called
``switched on'' by |Examine|.^^|on|\
\block{open}^^|open|
``Open door or container.'' Affects scope and light; 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. A |container| can
only be entered or exited if it is both |enterable| and |open|. An |open|
|door| can be entered. Described by |when_open| in room descriptions.
\block{openable}^^|openable|
Can be opened or closed, unless |locked|.
\block{pluralname}^^|pluralname|
This single object's name is in the plural. For instance, an
object called ``seedless grapes'' should have |pluralname| set.
The library will then use the pronoun ``them'' and the indefinite
article ``some'' automatically.
\block{proper}^^|proper|
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).
\block{scenery}^^|scenery|
Not listed by the library in room descriptions; ``not portable'' to be
taken; ``you are unable to'' pull, push, or turn it.
\block{scored}^^|scored|
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.
\block{static}^^|static|
``Fixed in place'' if player tries to take, remove,
pull, push or turn.
\block{supporter}^^|supporter|
``Things can be put on top of it.'' Affects scope and light;
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.
\block{switchable}^^|switchable|
Can be switched on or off; listed
as such by |Examine|; described using |when_on| or |when_off|
in room descriptions.
\block{talkable}^^|talkable|
Player can talk to this object in
``thing, do this'' style. This is useful for microphones and
the like, when |animate| is inappropriate.
\block{transparent}^^|transparent|
``Contents are visible.'' Affects scope and light;
a |transparent| container is treated as if it were |open| for
printing of contents.
\block{visited}^^|visited|
``Has been or is being visited by the player.''
Given to a room immediately after a |Look| first
happens there: if this room is |scored| then |ROOM_SCORE| points
are awarded. Affects whether room descriptions are abbreviated
or not.
\block{workflag}^^|workflag|
Temporary flag used by Inform internals,
also available to outside routines; can be used to select items
for some lists printed by |WriteListFrom|.
\block{worn}^^|worn|
``Item of clothing being worn.'' Should
only be 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|.
\bigskip\noindent
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 obsolete.
\section{A6}{Library properties}^^{properties: defined in library}
\noindent
The following table lists every library-defined property. The banner
headings give the name, what type of value makes sense and the default value
(if other than 0). The symbol $\oplus$ means ``this property is additive''
so that inherited values from class definitions pile up into a list, rather
than wipe each other out. Recall that `false' is the value 0 and `true'
the value 1.
\bigskip\ninepoint
\prop{n\_to, s\_to, e\_to, w\_to, ...}{Room, object or routine}%
\fr These twelve properties (there are also |ne_to|, |nw_to|, |se_to|,
|sw_to|, |in_to|, |out_to|, |u_to| and |d_to|) are the map connections for
the room. A value of 0 means ``can't go this way''. Otherwise, the
value should either be a room or a |door| object: thus, |e_to| might be set
to |crystal_bridge| if the direction ``east'' means ``over the crystal
bridge''.
\rr The room or object the map connects to; or 0 for ``can't go this way'';
or 1 for ``can't go this way; stop and print nothing further''.
\warn Do not confuse the direction properties |n_to| and so on with
the twelve direction objects, |n_obj| et
al.^^{directions: direction properties}
\prop{add\_to\_scope}{List of objects or routine}^^|add to scope|
\fo When this object is in scope, so are all those listed, or all those
nominated by the routine. A routine given here should call
|PlaceInScope(obj)| to put |obj| in scope.
\nrr
\cpropd{after}{Routine}{NULL}^^|after|
Receives actions after they have happened, but before the player has
been told of them.
\fr All actions taking place in this room.
\fo All actions for which this object is |noun| (the first object
specified in the command); and all fake actions for it.
\rr False to continue (and tell the player what has happened), true to
stop here (printing nothing).
\noindent The |Search| action is a slightly special case. Here, |after| is
called when it is clear that it would be sensible to look inside the object
(e.g., it's an open container in a light room) but before the contents
are described.
\propd{article}{String or routine}{"a"}^^|article|
\fo Indefinite article for object or routine to print one.
\nrr
\prop{articles}{Array of strings}^^|articles|
For objects: If given, these are the articles used with
the object's name. (Provided for non-English languages
where ^{irregular nouns} may have unusual ^{vowel-contraction}
rules with articles: e.g. with French non-mute `H'.)
\cpropd{before}{Routine}{NULL}^^|before|
Receives advance warning of actions (or fake actions) about to happen.
\fr All actions taking place in this room.
\fo All actions for which this object is |noun| (the first object
specified in the command); and all fake actions, such as |Receive|
and |LetGo| if this object is the container or supporter concerned.
\rr False to continue with the action, true to stop here (printing
nothing).
\noindent First special case: A vehicle object receives the |Go|
action if the player is trying to drive around in it. In this case:
\rr 0 to disallow as usual; 1 to allow as usual, moving vehicle and
player; 2 to disallow but do (and print) nothing; 3 to allow but do
(and print) nothing. If you want to move the vehicle in your own code,
return 3, not 2: otherwise the old location may be restored by subsequent
workings.
\noindent Second special case: in a |PushDir| action, the |before|
routine must call |AllowPushDir()| and then return true in order to
allow the attempt (to push an object from one room to another) to
succeed.
\propd{cant\_go}{String or routine}{"You can't go that way."}^^|cant go|
\fr Message, or routine to print one, when a player tries to go in an
impossible direction from this room.
\nrr
\propd{capacity}{Number or routine}{100}^^|capacity|
\fo Number of objects a |container| or |supporter|
can hold.
\fpo Number of things the player can carry (when the player is this
object); the default player object (|selfobj|) has |capacity| initially
set to the constant |MAX_CARRIED|.
\propd{daemon}{Routine}{NULL}^^|daemon|
This routine is run each turn, once it has been activated by a
call to |StartDaemon|, and until stopped by a call to |StopDaemon|.
\cpropd{describe}{Routine}{NULL}^^|describe|
\fo Called when the object is to be described in a room description,
before any paragraph break (i.e., skipped line) has been printed. A
sometimes useful trick is to print nothing in this routine and return
true, which makes an object `invisible'.
\fr Called before a room's long (``look'') description is printed.
\rr False to describe in the usual way, true to stop printing here.
\prop{description}{String or routine}^^|description|
\fo The |Examine| message, or a routine to print one out.
\fr The long (``look'') description, or a routine to print one out.
\nrr
\prop{door\_dir}{Direction property or routine}^^|door dir|
\fco When the player tries to go in this direction, e.g., by typing the
name of this object, then the map connection tried is the value of
this direction property for the current room. For example, the
|n_obj| ``north'' object normally has |door_dir| set to |n_to|.
\fo The direction that this |door| object goes via (for instance,
a bridge might run east, in which case this would be set to |e_to|).
\rr The direction property to try.
\prop{door\_to}{Room or routine}^^|door to|
\fo The place this door object leads to. A value of 0 means
``leads nowhere''.
\rr The room. Again, 0 (or false) means ``leads nowhere''.
Further, 1 (or true) means ``stop the movement action immediately
and print nothing further''.
\cpropd{each\_turn}{String or routine}{NULL}^^|each turn|
String to print, or routine to run, at the end of each turn in which
the object is in scope (after all timers and daemons for that turn have
been run).
\nrr
\prop{found\_in}{List of rooms or routine}^^|found in|
This object will be found in all of the listed rooms, or if
the routine says so, unless it has the attribute |absent|. If
an object in the list is not a room, it means ``present in the
same room as this object''.
\rr True to be present, otherwise false. The routine can look
at the current |location| in order to decide.
\warn This property is only looked at when the player changes rooms.
\prop{grammar}{Routine}^^|grammar|
\fato This is called when the
parser has worked out that the object in question is being spoken
to, and has decided the |verb_word| and |verb_wordnum| (the position
of the verb word in the word stream) but hasn't yet tried any grammar.
The routine can, if it wishes, parse past some words (provided it
moves |verb_wordnum| on by the number of words it wants to eat up).
\rr False to carry on as usual; true to indicate that the routine
has parsed the entire command itself, and set up |action|, |noun|
and |second| to the appropriate order; or a dictionary value for
a verb, such as |'take'|, to indicate ``parse the command from this
verb's grammar instead''; or minus such a value, e.g. |-'take'|,
to indicate ``parse from this verb and then parse the usual
grammar as well''.
\prop{initial}{String or routine}^^|initial|
\fo The description of an object not yet picked up, used when a
room is described; or a routine to print one out.
\fr Printed or run when the room is arrived in, either by ordinary
movement or by |PlayerTo|.
\warn If the object is a |door|, or a |container|, or is |switchable|,
then use one of the |when_| properties rather than |initial|.
\nrr
\prop{inside\_description}{String or routine}^^|inside description|
\fo Printed as part or all of a room description when the player is
inside the given object, which must be |enterable|.
\prop{invent}{Routine}^^|invent|
This routine is for changing an object's inventory listing. If provided,
it's called twice, first with the variable |inventory_stage| set to 1,
second with it set to 2. At stage 1, you have an entirely free hand to
print a different inventory listing.
\rr Stage 1: False to continue; true to stop here, printing nothing further
about the object or its contents.
\noindent At stage 2, the object's indefinite article and short name have
already been printed, but messages like `` (providing light)'' haven't.
This is an opportunity to add something like `` (almost empty)".
\rr Stage 2: False to continue; true to stop here, printing nothing further
about the object or its contents.
\cpropd{life}{Routine}{NULL}^^|life|
This routine holds rules about |animate| objects, behaving much like
|before| and |after| but only handling the person-to-person events:
\beginstt
Attack Kiss WakeOther ThrowAt Give Show Ask Tell Answer Order
\endtt
See \S 16, and see also the properties |orders| and |grammar|.
\rr True to stop and print nothing, false to resume as usual (for example,
printing ``Miss Gatsby has better things to do.'').
\prop{list\_together}{Number, string or routine}^^|list together|
\fo
Objects with the same |list_together| value are grouped together in
object lists (such as inventories, or the miscellany at the end of a
room description). If a string such as |"fish"| is given, then such
a group will be headed with text such as |"five fish"|.
\noindent A routine, if given, is called at two stages in the process
(once with the variable |inventory_stage| set to 1, once with it set to 2).
These stages occur before and after the group is printed; thus, a
preamble or postscript can be printed. Also, such a routine may
change the variable |c_style| (which holds the current list style).
On entry, the variable |parser_one| holds the first object in the
group, and |parser_two| the current depth of recursion in the list.
Applying |x=NextEntry(x,parser_two);| moves |x| on from |parser_one|
to the next item in the group. Another helpful variable is
|listing_together|, set up to the first object of a group being listed
(or to 0 whenever no group is being listed).
\rr Stage 1: False to continue, true not to print the group's list
at all.
\rr Stage 2: No return value.
\prop{orders}{Routine}^^|orders|
\fato This carries out the player's
orders (or doesn't, as it sees fit): it looks at |actor|, |action|,
|noun| and |second| to do so. Unless this object is the current
player, |actor| is irrelevant (it is always the player) and the
object is the person being ordered about.
\noindent If the player typed an incomprehensible command, like
``robot, og sthou'', then the action is |NotUnderstood| and the
variable |etype| holds the parser's error number.
\noindent If this object is the current player then |actor| is
the person being ordered about. |actor| can either be this
object -- in which case an action is being processed, because
the player has typed an ordinary command -- or can be some other
object, in which case the player has typed an order. See
\S 16 for how to write |orders| routines in these cases.
\rr True to stop and print nothing further; false to continue.
(Unless the object is the current player, the |life| routine's
|Order| section gets an opportunity to meddle next; after that,
Inform gives up.)
\cprop{name}{List of dictionary words}^^|name|
\fo A list of dictionary words referring to this object.
\warn The |parse_name| property of an object may take precedence over this,
if present.
\fr A list of words which the room understands but which refer to things
which ``do not need to be referred to in this game''; these are only looked
at if all other attempts to understand the player's command have failed.
\warn Uniquely in Inform syntax, these dictionary words are given in double
quotes |"thus"|, whereas in all other circumstances they would be |'thus'|.
This means they can safely be only one letter long without ambiguity.
\prop{number}{Any value}^^|number|
A general purpose property left free: conventionally holding a number like
``number of turns' battery power left''.
\fco Note that the standard compass objects defined by the library all
provide a |number| property, in case this might be useful to the designer.
\fpo Exception: an object to be used as a player-object must provide one of
these, and musn't use it for anything.
\prop{parse\_name}{Routine}^^|parse name|
\fo To parse an object's name (this overrides the |name| but is also used in
determining if two objects are describably identical). This routine should
try to match as many words as possible in sequence, reading them one at a
time by calling |NextWord()|. (It can leave the ``word marker'' variable
|wn| anywhere it likes).
\rr 0 if the text didn't make any sense at all, $-1$ to make the parser resume
its usual course (looking at the |name|), or the number of words in a row
which successfully matched.
\noindent In addition to this, if the text matched seems to be in the plural
(for instance, a blind mouse object reading |blind mice|), the routine can
set the variable |parser_action| to the value |##PluralFound|. The parser
will then match with all of the different objects understood, rather than
ask a player which of them is meant.
\noindent A |parse_name| routine may also (voluntarily) assist the parser
by telling it whether or not two objects which share the same |parse_name|
routine are identical. (They may share the same routine if they both inherit
it from a class.) If, when it is called, the variable |parser_action| is
set to |##TheSame| then this is the reason. It can then decide whether or
not the objects |parser_one| and |parser_two| are indistinguishable.
\rr $-1$ if the objects are indistinguishable, $-2$ if not.
\prop{plural}{String or routine}^^|plural|
\fo The plural name of an object (when in the presence of others like it),
or routine to print one; for instance, a wax candle might have |plural| set
to |"wax candles"|.
\nrr
\prop{react\_after}{Routine}^^|react after|
\fo Acts like an |after| rule, but detects any actions in the vicinity
(any actions which take place when this object is in scope).
\rr True to print nothing further; false to carry on.
\prop{react\_before}{Routine}^^|react before|
\fo Acts like a |before| rule, but detects any actions in the vicinity
(any actions which take place when this object is in scope).
\rr True to stop the action, printing nothing; false to carry on.
\prop{short\_name}{Routine}^^|short name|
\fo The short name of an object (like ``brass lamp"), or a routine to print
it.
\rr True to stop here, false to carry on by printing the object's `real'
short name (the string given at the head of the object's definition). It's
sometimes useful to print text like |"half-empty "| and then return false.
\prop{short\_name\_indef}{Routine}^^|short name indef|
\fo If set, this form of the short name is used
when the name is prefaced by an indefinite article. (This
is not useful in English-language games, but in other
languages adjectival parts of names agree with the
definiteness of the article.)
\prop{time\_left}{Number}^^|time left|
Number of turns left until the timer for this object (if set, which must be
done using |StartTimer|) goes off. Its initial value is of no significance,
as |StartTimer| will write over this, but a timer object must provide the
property. If the timer is currently set, the value 0 means ``will go off
at the end of the current turn'', the value 1 means ``...at the end of
next turn'' and so on.
\propd{time\_out}{Routine}{NULL}^^|time out|
Routine to run when the timer for this object goes off (having been set by
|StartTimer| and not in the mean time stopped by |StopTimer|).
\warn A timer object must also provide a |time_left| property.
\prop{when\_closed}{String or routine}^^|when closed|
\fo Description, or routine to print one, of something closed (a |door| or
|container|) in a room's long description.
\nrr
\prop{when\_open}{String or routine}^^|when open|
\fo Description, or routine to print one, of something open (a |door| or
|container|) in a room's long description.
\nrr
\prop{when\_on}{String or routine}^^|when on|
\fo Description, or routine to print one, of a |switchable| object which is
currently switched on, in a room's long description.
\nrr
\prop{when\_off}{String or routine}^^|when off|
\fo Description, or routine to print one, of a |switchable| object which is
currently switched off, in a room's long description.
\nrr
\propd{with\_key}{Object}{nothing}^^|with key|
The key object needed to lock or unlock this |lockable| object. A player
must explicitly name it as the key being used and be holding it at the time.
The value |nothing|, or 0, means that no key fits (though this is not made
clear to the player, who can try as many as he likes).
\ninepoint
\section{A7}{Library-defined objects and routines}%
The library defines the following
^{special objects}:^^{objects: defined in library}
\bigskip\stepin=90pt
\block{compass}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|.^^|compass|
\block{n\_obj, ...}^^{walls}^^{directions: direction objects}
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|).
The other such objects are |s_obj|, |e_obj|, |w_obj|, |ne_obj|, |nw_obj|,
|se_obj|, |sw_obj|, |u_obj|, |d_obj|, |in_obj| and |out_obj|.
Note that the parser understands ^{``ceiling''} to refer to |u_obj| and ^{``floor''} to refer to
|d_obj|. (|in_obj| and |out_obj| differ slightly, because ``in'' and
``out'' are verbs with other effects in some cases; these objects should not
be removed from the |compass|.)
\block{thedark}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.^^|thedark|
\block{selfobj}The default player-object. Code should never refer directly
to |selfobj|, but only to |player|, a variable whose value is usually indeed
|selfobj| but which might become |green_frog| if the player is transformed
into one.^^|selfobj|^^{player-object}
\block{InformLibrary}Represents the library. You never need to use
it, but it might sometimes be the value of |sender| when a message is received.
\block{InformParser}Represents the parser.
\bigskip\noindent
The following routines are defined in the library and available for public
use:^^{library routines}
\bigskip\stepin=110pt
\block{Achieved(task)}^^|Achieved|
Indicate the |task| is achieved (which only
awards score the first time).
\block{AddToScope(obj)}^^|AddToScope|
Used in an |add_to_scope| routine of an object to add another object
into scope whenever the first is in scope.
\block{AllowPushDir()}^^|AllowPushDir|
Signal that an attempt to push an object from
one place to another should be allowed.
\block{CDefArt(obj)}^^|CDefArt|
Print the capitalised definite article and
short name of |obj|. Equivalent to |print (The) obj;|.
\block{ChangeDefault(p,v)}^^|ChangeDefault|
Changes the default value of property |p|. (But this won't
do anything useful to |name|.)
\block{ChangePlayer(obj,flag)}^^|ChangePlayer|
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.
\block{DefArt(obj)}^^|DefArt|
Print the definite article and short name of
|obj|. Equivalent to |print (the) obj;|.
\block{DoMenu(text,R1,R2)}^^|DoMenu|
Produce a menu, using the two routines given.
\block{EnglishNumber(x)}^^|EnglishNumber|
Prints out |x| in English (e.g., ``two hundred and seventy-seven").
\block{HasLightSource(obj)}^^|HasLightSource|
Returns true if |obj| `has light'.
\block{InDefArt(obj)}^^|InDefArt|
Print the indefinite article and short name
of |obj|. Equivalent to |print (a) obj;|.
\block{Locale(obj,tx1,tx2)}^^|Locale|
Prints out the paragraphs of room description which would appear
if |obj| were the room: i.e., prints out descriptions of objects
in |obj| according to the usual rules. After describing the
objects which have their own paragraphs, a list is given of
the remaining ones. The string |tx1| is printed if there were
no previous paragraphs, and the string |tx2| otherwise.
(For instance, you might want ``On the ledge you can see''
and ``On the ledge you can also see''.) After the list, nothing
else is printed (not even a full stop) and the return value is
the number of objects in the list (possibly zero).
\block{LoopOverScope(R,actor)}^^|LoopOverScope|
Calls routine |R(obj)| for each object |obj| in scope. |actor|
is optional: if it's given, then scope is calculated for the
given actor, not the player.
\block{NextWord()}^^|NextWord|
Returns the next dictionary word in the player's
input, moving the word number |wn| on by one. Returns 0
if the word is not in the dictionary or if the word stream has
run out.
\block{NextWordStopped()}^^|NextWordStopped|
As |NextWord|, but returning $-1$ when the word stream has run out.
\block{NounDomain(o1,o2,type)}^^|NounDomain|^^|REPARSE CODE|
This routine is one of the keystones of the parser: the objects
given are the domains to search through when parsing (almost
always the location and the actor) and the |type| indicates a
token. The only ^{tokens} safely usable are: 0: \cstok{noun},
1: \cstok{held} and 6: \cstok{creature}. The routine parses
the best single object name it can from the current position
of |wn|. It returns 0 (no match), an object number or
the constant |REPARSE_CODE| (to indicate that it had to ask
a clarifying question: this reconstructed the input drastically
and the parser must begin all over again). |NounDomain| should
only be used by ^{general parsing routines} and these should
always return |REPARSE_CODE| if it does. Note that all of the
usual scope and name-parsing rules apply to the search performed
by |NounDomain|.
\block{ObjectIsUntouchable}^^|ObjectIsUntouchable|
Determines whether any solid barrier (that is, any |container| that
is not |open|) lies between the player and |obj|. If |flag| is set,
this routine never prints anything; otherwise it prints a message
like ``You can't, because ... is in the way.'' if any barrier is
found. Returns |true| if a barrier is found, |false| if not.
\block{OffersLight(obj)}^^|OffersLight|
Returns true if |obj| `offers light'.
\block{PlaceInScope(obj)}^^|PlaceInScope|
Puts |obj| into scope for the parser.
\block{PlayerTo(place,flag)}^^|PlayerTo|
Move the player to |place|. Unless
|flag| is given and is 1, describe the player's surroundings.
\block{PrintShortName(obj)}^^|PrintShortName|
Print the short name of |obj|.
(This is protected against |obj| having a meaningless value.)
Equivalent to |print (name) obj;|.
\block{ScopeWithin(obj)}^^|ScopeWithin|
Puts the contents of |obj| into scope,
recursing downward according to the usual scope rules.
\block{SetTime(time,rate)}^^|SetTime|
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.
\block{StartDaemon(obj)}^^|StartDaemon|
Makes the daemon of |obj| active, so
that its |daemon| routine will be called every turn.
\block{StartTimer(obj,time)}^^|StartTimer|
Starts the timer of |obj|, set
to go off in |time| turns, at which time its |time_out| routine will be called
(it must provide a |time_left| property).
\block{StopDaemon(obj)}^^|StopDaemon|
Makes the daemon of |obj| inactive, so
that its |daemon| routine is no longer called.
\block{StopTimer(obj)}^^|StopTimer|
Stops the timer of |obj|, so that
it won't go off after all.
\block{TestScope(obj,actor)}^^|TestScope|
Returns true if |obj| is in scope; otherwise false. |actor|
is optional: if it's given, then scope is calculated for the
given actor, not the player.
\block{TryNumber(wordnum)}^^|TryNumber|
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|
\block{UnsignedCompare(a,b)}^^|UnsignedCompare|
Returns 1 if $a>b$, 0 if $a=b$ and $a<b$, regarding $a$ and $b$ as unsigned
numbers between 0 and 65535 (or |$ffff|). (The usual $>$ condition performs
a signed comparison.)
\block{WordAddress(n)}^^|WordAddress|
Returns the byte array containing the raw text of the $n$-th
word in the word stream.
\block{WordLength(n)}^^|WordLength|
Returns the length of the raw text of the $n$-th
word in the word stream.
\block{WriteListFrom(obj,s)}^^|WriteListFrom|
Write a list of |obj| and its
siblings, with the style being |s| (a bitmap of options).
\block{YesOrNo()}^^|YesOrNo|
Assuming that a question has already been printed,
wait for the player to type ``yes'' or ``no'', returning true or false
accordingly.
\block{ZRegion(value)}^^|ZRegion|
Works out the type of |value|, if possible. Returns 1 if it's a valid
object number, 2 if a routine address, 3 if a string address and 0
otherwise.
\section{A8}{Library actions}%
The actions implemented by the library are in three groups. Group 1 consists
of actions associated with `meta'-verbs, which are not subject to game
rules. (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.)
\beginlines
|1a. Quit, Restart, Restore, Verify, Save, ScriptOn, ScriptOff, Pronouns,|
| Score, Fullscore, LMode1, LMode2, LMode3, NotifyOn, NotifyOff,|
| Version, Places, Objects.|
\endlines^^{groups of actions: group 1}
^^{actions: list of group 1}^^{actions: defined in Library}
(|Lmode1|, |Lmode2| and |Lmode3| switch between ^{``brief''}, ^{``verbose''}
and ^{``superbrief''} room description styles.)
In addition, but only if |DEBUG| is defined, so that the debugging suite
is present, group 1 contains
\beginlines
|1b. TraceOn, TraceOff, TraceLevel, ActionsOn, ActionsOff, RoutinesOn,|
| RoutinesOff, TimersOn, TimersOff, CommandsOn, CommandsOff, CommandsRead,|
| Predictable, XPurloin, XAbstract, XTree, Scope, Goto, Gonear.|
\endlines^^{actions: in debugging suite}^^{debugging suite actions}
Group 2 contains actions which sometimes get as far as the `after' stage,
because the library sometimes does something when processing them.
\beginlines
|2. Inv, InvTall, InvWide, Take, Drop, Remove, PutOn, Insert, Transfer,|
| Empty, Enter, Exit, GetOff, Go, GoIn, Look, Examine, Search, Give, Show,|
| Unlock, Lock, SwitchOn, SwitchOff, Open, Close, Disrobe, Wear, Eat.|
\endlines^^{groups of actions: group 2}
Group 3 contains the remaining actions, which never reach `after' because
the library simply prints a message and stops at the `during' stage.
\beginlines
|3. Yes, No, Burn, Pray, Wake, WakeOther [person], Consult,|
| Kiss, Think, Smell, Listen, Taste, Touch, 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, SetTo, WaveHands [ie, just "wave"],|
| Wave [something], Pull, Push, PushDir [push something in a direction],|
| Turn, Squeeze, LookUnder [look underneath something],|
| ThrowAt, Answer, Buy, Ask, AskFor, Sing, Climb, Wait, Sleep.|
\endlines\ninepoint^^{groups of actions: group 3}
\danger The actions |PushDir| and |Go| (while the player is inside an
|enterable| object) have special rules: see \S 14.
\noindent
The library also defines 8 fake actions:
\beginlines
|LetGo, Receive, ThrownAt, Order, TheSame, PluralFound, Miscellany, Prompt|
\endlines\ninepoint^^{fake actions: defined in library}
|LetGo|, |Receive| and |ThrownAt| are used to allow the |second|
noun of |Insert|, |PutOn|, |ThrowAt|, |Remove| actions to intervene;
|Order| is used to process actions through somebody's |life| routine;
|TheSame| and |PluralFound| are defined by the parser as ways for the
program to communicate with it; |Miscellany| and |Prompt| are defined
as slots for |LibraryMessages|.
\section{A9}{Library message numbers}%
\ninepoint
\def\M#1{\par\noindent\hangindent=20pt\hangafter=1{\ninebf #1:}\quad}
\def\N{\quad}
\M{Answer} ``There is no reply.''
\M{Ask} ``There is no reply.''
\M{Attack} ``Violence isn't the answer to this one.''
\M{Blow} ``You can't usefully blow that/those.''
\M{Burn} ``This dangerous act would achieve little.''
\M{Buy} ``Nothing is on sale.''
\M{Climb} ``I don't think much is to be achieved by that.''
\M{Close} 1. ``That's/They're not something you can close.''
\N 2. ``That's/They're already closed.''
\N 3. ``You close \<x1>.''
\M{Consult} ``You discover nothing of interest in \<x1>.''
\M{Cut} ``Cutting that/those up would achieve little.''
\M{Dig} ``Digging would achieve nothing here.''
\M{Disrobe} 1. ``You're not wearing that/those.''
\N 2. ``You take off \<x1>.''
\M{Drink} ``There's nothing suitable to drink here.''
\M{Drop} 1. ``The \<x1> is/are already here.''
\N 2. ``You haven't got that/those.''
\N 3. ``(first taking \<x1> off)''
\N 4. ``Dropped.''
\M{Eat} 1. ``That's/They're plainly inedible.''
\N 2. ``You eat \<x1>. Not bad.''
\M{EmptyT} 1. \<x1> `` can't contain things.''
\N 2. \<x1> `` is/are closed.''
\N \<x1> `` is/are empty already.''
\M{Enter} 1. ``But you're already on/in \<x1>.''
\N 2. ``That's/They're not something you can enter.''
\N 3. ``You can't get into the closed \<x1>.''
\N 4. ``You can only get into something freestanding.''
\N 5. ``You get onto/into \<x1>.''
\M{Examine} 1. ``Darkness, noun. An absence of light to see by.''
\N 2. ``You see nothing special about \<x1>.''
\N 3. ``\<x1> is/are currently switched on/off.''
\M{Exit} 1. ``But you aren't in anything at the moment.''
\N 2. ``You can't get out of the closed \<x1>.''
\N 3. ``You get off/out of \<x1>.''
\M{Fill} ``But there's no water here to carry.''
\M{FullScore} 1. ``The score is/was made up as follows:|^|''
\N 2. ``finding sundry items''
\N 3. ``visiting various places''
\N 4. ``total (out of |MAX_SCORE|)''
\M{GetOff} ``But you aren't on \<x1> at the moment.''
\M{Give} 1. ``You aren't holding \<x1>.''
\N 2. ``You juggle \<x1> for a while, but don't achieve much.''
\N 3. ``\<x1> doesn't/don't seem interested.''
\M{Go} 1. ``You'll have to get off/out of \<x1> first.''
\N 2. ``You can't go that way.''
\N 3. ``You are unable to climb \<x1>.''
\N 4. ``You are unable to descend \<x1>.''
\N 5. ``You can't, since \<x1> is/are in the way.''
\N 6. ``You can't, since \<x1> leads nowhere.''
\M{Insert} 1. ``You need to be holding \<x1> before you
can put it/them into something else.''
\N 2. ``That/Those can't contain things.''
\N 3. ``\<x1> is/are closed.''
\N 4. ``You'll need to take it/them off first.''
\N 5. ``You can't put something inside itself.''
\N 6. ``(first taking it/them off)|^|''
\N 7. ``There is no more room in \<x1>.''
\N 8. ``Done.''
\N 9. ``You put \<x1> into \<second>.''
\M{Inv} 1. ``You are carrying nothing.''
\N 2. ``You are carrying''
\M{Jump} ``You jump on the spot, fruitlessly.''
\M{JumpOver} ``You would achieve nothing by this.''
\M{Kiss} ``Keep your mind on the game.''
\M{Listen} ``You hear nothing unexpected.''
\M{LMode1} `` is now in its normal ~brief~ printing mode, which gives
long descriptions of places never before visited and short
descriptions otherwise.''
\M{LMode2} `` is now in its ~verbose~ mode, which always gives long
descriptions of locations (even if you've been there before).''
\M{LMode3} `` is now in its ~superbrief~ mode, which always gives short
descriptions of locations (even if you haven't been there before).''
\M{Lock} 1. ``That doesn't/They don't seem to be something you can lock.''
\N 2. ``That's/They're locked at the moment.''
\N 3. ``First you'll have to close \<x1>.''
\N 4. ``That doesn't/Those don't seem to fit the lock.''
\N 5. ``You lock \<x1>.''
\M{Look} 1. `` (on \<x1>)''
\N 2. `` (in \<x1>)''
\N 3. `` (as \<x1>)''
\N 4. ``|^|On \<x1> is/are \<list>''
\N 5. ``[On/In \<x1>] you/You can also see \<list> [here].''
\N 6. ``[On/In \<x1>] you/You can see \<list> [here].''
\M{LookUnder} 1. ``But it's dark.''
\N ``You find nothing of interest.''
\M{Mild} ``Quite.''
\M{ListMiscellany} 1. `` (providing light)''
\N 2. `` (which is/are closed)''
\N 3. `` (closed and providing light)''
\N 4. `` (which is/are empty)''
\N 5. `` (empty and providing light)''
\N 6. `` (which is/are closed and empty)''
\N 7. `` (closed, empty and providing light)''
\N 8. `` (providing light and being worn''
\N 9. `` (providing light''
\N 10. `` (being worn''
\N 11. `` (which is/are ''
\N 12. ``open''
\N 13. ``open but empty''
\N 14. ``closed''
\N 15. ``closed and locked''
\N 16. `` and empty''
\N 17. `` (which is/are empty)''
\N 18. `` containing ''
\N 19. `` (on ''
\N 20. ``, on top of ''
\N 21. `` (in ''
\N 22. ``, inside ''
\M{Miscellany} 1. ``(considering the first sixteen objects only)|^|''
\N 2. ``Nothing to do!''
\N 3. `` You have died ''
\N 4. `` You have won ''
\N 5. (The RESTART/RESTORE/QUIT and possibly FULL
and AMUSING query, printed after the game is over.)
\N 6. ``[Your interpreter does not provide undo. Sorry!]''
\N 7. ``Undo failed. [Not all interpreters provide it.]''
\N 8. ``Please give one of the answers above.''
\N 9. ``|^|It is now pitch dark in here!''
\N 10. ``I beg your pardon?''
\N 11. ``[You can't ``undo'' what hasn't been done!]''
\N 12. ``[Can't ``undo'' twice in succession. Sorry!]''
\N 13. ``[Previous turn undone.]''
\N 14. ``Sorry, that can't be corrected.''
\N 15. ``Think nothing of it.''
\N 16. ````Oops'' can only correct a single word.''
\N 17. ``It is pitch dark, and you can't see a thing.''
\N 18. ``yourself'' (the short name of the |selfobj| object)
\N 19. ``As good-looking as ever.''
\N 20. ``To repeat a command like ``frog, jump'', just say
``again'', not ``frog, again''.''
\N 21. ``You can hardly repeat that.''
\N 22. ``You can't begin with a comma.''
\N 23. ``You seem to want to talk to someone, but I can't see whom.''
\N 24. ``You can't talk to \<x1>.''
\N 25. ``To talk to someone, try ``someone, hello'' or some such.''
\N 26. ``(first taking |not_holding|)''
\N 27. ``I didn't understand that sentence.''
\N 28. ``I only understood you as far as wanting to ''
\N 29. ``I didn't understand that number.''
\N 30. ``You can't see any such thing.''
\N 31. ``You seem to have said too little!''
\N 32. ``You aren't holding that!''
\N 33. ``You can't use multiple objects with that verb.''
\N 34. ``You can only use multiple objects once on a line.''
\N 35. ``I'm not sure what ``\<pronoun>'' refers to.''
\N 36. ``You excepted something not included anyway!''
\N 37. ``You can only do that to something animate.''
\N 38. ``That's not a verb I recognise.''
\N 39. ``That's not something you need to refer to in the
course of this game.''
\N 40. ``You can't see ``\<pronoun>'' (\<value>) at the moment.''
\N 41. ``I didn't understand the way that finished.''
\N 42. ``None/only \<x1> of those is/are available.''
\N 43. ``Nothing to do!''
\N 44. ``There are none at all available!''
\N 45. ``Who do you mean, ''
\N 46. ``Which do you mean, ''
\N 47. ``Sorry, you can only have one item here. Which exactly?''
\N 48. ``Whom do you want [\<actor>] to \<command>?''
\N 49. ``What do you want [\<actor>] to \<command>?''
\N 50. ``Your score has just gone up/down by \<x1> point/points.''
\N 51. ``(Since something dramatic has happened, your list of
commands has been cut short.)''
\N 52. ``Type a number from 1 to \<x1>, 0 to redisplay or press ENTER.''
\N 53. ``[Please press SPACE.]''
\M{No} see {\bf Yes}
\M{NotifyOff} ``Score notification off.''
\M{NotifyOn} ``Score notification on.''
\M{Objects} 1. ``Objects you have handled:|^|''
\N 2. ``None.''
\N 3. `` (worn)''
\N 4. `` (held)''
\N 5. `` (given away)''
\N 6. `` (in \<x1>)'' [without article]
\N 7. `` (in \<x1>)'' [with article]
\N 8. `` (inside \<x1>)''
\N 9. `` (on \<x1>)''
\N 10. `` (lost)''
\M{Open} 1. ``That's/They're not something you can open.''
\N 2. ``It seems/They seem to be locked.''
\N 3. ``That's/They're already open.''
\N 4. ``You open \<x1>, revealing \<children>''
\N 5. ``You open \<x1>.''
\M{Order} ``\<x1> has/have better things to do.''
\M{Places} ``You have visited: ''
\M{Pray} ``Nothing practical results from your prayer.''
\M{Prompt} 1. ``|^>|''
\M{Pronouns} 1. ``At the moment, ''
\N 2. ``means ''
\N 3. ``is unset ''
\N 4. ``no pronouns are known to the game.''
\M{Pull} 1. ``It is/Those are fixed in place.''
\N 2. ``You are unable to.''
\N 3. ``Nothing obvious happens.''
\N 4. ``That would be less than courteous.''
\M{Push} see {\bf Pull}
\M{PushDir} 1. ``Is that the best you can think of?''
\N 2. ``That's not a direction.''
\N 3. ``Not that way you can't.''
\M{PutOn} 1. ``You need to be holding \<x1> before you
can put it/them on top of something else.''
\N 2. ``You can't put something on top of itself.''
\N 3. ``Putting things on \<x1> would achieve nothing.''
\N 4. ``You lack the dexterity.''
\N 5. ``(first taking it/them off)|^|''
\N 6. ``There is no more room on \<x1>.''
\N 7. ``Done.''
\N 8. ``You put \<x1> on <second>.''
\M{Quit} 1. ``Please answer yes or no.''
\N 2. ``Are you sure you want to quit? ''
\M{Remove} 1. ``It is/They are unfortunately closed.''
\N 2. ``But it isn't/they aren't there now.''
\N 3. ``Removed.''
\M{Restart} 1. ``Are you sure you want to restart? ''
\N 2. ``Failed.''
\M{Restore} 1. ``Restore failed.''
\N 2. ``Ok.''
\M{Rub} ``You achieve nothing by this.''
\M{Save} 1. ``Save failed.''
\N 2. ``Ok.''
\M{Score} ``You have so far/In that game you scored \<score> out of
a possible |MAX_SCORE|, in \<turns> turn/turns''
\M{ScriptOn} 1. ``Transcripting is already on.''
\N 2. ``Start of a transcript of''
\M{ScriptOff} 1. ``Transcripting is already off.''
\N 2. ``|^|End of transcript.''
\M{Search} 1. ``But it's dark.''
\N 2. ``There is nothing on \<x1>.''
\N 3. ``On \<x1> is/are \<list of children>.''
\N 4. ``You find nothing of interest.''
\N 5. ``You can't see inside, since \<x1> is/are closed.''
\N 6. ``\<x1> is/are empty.''
\N 7. ``In \<x1> is/are \<list of children>.''
\M{Set} ``No, you can't set that/those.''
\M{SetTo} ``No, you can't set that/those to anything.''
\M{Show} 1. ``You aren't holding \<x1>.''
\N 2. ``\<x1> is/are unimpressed.''
\M{Sing} ``Your singing is abominable.''
\M{Sleep} ``You aren't feeling especially drowsy.''
\M{Smell} ``You smell nothing unexpected.''
\M{Sorry} ``Oh, don't apologise.''
\M{Squeeze} 1. ``Keep your hands to yourself.''
\N 2. ``You achieve nothing by this.''
\M{Strong} ``Real adventurers do not use such language.''
\M{Swim} ``There's not enough water to swim in.''
\M{Swing} ``There's nothing sensible to swing here.''
\M{SwitchOff} 1. ``That's/They're not something you can switch.''
\N 2. ``That's/They're already off.''
\N 3. ``You switch \<x1> off.''
\M{SwitchOn} 1. ``That's/They're not something you can switch.''
\N 2. ``That's/They're already on.''
\N 3. ``You switch \<x1> on.''
\M{Take} 1. ``Taken.''
\N 2. ``You are always self-possessed.''
\N 3. ``I don't suppose \<x1> would care for that.''
\N 4. ``You'd have to get off/out of \<x1> first.''
\N 5. ``You already have that/those.''
\N 6. ``That seems/Those seem to belong to \<x1>.''
\N 7. ``That seems/Those seem to be a part of \<x1>.''
\N 8. ``That isn't/Those aren't available.''
\N 9. ``\<x1> isn't/aren't open.''
\N 10. ``That's/They're hardly portable.''
\N 11. ``That's/They're fixed in place.''
\N 12. ``You're carrying too many things already.''
\N 13. ``(putting \<x1> into |SACK_OBJECT| to make room)''
\M{Taste} ``You taste nothing unexpected.''
\M{Tell} 1. ``You talk to yourself a while.''
\N 2. ``This provokes no reaction.''
\M{Touch} 1. ``Keep your hands to yourself!''
\N 2. ``You feel nothing unexpected.''
\N 3. ``If you think that'll help.''
\M{Think} ``What a good idea.''
\M{Tie} ``You would achieve nothing by this.''
\M{ThrowAt} 1. ``Futile.''
\N 2. ``You lack the nerve when it comes to the crucial moment.''
\M{Turn} see {\bf Pull}
\M{Unlock} 1. ``That doesn't seem to be something you can unlock.''
\N 2. ``It's/They're unlocked at the moment.''
\N 3. ``That doesn't/Those don't seem to fit the lock.''
\N 4. ``You unlock \<x1>.''
\M{VagueGo} ``You'll have to say which compass direction to go in.''
\M{Verify} 1. ``The game file has verified as intact.''
\N 2. ``The game file did not verify properly, and may be corrupted
(or you may be running it on a very primitive interpreter which
is unable properly to perform the test).''
\M{Wait} ``Time passes.''
\M{Wake} ``The dreadful truth is, this is not a dream.''
\M{WakeOther} ``That seems unnecessary.''
\M{Wave} 1. ``But you aren't holding that/those.''
\N 2. ``You look ridiculous waving \<x1>.''
\M{WaveHands} ``You wave, feeling foolish.''
\M{Wear} 1. ``You can't wear that/those!''
\N 2. ``You're not holding that/those!''
\N 3. ``You're already wearing that/those!''
\N 4. ``You put on \<x1>.''
\M{Yes} ``That was a rhetorical question.''
\section{A10}{Entry points and meaningful 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 {\it must} define an ^|Initialise| routine, which is
obliged to set the |location| variable to a room; the rest are
optional.^^{entry points}\bigskip\stepin=110pt
\block{AfterLife}^^|AfterLife|
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.
\block{AfterPrompt}^^|AfterPrompt|
Called just after the prompt is printed: therefore, called after all the
printing for this turn is definitely over. A useful opportunity to
use |box| to display quotations without them scrolling away.
\block{Amusing}^^|Amusing|
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.)
\block{BeforeParsing}^^|BeforeParsing|
Called after the parser has read in some text and set up the
|buffer| and |parse| tables, but has done nothing else yet (except
to set the word marker |wn| to 1). The routine can do anything it
likes to these tables, and can leave the word marker anywhere; there
is no meaningful return value.
\block{ChooseObjects(obj,c)}^^|ChooseObjects|
When |c| is 0, the parser is processing an ``all'' and has
decided to exclude |obj| from it; when |c| is 1, it has
decided to include it. Returning 1 forces inclusion,
returning 2 forces exclusion and returning 0 lets the parser's
decision stand. When |c| is 2, the parser wants help in
resolving an ambiguity: using the |action_to_be| variable
the routine must decide how appropriate |obj| is for the
given action and return a score of 0 to 9 accordingly. See \S 29.
\block{DarkToDark}^^|DarkToDark|
Called when a player goes from one dark room into another one; a splendid
excuse to kill the player off.
\block{DeathMessage}^^|DeathMessage|
Prints up ``You have died" style messages, for |deadflag| values of 3 or
more. (If you choose ever to set |deadflag| to such.)
\block{GamePostRoutine}^^|GamePostRoutine|
A kind of super-|after| rule, which applies to all actions in the game,
whatever they are: use only in the last resort.
\block{GamePreRoutine}^^|GamePreRoutine|
A kind of super-|before| rule, which applies to all actions in the game,
whatever they are: use only in the last resort.
\block{Initialise}^^|Initialise|
A compulsory routine, which must set |location| and is convenient for
miscellaneous initialising, perhaps for random settings.
\block{InScope}^^|InScope|
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.
\block{LookRoutine}^^|LookRoutine|
Called at the end of every |Look| description.
\block{NewRoom}^^|NewRoom|
Called when the room changes, before any description of it is printed. This
happens in the course of ordinary movements or use of |PlayerTo|, but may
not happen if the game uses |move| to shift the player object directly.
\block{ParseNoun(obj)}^^|ParseNoun|
To do the job of parsing the |name| property (if |parse_name| hasn't done
it already). This takes one argument, the object in question, and returns
a value as if it were a |parse_name| routine.
\block{ParseNumber(text,n)}^^|ParseNumber|
An opportunity to parse numbers in a different (or additional) way. The
text to be parsed is a byte array of length |n| starting at |text|.
\block{ParserError(pe)}^^|ParserError|
The chance to print different parser error messages (like ``I don't
understand that sentence''). |pe| is the parser error number (see \S 29).
\block{PrintRank}^^|PrintRank|
Completes the printing of the score. You might want to change this, so as
to make the ranks something like ^{``junior astronaut"} or ^{``master
catburglar"} or whatever suits your game.
\block{PrintVerb(v)}^^|PrintVerb|
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. |v| is the dictionary address of the verb.
Returns true (or 1) if it has printed something.
\block{PrintTaskName(n)}^^|PrintTaskName|
Prints the name of task |n| (such as ``driving the car").
\block{TimePasses}^^|TimePasses|
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.
\block{UnknownVerb}^^|UnknownVerb|
Called by the parser when it hits an unknown verb,
so that you can transform it into a known one.
\bigskip\noindent
The following constants, if defined in a game, change settings made by the
library. Those described as ``To indicate that...'' have no meaningful
value; one simply defines them by, e.g., the directive |Constant DEBUG;|.
\bigskip\stepin=90pt
\block{AMUSING\_PROVIDED}To indicate that an |Amusing| routine is provided.
\block{DEBUG}To indicate that the special ``debugging" verbs are to be
included.
\block{Headline}Style of game and copyright message.
\block{MAX\_CARRIED}Maximum number of (direct) possessions the player can
carry.
\block{MAX\_SCORE}Maximum game score.
\block{MAX\_TIMERS}Maximum number of timers or daemons active at any one time
(defaults to 32).
\block{NO\_PLACES}To indicate that the ``places'' and ``objects'' verbs
should not be allowed.
\block{NUMBER\_TASKS}Number of `tasks' to perform.
\block{OBJECT\_SCORE}Score for picking up a |scored| object for the first
time.
\block{ROOM\_SCORE}Score for visiting up a |scored| room for the first time.
\block{SACK\_OBJECT}Object which acts as a `rucksack', into which the game
automatically tidies away things for the player.
\block{Story}Story name, conventionally in CAPITAL LETTERS.
\block{TASKS\_PROVIDED}To indicate that ``tasks'' are provided.
\block{WITHOUT\_DIRECTIONS}To indicate that the standard compass directions
are to be omitted.
\section{A11}{What order the program should be in}%
This section summarises Inform's ``this has to be defined before
that can be'' rules.
\smallskip
\item{1.} The three library files, |Parser|, |Verblib| and |Grammar| must be
included in that order.
\smallskip
\itemitem{(a)} Before inclusion of |Parser|: you must define the constants
|Story| and |Headline|; the constant |DEBUG| must be defined here, if
anywhere; similarly for |Replace| directives; but you may not yet define global
variables, objects or routines. If you are linking in the library
(using |USE_MODULES|) then you may not use the |Attribute| or |Property|
directive in this part of the program.
\itemitem{(b)} Between |Parser| and |Verblib|: if a `sack object' is
to be included, it should be defined here, and the constant |SACK_OBJECT|
set to it; the |LibraryMessages| object should be defined here, if at
all; likewise the |task_scores| array.
\itemitem{(c)} Before inclusion of |Verblib|: the constants
\begindisplay
\qquad |MAX_CARRIED|, |MAX_SCORE|, |NUMBER_TASKS|, |OBJECT_SCORE|,\cr
\qquad |ROOM_SCORE|, |AMUSING_PROVIDED| and |TASKS_PROVIDED|\cr
\enddisplay
must be defined before this (if ever).
\itemitem{(d)} Before inclusion of |Grammar|: |Verb| and |Extend| directives
cannot be used.
\itemitem{(e)} After inclusion of |Grammar|: It's too late to define any
entry point routines.
\smallskip
\item{2.} Any |Switches| directive must come before the definition of any
constants.
\item{3.} If an object begins inside another, it must be defined after its
parent.
\item{4.} |Global| variables must be declared earlier in the
program than the first reference to them.
\item{5.} Attributes and classes must be declared earlier than
their first usage in an object definition.
\item{6.} General parsing and scope routines must be defined before being quoted
in grammar tokens.
\item{7.} Nothing can be defined after the |End| directive.
\tenpoint
\vfill\eject\lexicontrue\mark{actions}
\ninepoint
\section{A12}{A short Inform lexicon}%
This brief dictionary of Inform jargon defines terms used in the manual,
generally excepting language features set in |computer| type.
Cross-references are italicised. Everything here is in the body of the
text somewhere and can be found via the index.
\medskip
\def\W#1{{\sl #1}}
\stepin=20pt
\def\E#1{\par\noindent\hangindent=20pt\hangafter=1{\ninebf #1}\mark{#1}\quad}
\E{action}%
A single attempted action by the \W{player}, such as taking a lamp,
generated either by the \W{parser} or in code. It is stored as
three numbers, the first being the \W{action number}, the others
being the \W{noun} and \W{second noun} (if any: otherwise 0).
\E{action number}%
A number identifying which kind of action is under way, e.g., |Take|,
which can be written as a \W{constant} by prefacing its name with
|##|.
\E{action routine}%
The \W{routine} of code executed when an \W{action} has been
allowed to take place. What marks it out as the routine in
question is that its name is the name of the \W{action} with
|Sub| appended, as for instance |TakeSub|.
\E{actor}%
The \W{parser} can interpret what the \W{player} types as either a
request for the player's own character to do something, in which
case the actor is the player's object, or to request somebody else
to do something, in which case the actor is the person being
spoken to. This affects the parser significantly because the
person speaking and the person addressed may be able to see
different things.
\E{additive}%
An additive \W{property} is one whose value accumulates into a
list held in a \W{word array}, rather than being over-written as
a single value, during \W{inheritance} from \W{classes}.
\E{Advanced game}%
The default Inform \W{format} of \W{story file}, also known as
Version 5. It can be extended (see \W{version}) if needed.
\W{Standard games} should no longer be used unless necessary.
\E{alias}%
A single \W{attribute} or \W{common property} may be used for two
different purposes, with different names, provided care is exercised
to avoid clashes: the two names are called aliases. The \W{library}
uses this: for instance, |time_out| is an alias for |daemon|.
\E{ambiguity}%
Arises when the \W{player} has typed something vague like ``fish''
in circumstances when many nearby objects might be called that. The
\W{parser} then resolves this, possibly in conjunction with the program.
\E{argument}%
A parameter specified in a \W{routine} call, such as |7| in the call
|AwardPoints(7)|.
\E{array}%
An indexed collection of global variables. There are four kinds,
\W{byte arrays} |->|, \W{word arrays} |-->|, \W{strings} and
\W{tables}.
\E{assembly language}%
The \W{Z-machine} runs a sequence of low-level instructions,
or assembly lines (also called opcodes). These can be programmed
directly as Inform \W{statements} by prefixing them with |@|, but
only a few are documented in this manual, in \S 33, the rest
being in the `Z-machine Standards Document'.
\E{assembler error}%
A very low-level \W{error} caused by a malformed line of
\W{assembly language}.
\E{assignment}%
A \W{statement} which sets the value of a \W{global} or \W{local
variable}, or \W{array} entry.
\E{attribute}%
An \W{object} can be created as having certain attributes, which
are simple off-or-on states (or flags), which can then be
given, tested for or taken away by the program. For example,
|light| represents the state ``is giving off light''.
\E{block of code}%
See \W{code block}.
\E{box}%
A rectangle of text, usually displayed in reverse video onto the
screen and with text such as a quotation inside (see \S 32).
\E{byte}%
An 8-bit cell of memory, capable of holding numbers between 0
and 255.
\E{byte address}%
The whole lower part of the \W{memory map} of the \W{Z-machine}
can be regarded as a \W{byte array}, and a byte address is an
index into this. E.g., byte address 0 refers to the lowest byte
in the machine (which always holds the \W{version} number).
\W{Dictionary} words are internally stored as byte addresses.
\E{byte array}%
An \W{array} indexed with the |->| \W{operator} whose entries are
only 1 byte each: they can therefore hold numbers between 0 and 255,
or ASCII ^{characters}, but not strings or object numbers.
\E{character}%
A single letter `A' or symbol `*', written as a \W{constant} using
the notation |'A'|, and internally stored as its ASCII code. Can
be printed using |print (char)|.
\E{child}%
See \W{object tree}.
\E{class}%
A template for an \W{object} definition, giving certain properties
and attributes which are \W{inherited} by any objects defined as
being of this class. Classes also exist as objects in their own
right and belong to a \W{metaclass} called |Class|.
\E{code block}%
A collection of \W{statements} can be grouped together into a block
using braces |{| and |}| so that they count as a single unit for
|if| statements, what is to be done inside a |for| loop, etc.
\E{common property}%
Any \W{property} set by the \W{class} |Object| is passed on to
every \W{object} and is called a ``common property'': for example,
|description|. All others are \W{individual properties}. New
properties can be declared as common with the |Property| directive.
They behave similarly except that:
(a) values of common properties can be read even from an \W{object}
not providing them, the result being a special default value, which
can be altered using |ChangeDefault|;
(b) they are faster and slightly more economical of memory to use;
(c) there are a limited number of them.
\E{compass}%
The |compass| \W{object}, created by the \W{library} but never
tangible to the \W{player} during the game, is used to hold the currently
valid \W{direction objects}.
\E{compiler}%
The Inform program itself, which transmutes Inform programs (or
source code) into the \W{story file} which is played with the use
of an \W{interpreter} at \W{run-time}.
\E{condition}%
A state of affairs which either is, or isn't, true at any given
moment, such as |x == y|, often written in round brackets |(| and |)|.
The central operator |==| is also called the condition. A numerical
value given with no operator is considered true if it is non-zero
and otherwise false.
\E{constant}%
An explicitly written-out number, such as |34| or |$$10110111|; or the
internal name of an object, such as |brass_lamp|, whose value is its
\W{object number}; or the internal name of an array, whose value is its
\W{byte address}; or a word defined by either the \W{library} or Inform code
as meaning a particular value; or a \W{character}, written |'X'| and
whose value is its ASCII code; or a \W{dictionary word}, written |'word'|
and whose value is its \W{byte address}; or an \W{action}, written |##Action|
and whose value is its \W{action number}; or a \W{routine} written |#r$Routine|
whose value is its \W{packed address}; or the name of a \W{property} or
\W{attribute} or \W{class}.
\E{containment}%
See \W{object tree}.
\E{cursor}%
An invisible notional position at which text is being printed in the upper
\W{window}, when the windows are split; the origin is $(1,1)$ in the top
left.
\E{daemon}%
A \W{routine} attached to an \W{object} which, once started, is run once during
the end sequence of every \W{turn} until explicitly stopped. Used to manage
events happening as time passes by, or to notice changes in the state of the
game which require some activity.
\E{default value}%
See \W{property}.
\E{description}%
The usually quite long piece of text attached to an \W{object}; if it's a
\W{room}, then this is the long description printed out when the room is
first visited; otherwise it will usually be printed when the object is
examined by the \W{player}.
\E{dictionary}^^{dictionary}
A list kept inside the \W{Z-machine} of all the words ordinarily understood
by the game, such as ``throw'' and ``mauve'', usually between about 300 and
2000 words long. Inform automatically puts this list together from all the
|name| values of objects and all usages of constants like |'word'|.
Dictionary words are stored to a resolution of 9 characters (6 for
\W{Standard games}), written |'thus'| (provided they have more than one
letter; otherwise |#n$x| for the word ``x''; except as values of the special
|name| property) and are internally referred to by numbers which are their
\W{byte addresses} inside the list.
\E{direct containment}%
See \W{object tree}.
\E{direction object}%
An object representing both the abstract idea of a direction and the wall
which is in that direction: for instance, |n_obj| represents ``northness''
and the north wall of the current \W{room}. Typing ``go north'' causes the
\W{parser} to generate the \W{action} |Go n_obj|. The current direction
objects are exactly those currently inside the |compass| object and they
can be dynamically changed. The |door_dir| property of a direction object
holds its corresponding direction property.
\E{direction property}%
The \W{library} creates 12 direction properties: |n_to|, |s_to|, etc., |u_to|,
|d_to|, |in_to| and |out_to|. These are used to give \W{map} connections from
\W{rooms} and indicate directions which doors and \W{direction objects}
correspond to.
\E{directive}%
A line of Inform code which instructs the \W{compiler} to do something, such as
to define a new \W{constant}; it takes immediate effect and does not correspond
to anything happening at \W{run-time}. These are not normally written inside
\W{routines} but can be if prefaced by a |#| character.
\E{eldest child}%
See \W{object tree}.
\E{embedded routine}%
A \W{routine} defined as the \W{property} value of an \W{object}, which
is defined without a name of its own, and which by default returns `false'
rather than `true'.
\E{encapsulation}%
When an \W{object} declares a \W{property} as being |private|, its value
is unavailable anywhere else in the program: it can be read or written to
only by that one object itself. This close concealment of data is called
encapsulation.
\E{entry point}%
A \W{routine} in an Inform program which is directly called by the \W{library}
to intervene in the normal operation of the game (if the routine so wishes).
Provision of entry points is optional, except for |Initialise|, which must
always occur in every game.
\E{error}%
When the \W{compiler} finds something in the program which it can't make sense
of, it produces an error (which will eventually prevent it from generating a
\W{story file}, so that it cannot generate an illegal \W{story file} which
would fail at \W{run-time}). If the error is \W{fatal} the compiler stops
at once.
\E{examine message}%
See \W{description}.
\E{expression}%
A general piece of Inform code which determines a numerical value. It may
be anything from a single \W{constant} to a bracketed calculation of
\W{variable}, \W{property} or \W{array} values, such as
|3+(day_list-->(calendar.number))|.
\E{fake action}%
A form of \W{action} which has no corresponding \W{action routine} and will
have no effect after the |before|-processing stage of considering an action
is over. A fake action is never generated by the \W{parser} and can only be
triggered by a |<|...|>| statement. The \W{library} makes use of this but
other Inform code is advised not to.
\E{fake fake action}%
A form of \W{action} which does have an \W{action routine} and is processed
exactly as ordinary actions are, but which is never generated by the
\W{parser}, only by the program, which can use it to pass a message to an
\W{object}.
\E{fatal error}%
An \W{error} found by the \W{compiler} which causes it to give up immediately;
for instance, a disc being full or memory running out are fatal.
\E{format}%
See \W{version}.
\E{function}%
See \W{routine}.
\E{fuse}%
See \W{timer}.
\E{global variable}%
A variable which can be used by every routine in the program.
\E{grammar}%
A list of \W{lines} which is attached to a particular \W{verb}. The \W{parser}
decodes what the \W{player} has typed by trying to match it against each line
in turn of the grammar attached to the \W{verb} which the first word of the
player's input corresponds to.
\E{hardware function}%
A function which is used just like any other \W{routine} but which is
not defined anywhere in the \W{library} or \W{program}: the \W{compiler}
provides it automatically, usually converting the apparent call to a
routine into a single line of \W{assembly language}.
\E{importing}%
When compiling a \W{module}, Inform needs to be told of any global
variables it is using which are defined only in the outside program
(compiled on a different occasion). Such a variable is said to be
``imported'' using the |Import global| directive.
\E{indirect containment}%
See \W{object tree}.
\E{individual property}%
Opposite of \W{common property}.
\E{inheritance}%
The process in which \W{property} values and \W{attribute} settings specified
in a \W{class} definition are passed on to an \W{object} defined as having
that class.
\E{internal name}%
See \W{name}.
\E{interpreter}%
A program for some particular model of computer, for example the IBM PC, which
reads in the \W{story file} of a game and allows someone to play it. A
different interpreter is needed for each model of computer (though generic
source codes exist which make it relatively easy to produce these).
\E{inventory}%
1. Verb, imperative: a demand for a list of the items one is holding; 2.
noun: the list itself. (When Crowther and Woods were writing the original
^{`Advent'}, they were unable to think of a good imperative verb and fell
back on the barely sensible ``take inventory'', which was soon corrupted
into the not at all sensible ``inventory'', thence ``inv'' and finally
``i''.)
\E{library}%
The `operating system' for the \W{Z-machine}: a large segment of Inform
code, written out in three \W{library files}, which manages the model world,
provides the \W{parser} and consults the game's program now and then to
give it a chance to make interesting things happen.
\E{library files}%
The three files |parser|, |verblib| and |grammar| containing the source
code of the \W{library}. These are normally |Include|d in the code for
every Inform game.
\E{library routine}%
A \W{routine} provided by the \W{library} which is `open to the public'
in that the designer's program is allowed to call and make use of it.
\E{line}%
One possible pattern which the \W{parser} might match against what the
\W{player} has typed beyond the initial \W{verb} word. A \W{grammar} line
consists of a sequence of \W{tokens}, each of which must be matched
in sequence, plus an \W{action} which will be generated if the line
successfully matches.
\E{linking}%
The process of assimilating a previously-compiled \W{module} into the
game now being compiled, in order to save compilation time.
\E{local variable}%
A variable attached to a particular \W{routine} (or, more precisely,
a particular call to a routine: if a routine calls itself, then the parent
and child incarnation have independent copies of the local variables) whose
value is inaccessible to the rest of the program. Also used to hold the
\W{arguments} of the call.
\E{long}%
A \W{property} whose values must always be stored as \W{words}, or
\W{word arrays}, rather than \W{bytes} or \W{byte arrays}. A safely
ignorable concept since except for \W{Standard games} all properties are
long.
\E{logical machine}%
See \W{Z-machine}.
\E{low string}%
A string which can be used as the value of a \W{variable string}, printed
with the |@| escape character. Must be declared with |Lowstring|.
\E{map}%
The geographical design of the game, divided into areas called \W{rooms}
with connections between them in different directions. The \W{story file}
doesn't contain an explicit map table but stores the information implicitly
in the definition of the room \W{objects}.
\E{memory map}%
Internally, the \W{Z-machine} contains a large \W{array} in whose values
the entire story file and all its data structures are stored. Particular
cells low down in this array are indexed by \W{byte addresses}, and
\W{routines} and \W{strings} which are lodged higher up are referred to by
\W{packed addresses}. The organisation of this array (which ranges of
indices correspond to what) is called the memory map.
\E{message}%
A way to communicate with an \W{object}, specifying the object to call,
the \W{property} being addressed (in effect, the ``kind of message being
sent'') and possibly other parameters. A single value is returned as
a reply.
\E{metaclass}%
There are four fundamental \W{classes} of \W{object}, such that every object
belongs to exactly one of the four. These are |Object|, |Class|, |Routine|
and |String|, and are called metaclasses. (Since they are examples of
classes, they themselves have metaclass |Class|.)
\E{meta-verb}%
A \W{verb} whose actions are always commands from the \W{player} to the game,
rather than requests for something to happen in the model world: for
instance, ``quit'' is meta but ``take'' is not.
\E{module}%
A previously-compiled but incomplete segment of game, which is kept in
order for it to be \W{linked} into a later compilation. It can be
linked many times once created, saving much compilation time. (For
example, almost the whole Library can be reduced to two modules.)
\E{multiple object}%
The \W{parser} matches a \W{token} with a multiple object when the \W{player}
has either explicitly referred to more than one \W{object} (e.g. ``drop
lamp and basket'') or implicitly done so (e.g. ``drop everything'' when
this amounts to more than 1 item); though the match is only made if the
token will allow it.
\E{names}%
An \W{object} has three kinds of name: 1. its internal name, a word such
as |brass_lamp|, which is a \W{constant} referring to it within the program;
2. its short name, such as ``dusty old brass lamp'' or ``Twopit Room'',
which is printed in \W{inventories} or before a \W{room description}; 3.
\W{dictionary words} which appear as values of its |name| property, such
as |"dusty"|, |"brass"|, etc., which the \W{player} can type to refer to it.
\E{noun}%
The first parameter (usually an \W{object} but possibly a number) which
the \W{parser} has matched in a \W{line} of \W{grammar} is the noun for
the \W{action} which is generated. It is stored in the |noun| variable
(not to be confused with the |noun| token).
\E{object}%
1. The physical substance of the game's world is divided up into indivisible
objects, such as `a brass lamp' or `a meadow'. These contain each other
in a hierarchy called the \W{object tree}. An object may be defined with an
initial location (another object) and must have an \W{internal name} and
a \W{short name}; attached to it throughout the game are variables called
\W{attributes} and \W{properties} which reflect its current state. The
definition of an object may make it \W{inherit} initial settings for this
state from one or more \W{classes}. 2. More generally, classes themselves
and even \W{routines} and \W{strings} are abstractly considered objects.
Objects in sense (1) above, ``concrete objects'', are members of the
\W{metaclass} |Object|, while classes belong to |Class|, routines to
|Routine| and strings to |String|.
\E{object number}%
\W{Objects} are automatically numbered from 1 upwards, in order of
definition, and the \W{internal name} of an object is in fact a \W{constant}
whose value is this number.
\E{object tree}%
The hierarchy of containment between \W{objects} of ^{metaclass} |Object|,
i.e., of concretely existing objects. Each has a `parent',
though this may be `nothing' (to indicate that it is uncontained, as for
instance \W{rooms} are) and possibly some `children' (the objects directly
contained within it). The `child' of an object is the `eldest' of these
children, the one most recently moved within it or, if none have been moved
into it since the start of play, the first one defined as within it. The
`sibling' of this child is then the next eldest, or may be `nothing' if
there is no next eldest. Note that if $A$ is inside $B$ which is itself
inside $C$, then $C$ `directly contains' $B$ but only `indirectly
contains' $A$: and we do not call $A$ one of the children of $C$.
\E{obsolete usage}%
A point in the program using Inform syntax which was correct under some
previous version of the \W{compiler} but is no longer correct (usually
because there is a neater way to express the same idea). Inform often
allows these but, if so, issues \W{warnings}.
\E{opcodes}%
See \W{assembly language}.
\E{operator}%
A symbol in an \W{expression} which acts on one or more sub-expressions,
combining their values to produce a result. This may be arithmetic, as
in $+$ or $/$, or to do with array or property value indexing, as in
|->| or |.&|. Note that \W{condition} operators such as |==| are not
formally expression operators.
\E{order}%
An instruction by the \W{player} for somebody else to do something. For
instance, ``policeman, give me your hat'' is an order. The order is
parsed as if an \W{action} but is then processed in the other person's
\W{object} definition.
\E{packed address}%
A number encoding the location of a \W{routine} or \W{string} within
the \W{memory map} of the \W{Z-machine}.
\E{parent}%
See \W{object tree}.
\E{parser}%
That part of the \W{library} which, once per turn, issues the \W{prompt};
asks the \W{player} to type something; looks at the initial \W{verb} word; tries
to match the remaining words against one of the \W{lines} of \W{grammar} for
this verb and, if successful, generates the resulting \W{action}.
\E{player}%
1. the person sitting at the keyboard at \W{run-time}, who is playing
the game; 2. his character inside the model world of the game. (There is an
important difference - one has access to the ``undo'' verb. The other
actually dies.)
\E{private property}%
See \W{encapsulation}.
\E{prompt}%
The text printed to invite the \W{player} to type: usually just |>|.
\E{property}%
1. The value of a variable attached to a particular \W{object}, accessible
throughout the program, which can be a single \W{word}, an \W{embedded
routine} or an \W{array} of values; 2. a named class of such variables,
such as |description|, which may or may not be \W{provided} by any given
object. Properties can be \W{encapsulated} for privacy. All properties
are either \W{common} or \W{individual} (the latter unless otherwise
declared).
\E{provision}%
If a \W{property}, such as |description|, is given in the definition of
an \W{object} (or in the definition of a \W{class} which the object belongs
to) then the object is said to ``provide'' that property.
\E{resolution}%
See \W{dictionary}.
\E{return value}%
See \W{routine}.
\E{room}%
The geography of a game is subdivided into parcels of area called rooms,
within which it is (usually) assumed that the \W{player} has no particular
location but can reach all corners of easily and without giving explicit
instruction to do so. For instance, ``the summit of Scafell Pike'' might be
such an area, while ``the summit of Ben Nevis'' (being a large L-shaped
ridge) would probably be divided into three or four. These rooms fit
together into the \W{map} and each is implemented as an \W{object}.
\E{room description}%
See \W{description}.
\E{routine}%
An Inform program is always executed in routines, each of which is ``called''
(possibly with \W{arguments}) and must return a particular \W{word} value,
though this is sometimes disguised from the programmer because (for example)
the \W{statement} |return;| actually returns |true| (1) and the statement
|ExplodeBomb();| makes the call to the routine but throws away the return
value subsequently. Routines are permitted to call themselves (if the
programmer wants to risk it) and have their own \W{local variables}.
Calling a routine is analogous to sending a \W{message} to an \W{object},
and indeed routines are abstractly considered objects in their own right,
belonging to \W{metaclass} |Routine|.
\E{rule}%
\W{Embedded routines} given as values of a \W{property} like |before| or
|after| are sometimes loosely called rules, because they encode exceptional
rules of the game such as ``the 10-ton weight cannot be picked up''.
However, there is no formal concept of `rule'.
\E{run-time}%
The time when an \W{interpreter} is running the \W{story file}, i.e., when
someone is actually playing the game, as distinct from `compile-time' (when
the \W{compiler} is at work making the story file). Some errors (such as
an attempt to divide a number by zero) can only be detected at run-time.
\E{scope}%
To say that an \W{object} is in scope to a particular \W{actor} is
roughly to say that it is visible, and can sensibly be referred to.
\E{second noun}%
The second parameter (usually an \W{object} but possibly a number) which the
\W{parser} has matched in a \W{line} of \W{grammar} is the second noun for
the \W{action} generated. It is stored in the |second| variable.
\E{see-through}%
An \W{object} is called this if it has |transparent|, or is an open
|container|, or is a |supporter|. Roughly this means `if the object is
visible, then its \W{children} are visible'. (This criterion is often
applied in the \W{scope} (and `light') rules inside the \W{library}.)
\E{sender}%
When a \W{message} is sent from one \W{object} to another, the originator
is called the ``sender''. Whenever a message is being received, the
variable |sender| holds this object's identity.
\E{short name}%
See \W{name}.
\E{sibling}%
See \W{object tree}.
\E{statement}%
A single instruction for the game to carry out at \W{run-time}; a
\W{routine} is a collection of statements. These include \W{assignments}
and \W{assembly language} but not \W{directives}.
\E{status line}%
The region at the top of the screen which, in play, usually shows the
current score and location, and which is usually printed in reversed colours
for contrast.
\E{story file}%
The output of the \W{compiler} is a single file containing everything about
the game produced, in a \W{format} which is standard. To be played, the
file must be run with an \W{interpreter}. Thus only one file is needed for
every Inform game created, and only one auxiliary program must be written
for every model of computer which is to run such games. In this way
story files are absolutely portable across different computers.
\E{Standard game}%
An old \W{format} (version 3) of \W{story file} which should no longer be
used unless absolutely necessary (to run on very small computers) since it
imposes tiresome restrictions.
\E{string}%
1. a literal piece of text such as |"Mary had a fox"| (which is a
\W{constant} internally represented by a number, its \W{packed address},
and may be created as a \W{low string}), abstractly considered an \W{object}
of \W{metaclass} |String|; 2. a form of \W{byte array} in
which the 0th entry holds the number of entries (so called because such an
array is usually used as a list of \W{characters}, i.e. a string variable);
3. see \W{variable string}.
\E{switch}%
1. certain \W{objects} are `switchable', meaning they can be turned off or
on by the \W{player}; 2. options set by the programmer when the \W{compiler}
starts are called switches; 3. a |switch| \W{statement} is one which
switches execution, like a railway turntable, between different lines
according to the current value of an \W{expression}.
\E{synonym}%
Two or more words which refer to the same \W{verb} are called synonyms (for
example, ``wear'' and ``don'').
\E{table}%
A form of \W{word array} in which the 0th entry holds the number of entries.
\E{timer}%
A \W{routine} attached to a particular \W{object} which, once set, will be
run after a certain number of \W{turns} have passed by. (Sometimes called
a `fuse'.)
\E{token}%
A particle in a \W{line} of \W{grammar}, which the \W{parser} tries
to match with one or more words from what the \W{player} has typed. For
instance, the token |held| can only be matched by an \W{object} the
\W{actor} is holding.
\E{tree}%
See \W{object tree}.
\E{turn}%
The period in play between one typed command and another.
\E{untypeable word}%
A \W{dictionary word} which contains at least one space, full stop or
comma and therefore can never be recognised by the \W{parser} as one of the
words typed by the \W{player}.
\E{variable}%
A named value which can be set or compared so that it varies at \W{run-time}.
It must be declared before use (the \W{library} declares many such).
Variables are either \W{local} or \W{global}; entries in \W{arrays} (or the
\W{memory map}) and \W{properties} of \W{objects} behave like global
variables.
\E{variable string}%
(Not the same as a \W{string} (3) variable.) There are 32 of these, which
can only be set (to a \W{string} (1) which must have been defined as a
\W{low string}) or printed out (using the |@| escape character).
\E{vehicle}%
An \W{object} which the \W{player} character can travel around in.
\E{verb}%
1. a collection of \W{synonymous} one-word English verbs for which the
\W{parser} has a \W{grammar} of possible \W{lines} which a command starting
with one of these verbs might take; 2. one of the one-word English verbs.
\E{version}%
The \W{compiler} can produce 6 different formats of \W{story file}, from
Version 3 (or \W{Standard}) to Version 8. By default it produces Version 5
(or \W{Advanced}) which is the most portable.
\E{warning}%
When the \W{compiler} finds something in the program which it disapproves
of (for example, an \W{obsolete usage}) or thinks might be a mistake, it
issues a warning message. This resembles an \W{error} but does not prevent
successful compilation; a working \W{story file} can still be produced.
\E{window}%
(Except in \W{Standard games}) the screen is divided into two windows, an
upper, fixed window usually containing the \W{status line} and the lower,
scrolling window usually holding the text of the game. One can divert
printing to the upper window and move a \W{cursor} about in it.
\E{word}%
1. an English word in the game's \W{dictionary}; 2. almost all numbers are
stored in 16-bit words of memory which unlike \W{bytes} can hold any
\W{constant} value, though they take twice as much storage space up.
\E{word array}%
An \W{array} indexed with the |-->| \W{operator} whose entries are
\W{words}: they can therefore hold any \W{constant} values.
\E{youngest child}%
See \W{object tree}.
\E{Z-machine}%
The imaginary computer which the \W{story file} is a program for. One
romantically pretends that this is built from circuitboards and microchips
(using terms like `hardware') though in fact it is merely simulated at
\W{run-time} by an \W{interpreter} running on some (much more sophisticated)
computer. Z is for `Zork'.
\tenpoint
\vfill\eject\lexiconfalse\mark{1}
\immediate\closeout\ans
\answerstrue
\sectionx{Answers to all the exercises}
\outer\def\ansno #1:{\medbreak
\noindent\llap{$\bullet$\rm\kern.15em}%
{\ninebf \bf #1}\mark{#1}\quad}
\poem
World is crazier and more of it than we think,
Incorrigibly plural. I peel and portion
A tangerine and spit the pips and feel
The drunkenness of things being various.
\poemby{^{Louis MacNeice} ({\oldstyle1907}--{\oldstyle1963})}{Snow}
\ninepoint
\ansno1:
{^^{exercises: mushroom picking}
Change the mushroom's |after| rule to:
\beginstt
after
[; Take: if (self hasnt general)
{ give self general;
"You pick the mushroom, neatly cleaving its thin stalk.";
}
"You pick up the slowly-disintegrating mushroom.";
Drop: "The mushroom drops to the ground, battered slightly.";
],
\endtt
As mentioned above, |general| is a general-purpose attribute, free for the
designer to use. The `neatly cleaving' message can only happen once, because
after that the mushroom object must have |general|. Note that the mushroom
is allowed to call itself |self| instead of |mushroom|.}
\ansno2:
{^^{exercises: opening medicine bottle}
\beginlines
|Object medicine "guaranteed child-proof medicine bottle" cupboard|
| with name "medicine" "bottle",|
| description "~Antidote only: no preventative effect.~",|
| openup|
| [; give self open ~locked; "The bottle cracks open!";|
| ],|
| has container openable locked;|
\endlines
Any other code in the game can send the message |medicine.openup()|
to crack open the bottle. For brevity, this solution assumes that
the bottle is always visible to the player when it is opened -- if not
the printed message will be incongruous.}
\ansno3:
{^^{exercises: before on second noun}
Briefly: provide a |GamePreRoutine| which tests to see if
|second| is an object, rather than |nothing| or a number. If it is,
check whether the object has a |second_before| rule (i.e. test the
condition |(object provides second_before)|). If it has, send the
|second_before| message to it, and return the reply as the return
value from |GamePreRoutine|.}
\ansno4:
{Put any validation rules desired into the |GamePreRoutine|.
For example, the following will filter out any stray |Drop| actions for
unheld objects:^^{actions: validation (exercise)}
^^{exercises: action validation}
\beginstt
[ GamePreRoutine;
if (action==Drop && noun notin player)
"You aren't holding ", (the) noun, ".";
rfalse;
];
\endtt}
\ansno5:
{^^{orange cloud}^^{exercises: orange cloud surrounding player}
\beginlines
|Object orange_cloud "orange cloud"|
| with name "orange" "cloud",|
| react_before|
| [; Look: "You can't see for the orange cloud surrounding you.";|
| Go, Exit: "You wander round in circles, choking.";|
| Smell: if (noun==0) "Cinnamon? No, nutmeg.";|
| ],|
| has scenery;|
\endlines}
\ansno6:
{^^{exercises: Mayan directions}
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 scenery;|
\endlines^^{world colours}^^{Mayan directions}^^{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| called |white_to| to be
|n_to|, and then enter map directions in the source code using
Mayan direction 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}
\ansno7:
{^^{reflecting the map}^^{exercises: reflecting the map east-west}
\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}
\ansno8:
{^^{exercises: exchanging ``east''/``west''}
This is a prime candidate for using ^{variable strings}
^|@nn|. 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.)}
\ansno9:
{^^{toothed bag}^^{acquisitive bag}^^{exercises: acquisitive bag}
\beginlines
|Object -> bag "toothed bag"|
| 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:|
| "The bag wriggles hideously as it swallows ",|
| (the) noun, ".";|
| ],|
| has container open;|
\endlines}
\ansno10:
{^^{exercises: television set}
\beginlines
|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;|
|Object -> power_button "power button"|
| with name "power" "button" "switch",|
| after|
| [; SwitchOn, SwitchOff: <<Examine screen>>;|
| ],|
| has switchable;|
|Object -> 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^^{Japanese cartoon}^^{television set}^^{Manga}^^{cartoon}}
\ansno11:
{\beginlines
|Object -> glass_box "glass box with a lid"|
| with name "glass" "box" "with" "lid"|
| has container transparent openable open;|
|Object -> steel_box "steel box with a lid"|
| with name "steel" "box" "with" "lid"|
| has container openable open;|
\endlines^^{exercises: glass and steel boxes}}
\ansno12:
{^^{macram\'e bag}^^{exercises: macram\'e bag}
(The |describe| part of this answer but is only decoration.) Note the
careful use of |inp1| and |inp2| rather than |noun| or |second|:
see the note at the end of \S 9.
\beginlines
|Object -> macrame_bag "macrame bag"|
| with name "macrame" "bag" "string" "net" "sack",|
| react_before|
| [; Examine, Search, Listen, Smell: ;|
| default:|
| if (inp1>1 && inp1 in self)|
| print_ret (The) inp1, " is tucked away in the bag.";|
| if (inp2>1 && inp2 in self)|
| print_ret (The) inp2, " is tucked away in the bag.";|
| ],|
| describe|
| [; print "^A macrame bag hangs from the ceiling, shut tight";|
| if (child(self)==0) ".";|
| print ". Inside you can make out ";|
| WriteListFrom(child(self), ENGLISH_BIT); ".";|
| ],|
| has container transparent;|
|Object -> -> "gold watch"|
| with name "gold" "watch",|
| description "The watch has no hands, oddly.",|
| react_before|
| [; Listen: if (noun==0 or self) "The watch ticks loudly."; ];|
\endlines}
\ansno13:
{^^{plank bridge}^^{bridge which collapses}
^^{exercises: plank bridge}The
``plank breaking'' rule is implemented here in its |door_to| routine.
Note that this returns `true' after killing the player.
\beginlines
|Object -> PlankBridge "plank bridge"|
| with description "Extremely fragile and precarious.",|
| name "precarious" "fragile" "wooden" "plank" "bridge",|
| when_open|
| "A precarious plank bridge spans the chasm.",|
| door_to|
| [; if (children(player)~=0)|
| { deadflag=1;|
| "You step gingerly across the plank, which bows under|
| your weight. But your meagre possessions are the straw|
| which breaks the camel's back! There is a horrid crack...";|
| }|
| print "You step gingerly across the plank, grateful that|
| you're not burdened.^";|
| if (location==NearSide) return FarSide; return NearSide;|
| ],|
| door_dir|
| [; if (location==NearSide) return s_to; return n_to;|
| ],|
| found_in NearSide FarSide,|
| has static door open;|
\endlines
There might be a problem with this solution if your game also contained
a character who wandered about, and whose code was clever enough to run
|door_to| routines for any |door|s it ran into. If so, |door_to| could
perhaps be modified to check that the |actor| is the |player|.}
\ansno14:
{^^{`Ruins'}^^{exercises: cage to open and enter}
\beginlines
|Object -> cage "iron cage"|
| with name "iron" "cage" "bars" "barred" "iron-barred",|
| when_open|
| "An iron-barred cage, large enough to stoop over inside,|
| looms ominously here.",|
| when_closed "The iron cage is closed.",|
| inside_description "You stare out through the bars.",|
| has enterable container openable open transparent static;|
\endlines}
\ansno15:
{^^{exercises: car that won't go east}
Change the car's |before| to
\beginlines
| before|
| [; Go: if (noun==e_obj)|
| { print "The car will never fit through your front door.^";|
| return 2;|
| }|
| if (car has on) "Brmm! Brmm!";|
| print "(The ignition is off at the moment.)^";|
| ],|
\endlines^^{little red car}}
\ansno16:
{^^{pumice ball}^^{eight-foot pumice ball}^^{ball of pumice}
^^{`Ruins'}^^{exercises: pushing pumice ball uphill}
Insert these lines into the |before| rule for |PushDir|:
\beginlines
| if (second==u_obj) <<PushDir self n_obj>>;|
| if (second==d_obj) <<PushDir self s_obj>>;|
\endlines}
\ansno17:
{^^{William Tyndale}^^{New Testament}^^{four Gospels}^^{Bible}
^^{exercises: Tyndale's Bible}
\beginlines
|Object -> bible "black Tyndale Bible"|
| with name "bible" "black" "book",|
| initial "A black Bible rests on a spread-eagle lectern.",|
| description "A splendid foot-high Bible, which must have survived|
| the burnings of 1520.",|
| before|
| [ w x; Consult:|
| wn = consult_from; w = NextWord();|
| switch(w)|
| { 'matthew': x="Gospel of St Matthew";|
| 'mark': x="Gospel of St Mark";|
| 'luke': x="Gospel of St Luke";|
| 'john': x="Gospel of St John";|
| default: "There are only the four Gospels.";|
| }|
| if (consult_words==1)|
| "You read the ", (string) x, " right through.";|
| w = TryNumber(wn);|
| if (w==-1000)|
| "I was expecting a chapter number in the ",|
| (string) x, ".";|
| "Chapter ", (number) w, " of the ", (string) x,|
| " is too sacred for you to understand now.";|
| ];|
\endlines}
\ansno18:
{^^{exercises: bearded psychiatrist}
Note that whether reacting before or after, the psychiatrist
does not cut any actions short, because |react_before| and
|react_after| both return false.
\beginlines
|Object -> psychiatrist "bearded psychiatrist"|
| with name "bearded" "doctor" "psychiatrist" "psychologist" "shrink",|
| initial "A bearded psychiatrist has you under observation.",|
| life|
| [; "He is fascinated by your behaviour, but makes no attempt to|
| interfere with it.";|
| ],|
| react_after|
| [; Insert: print "~Subject puts ", (name) noun, " in ",|
| (name) second, ". Interesting.~^^";|
| Look: print "~Pretend I'm not here,~ says the psychiatrist.^";|
| ],|
| react_before|
| [; Take, Remove: print "~Subject feels lack of ", (the) noun,|
| ". Suppressed Oedipal complex? Mmm.~^";|
| ],|
| has animate;|
\endlines}
\ansno19:
{^^{removing conversation actions}
^^{exercises: removing conversation actions}
Add the following lines, after the inclusion of |Grammar|:
\beginlines
|[ SayInsteadSub; "[To talk to someone, please type ~someone, something~|
|or else ~ask someone about something~.]"; ];|
|Extend "answer" replace * topic -> SayInstead;|
|Extend "tell" replace * topic -> SayInstead;|
\endlines
A slight snag is that this will throw out ``nigel,
tell me about the grunfeld defence'' (which the library will normally
convert to an |Ask| action, but can't if the grammar for ``tell'' is
missing). To avoid this, you could (instead of making the above
directives) |Replace| the |TellSub| routine (see \S 21)
by the |SayInsteadSub| one.}
\ansno20:
{^^{`Starcross'}^^{computer (voice-activated)}
^^{exercises: computer (voice-activated)}
There are several ways to do this. The easiest is to add more grammar
to the parser and let it do the hard work:
\beginstt
Object -> computer "computer"
with name "computer",
orders
[; Theta: print_ret "~Theta now set to ", noun, ".~";
default: print_ret "~Please rephrase.~";
],
has talkable;
..
[ ThetaSub; "You must tell your computer so."; ];
Verb "theta" * "is" number -> Theta;
\endtt}
\ansno21:
{^^{Simon Says}^^{Charlotte's game}^^{girl playing Simon Says}
^^{exercises: Charlotte playing Simon Says}
Obviously, a slightly wider repertoire of actions might be a good idea,
but:
\beginlines
|Object -> Charlotte "Charlotte"|
| with name "charlotte" "charlie" "chas",|
| grammar|
| [; give self ~general;|
| wn=verb_wordnum;|
| if (NextWord()=='simon' && NextWord()=='says')|
| { give self general;|
| verb_wordnum=verb_wordnum+2;|
| }|
| ],|
| orders|
| [ i; if (self hasnt general) "Charlotte sticks her tongue out.";|
| WaveHands: "Charlotte waves energetically.";|
| default: "~Don't know how,~ says Charlotte.";|
| ],|
| initial "Charlotte wants to play Simon Says.",|
| has animate female proper;|
\endlines
(The variable |i| isn't needed yet, but will be used by the
code added in the answer to the next exercise.)}
\ansno22:
{^^{clapping game}^^{exercises: Charlotte's clapping game}
First add a |Clap| verb (this is easy). Then
give Charlotte a |number| property (initially 0, say) and add
these three lines to the end of Charlotte's |grammar| routine:
\beginlines
| self.number=TryNumber(verb_wordnum);|
| if (self.number~=-1000)|
| { action=##Clap; noun=0; second=0; rtrue; }|
\endlines
Her |orders| routine now needs a local variable called |i|, and
the new clause:
\beginlines
| Clap: if (self.number==0) "Charlotte folds her arms.";|
| for (i=0:i<self.number:i++)|
| { print "Clap! ";|
| if (i==100)|
| print "(You must be regretting this by now.) ";|
| if (i==200)|
| print "(What a determined girl she is.) ";|
| }|
| if (self.number>100)|
| "^^Charlotte is a bit out of breath now.";|
| "^^~Easy!~ says Charlotte.";|
\endlines}
\ansno23:
{^^{exercises: Dyslexic Dan}
The interesting point here is that when the |grammar| property
finds the word ``take'', it accepts it and has to move |verb_wordnum|
on by one to signal that a word has been parsed succesfully.
\beginlines
|Object -> Dan "Dyslexic Dan"|
| with name "dan" "dyslexic",|
| grammar|
| [; if (verb_word == 'take') { verb_wordnum++; return 'drop'; }|
| if (verb_word == 'drop') { verb_wordnum++; return 'take'; }|
| ],|
| orders|
| [ i;|
| Take: "~What,~ says Dan, ~ you want me to take ",|
| (the) noun, "?~";|
| Drop: "~What,~ says Dan, ~ you want me to drop ",|
| (the) noun, "?~";|
| Inv: "~That I can do,~ says Dan. ~I'm empty-handed.~";|
| No: "~Right you be then.~";|
| Yes: "~I'll be having to think about that.~";|
| default: "~Don't know how,~ says Dan.";|
| ],|
| initial "Dyslexic Dan is here.",|
| has animate proper;|
\endlines^^{Dyslexic Dan}}
\ansno24:
{^^{exercises: extensions for one actor only}
Suppose Dan's grammar (but nobody else's) for the ``examine''
verb is to be extended. His grammar routine should also contain:
\beginlines
| if (verb_word == 'examine' or 'x')|
| { verb_wordnum++; return -'danx,'; }|
\endlines^^{extensions for one actor only}^^{cow pie}
(Note the crudity of this: it looks at the actual verb word, so you
have to check any synonyms yourself.) The verb ``danx,'' must be
declared later:
\beginlines
|Verb "danx," * "conscience" -> Inv;|
\endlines
and now ``Dan, examine conscience'' will send him an |Inv| order:
but ``Dan, examine cow pie'' will still send |Examine cow_pie| as usual.}
\ansno25:
{^^{alarm clock}^^{exercises: alarm clock}
\beginlines
|[ PrintTime x; print (x/60), ":", (x%60)/10, (x%60)%10; ];|
|Object -> alarm_clock "alarm clock"|
| with name "alarm" "clock",|
| number 480,|
| description|
| [; print "The alarm is ";|
| if (self has general) print "on, "; else print "off, but ";|
| "the clock reads ", (PrintTime) the_time,|
| " and the alarm is set for ", (PrintTime) self.number, ".";|
| ],|
| react_after|
| [; Inv: if (self in player) { new_line; <<Examine self>>; }|
| Look: if (self in location) { new_line; <<Examine self>>; }|
| ],|
| daemon|
| [; if (the_time >= self.number && the_time <= self.number+3|
| && self has general) "^Beep! Beep! The alarm goes off.";|
| ],|
| grammar [; return 'alarm,'; ],|
| orders|
| [; SwitchOn: give self general; StartDaemon(self); "~Alarm set.~";|
| SwitchOff: give self ~general; StopDaemon(self); "~Alarm off.~";|
| SetTo: self.number=noun; <<Examine self>>;|
| default: "~Commands are on, off or a time of day only, pliz.~";|
| ],|
| life|
| [; Ask, Answer, Tell:|
| "[Try ~clock, something~ to address the clock.]";|
| ],|
| has talkable;|
\endlines
and add a new verb to the grammar:
\beginlines
|Verb "alarm," * "on" -> SwitchOn|
| * "off" -> SwitchOff|
| * TimeOfDay -> SetTo;|
\endlines
(using the \cstok{TimeOfDay} token from the exercises of \S 27). Note
that since the word ``alarm,'' can't be matched by anything the player types,
this verb is concealed from ordinary grammar. The orders we produce here
are not used in the ordinary way (for instance, the action |SwitchOn| with
no |noun| or |second| would never ordinarily be produced by the parser) but this
doesn't matter: it only matters that the grammar and the |orders| property
agree with each other.}
\ansno26:
{^^{Star Trek: The Next Generation}^^{tricorder}
^^{exercises: tricorder}
\beginlines
|Object -> tricorder "tricorder"|
| with name "tricorder",|
| grammar [; return 'tc,'; ],|
| orders|
| [; Examine: if (noun==player) "~You radiate life signs.~";|
| print "~", (The) noun, " radiates ";|
| if (noun hasnt animate) print "no ";|
| "life signs.~";|
| default: "The tricorder bleeps.";|
| ],|
| life|
| [; Ask, Answer, Tell: "The tricorder is too simple.";|
| ],|
| has talkable;|
|...|
|Verb "tc," * noun -> Examine;|
\endlines}
\ansno27:
{^^{Star Trek: The Next Generation}^^{replicator}
^^{exercises: replicator}
\beginlines
|Object replicator "replicator"|
| with name "replicator",|
| grammar [; return 'rc,'; ],|
| orders|
| [; Give:|
| if (noun in self)|
| "The replicator serves up a cup of ",|
| (name) noun, " which you drink eagerly.";|
| "~That is not something I can replicate.~";|
| default: "The replicator is unable to oblige.";|
| ],|
| life|
| [; Ask, Answer, Tell: "The replicator has no conversation skill.";|
| ],|
| has talkable;|
|Object -> "Earl Grey tea" with name "earl" "grey" "tea";|
|Object -> "Aldebaran brandy" with name "aldebaran" "brandy";|
|Object -> "distilled water" with name "distilled" "water";|
|...|
|Verb "rc," * held -> Give;|
\endlines
The point to note here is that the \cstok{held} token means `held by the
replicator' here, as the |actor| is the replicator, so this is a neat way of
getting a `one of the following phrases' token into the grammar.}
\ansno28:
{^^{Star Trek: The Next Generation}^^{communications badge}
^^{exercises: communications badge}
This is similar to the previous exercises. One creates an attribute called
|crewmember| and gives it to the crew objects: the |orders| property is
\beginlines
| orders|
| [; Examine:|
| if (parent(noun)==0)|
| "~", (name) noun,|
| " is no longer aboard this demonstration game.~";|
| "~", (name) noun, " is in ", (name) parent(noun), ".~";|
| default: "The computer's only really good for locating the crew.";|
| ],|
\endlines
and the |grammar| simply returns |'stc,'| which is defined as
\beginlines
|[ Crew i;|
| switch(scope_stage)|
| { 1: rfalse;|
| 2: objectloop (i has crewmember) PlaceInScope(i); rtrue;|
| }|
|];|
|Verb "stc," * "where" "is" scope=Crew -> Examine;|
\endlines
An interesting point is that the scope routine doesn't need to do anything
at stage 3 (usually used for printing out errors) because the normal
error-message printing system is never reached. Something like ``computer,
where is Comminder Doto'' causes a |##NotUnderstood| order.}
\ansno29:
{^^{Zen}^^{flight computer}^^{Blake's 7}
^^{exercises: Zen flight computer}
\beginlines
|Object Zen "Zen" Flight_Deck|
| with name "zen" "flight" "computer",|
| initial "Square lights flicker unpredictably across a hexagonal|
| fascia on one wall, indicating that Zen is on-line.",|
| grammar [; return -'zen,'; ],|
| orders|
| [; Show: "The main screen shows a starfield,|
| turning through ", noun, " degrees.";|
| Go: "~Confirmed.~ The ship turns to a new bearing.";|
| SetTo: if (noun==0) "~Confirmed.~ The ship comes to a stop.";|
| if (noun>12) "~Standard by ", (number) noun,|
| " exceeds design tolerances.~";|
| "~Confirmed.~ The ship's engines step to|
| standard by ", (number) noun, ".";|
| Take: if (noun~=force_wall) "~Please clarify.~";|
| "~Force wall raised.~";|
| Drop: if (noun~=blasters) "~Please clarify.~";|
| "~Battle-computers on line.|
| Neutron blasters cleared for firing.~";|
| NotUnderstood: "~Language banks unable to decode.~";|
| default: "~Information. That function is unavailable.~";|
| ],|
| has talkable proper static;|
|Object -> force_wall "force wall" with name "force" "wall" "shields";|
|Object -> blasters "neutron blasters" with name "neutron" "blasters";|
|...|
|Verb "zen," * "scan" number "orbital" -> Show|
| * "set" "course" "for" Planet -> Go|
| * "speed" "standard" "by" number -> SetTo|
| * "raise" held -> Take|
| * "clear" held "for" "firing" -> Drop;|
\endlines
Dealing with |Ask|, |Answer| and |Tell| are left to the reader.}
\ansno30:
{^^{screen}^^{Starship Enterprise}^^{Captain Picard}^^{Noslen Maharg}
^^{Star Trek: The Next Generation}^^{Mrofni}^^{exercises: Picard and Maharg}
\beginstt
[ InScope;
if (action_to_be == ##Examine or ##Show or ##ShowR)
PlaceInScope(noslen_maharg);
if (scope_reason == TALKING_REASON)
PlaceInScope(noslen_maharg);
];
\endtt
Note that ^|ShowR| is a variant form of |Show| in which the parameters
are `the other way round': thus ``show maharg the phaser'' generates
|ShowR maharg phaser| internally, which is then converted to the more
usual |Show phaser maharg|.}
\ansno31:
{^^{telepathic contact}^^{Martha}^^{sealed room}^^{telekinesis}
^^{exercises: Martha the telepath}
Martha and the sealed room are defined as follows:
\beginlines
|Object sealed_room "Sealed Room"|
| with description|
| "I'm in a sealed room, like a squash court without a door,|
| maybe six or seven yards across",|
| has light;|
|Object -> ball "red ball" with name "red" "ball";|
|Object -> martha "Martha"|
| with name "martha",|
| orders|
| [ r; r=parent(self);|
| Give:|
| if (noun notin r) "~That's beyond my telekinesis.~";|
| if (noun==self) "~Teleportation's too hard for me.~";|
| move noun to player;|
| "~Here goes...~ and Martha's telekinetic talents|
| magically bring ", (the) noun, " to your hands.";|
| Look:|
| print "~", (string) r.description;|
| if (children(r)==1) ". There's nothing here but me.~";|
| print ". I can see ";|
| WriteListFrom(child(r),CONCEAL_BIT+ENGLISH_BIT);|
| ".~";|
| default: "~Afraid I can't help you there.~";|
| ],|
| life|
| [; Ask: "~You're on your own this time.~";|
| Tell: "Martha clucks sympathetically.";|
| Answer: "~I'll be darned,~ Martha replies.";|
| ],|
| has animate female concealed proper;|
\endlines
but the really interesting part is the ^|InScope| routine to fix
things up:
\beginlines
|[ InScope actor;|
| if (actor==martha) PlaceInScope(player);|
| if (actor==player && scope_reason==TALKING_REASON)|
| PlaceInScope(martha);|
| rfalse;|
|];|
\endlines
Note that since we want two-way communication, the player has to
be in scope to Martha too: otherwise Martha won't be able to
follow the command ``martha, give me the fish'', because ``me''
will refer to something beyond her scope.}
\ansno32:
{^^{exercises: troll afraid of the dark}
Just test if |HasLightSource(gift)==1|.}
\ansno33:
{^^{pet moth}^^{exercises: pet moth escapes in the dark}
We could solve this using a daemon, but for the
sake of demonstrating a feature of |thedark| we won't.
In |Initialise|, write |thedark.initial = GoMothGo;|
and add the routine:
\beginstt
[ GoMothGo;
if (moth in player)
{ remove moth;
"As your eyes try to adjust, you feel a ticklish sensation
and hear a tiny fluttering sound.";
}
];
\endtt}
\ansno34:
{^^{exercises: thief who wanders}
This is a crude implementation, for brevity (the real Zork
thief has an enormous stock of attached messages). A |life| routine
is omitted, and of course this particular thief steals
nothing. See ^{`The Thief'} for a much fuller,
annotated implementation.^^{thief in `Zork'}^^{gentleman thief}
\beginlines
|Object -> thief "thief"|
| with name "thief" "gentleman" "mahu" "modo",|
| 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 ofclass 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 ofclass 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;|
| }|
| }|
| ],|
| has animate;|
\endlines
(Not forgetting to |StartDaemon(thief)| at some point, for instance
in the game's |Initialise| routine.) So the thief walks at random but
never via 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. As for the |name|, note that `The ^{Prince of darkness} is
a gentleman. ^{Modo} he's called, and ^{Mahu}'
(^{William Shakespeare}, {\it King Lear} III iv).}
\ansno35:
{^^{exercises: weight--watching daemon}
We shall use a new property called |weight| and decide that
any object which doesn't provide any particular weight will weigh
10 units. Clearly, an object which contains other objects will
carry their weight too, so:
\beginlines
|[ WeightOf obj t i;|
| if (obj provides weight) t = obj.weight; else t = 10;|
| objectloop (i in obj) t = t + WeightOf(i);|
| return t;|
|];|
\endlines
Once every turn we shall check how much the player is carrying
and adjust a measure of the player's fatigue accordingly. There
are many ways we could choose to calculate this: for the sake of
example we'll define two constants:
\beginlines
|Constant CARRYING_STRENGTH = 500;|
|Constant HEAVINESS_THRESHOLD = 100;|
\endlines
Initially the player's strength will be the maximum possible,
which we'll set to 500. Each turn the amount of weight being
carried is substracted from this, but 100 is also added on
(without exceeding the maximum value). So if the player carries
more than 100 units, then her strength declines, but by dropping
things to get the weight below 100 she can allow it to recover.
If she drops absolutely everything, her entire strength will
recuperate in at most 5 turns. Exhaustion sets in if her strength
reaches 0, and at this point she is forced to drop something,
which gives her strength a slight boost. Anyway, here's an
implementation of all this:^^{fatigue daemon}
\beginlines
|Object weight_monitor|
| with players_strength,|
| warning_level 5,|
| activate|
| [; self.players_strength = CARRYING_STRENGTH; StartDaemon(self);|
| ],|
| daemon|
| [ w s b bw;|
| if (location ~= Weights_Room) { StopDaemon(self); return; }|
| s = self.players_strength|
| - WeightOf(player) + HEAVINESS_THRESHOLD;|
| if (s<0) s=0; if (s>CARRYING_STRENGTH) s=CARRYING_STRENGTH;|
| self.players_strength = s;|
| if (s==0)|
| { bw=-1;|
| objectloop(b in player)|
| if (WeightOf(b) > bw) { bw = WeightOf(b); w=b; }|
| self.players_strength = self.players_strength + bw;|
| print "^Exhausted with carrying so much, you decide |
| to discard ", (the) w, ": "; <<Drop w>>;|
| }|
| w=s/100; if (w==self.warning_level) return;|
| self.warning_level = w;|
| switch(w)|
| { 3: "^You are feeling a little tired.";|
| 2: "^You possessions are weighing you down.";|
| 1: "^Carrying so much weight is wearing you out.";|
| 0: "^You're nearly exhausted enough to drop everything|
| at an inconvenient moment.";|
| }|
| ];|
\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}.) Finally, of course, at some point
the weight monitor has to be sent an |activate| message to get things
going.}
\ansno36:
{^^{exercises: scuttling claws}See the next answer.}
\ansno37:
{^^{scuttling claws}^^{sound of scuttling claws}^^{`Ruins'}
\beginlines
|Object tiny_claws "sound of tiny claws" thedark|
| with article "the",|
| name "tiny" "claws" "sound" "of" "scuttling" "scuttle"|
| "things" "creatures" "monsters" "insects",|
| initial "Somewhere, tiny claws are scuttling.",|
| before|
| [; Listen: "How intelligent they sound, for mere insects.";|
| Touch, Taste: "You wouldn't want to. Really.";|
| Smell: "You can only smell your own fear.";|
| Attack: "They easily evade your flailing about in the dark.";|
| default: "The creatures evade you, chittering.";|
| ],|
| each_turn [; StartDaemon(self); ],|
| number 0,|
| daemon|
| [; if (location~=thedark) { self.number=0; StopDaemon(self); rtrue; }|
| switch(++(self.number))|
| { 1: "^The scuttling draws a little nearer, and your breathing|
| grows loud and hoarse.";|
| 2: "^The perspiration of terror runs off your brow. The|
| creatures are almost here!";|
| 3: "^You feel a tickling at your extremities and kick outward,|
| shaking something chitinous off. Their sound alone|
| is a menacing rasp.";|
| 4: deadflag=1;|
| "^Suddenly there is a tiny pain, of a hypodermic-sharp fang|
| at your calf. Almost at once your limbs go into spasm,|
| your shoulders and knee-joints lock, your tongue swells...";|
| }|
| ];|
\endlines}
\ansno38:
{^^{exercises: midnight}
Either set a daemon to watch for |the_time| suddenly dropping, or
put such a watch in the game's |TimePasses| routine.}
\ansno39:
{^^{sunrise and sunset}^^{daylight}^^{nightfall}^^{darkness: nightfall}
^^{light: daylight}^^{exercises: nightfall and daybreak}
A minimal solution is as follows:
\beginlines
|Constant SUNRISE 360; ! i.e., 6 am|
|Constant SUNSET 1140; ! i.e., 7 pm|
|Attribute outdoors; ! Give this to external locations|
|Attribute lit; ! And this to artificially lit ones|
|Global day_state = 2;|
|[ TimePasses f obj;|
| if (the_time >= SUNRISE && the_time < SUNSET) f=1;|
| if (day_state == f) rfalse;|
| objectloop (obj)|
| { if (obj has lit) give obj light;|
| if (obj has outdoors && obj hasnt lit)|
| { if (f==0) give obj ~light; else give obj light;|
| }|
| }|
| if (day_state==2) { day_state = f; return; }|
| day_state = f; if (location hasnt outdoors) return;|
| if (f==1) "^The sun rises, illuminating the landscape!";|
| "^As the sun sets, the landscape is plunged into darkness.";|
|];|
\endlines
In the |Initialise| routine, set the time (using |SetTime|)
and then call |TimePasses| to set all the |light| attributes
accordingly. Note that with this system, there's no need to
set |light| at all: that's automatic.}
\ansno40:
{^^{exercises: mid-air location}
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.^^{daemons: running order}}
\ansno41:
{^^{exercises: long time-scale game}
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.}
\ansno42:
{^^{exercises: player reacting before}
Two reasons. Firstly, there are times when we want to be able
to trap orders to other people, which |react_before| does not.
Secondly, the player's |react_before| rule is not necessarily
the first to react. In the case of the player's deafness, a ^{cuckoo}
may have already used |react_before| to sing. But it would have been
safe to use |GamePreRoutine|, if a little untidy (because a rule about
the player would not be part of the player's definition, which makes
for confusing source code). See \S 9 for the exact sequence of events
when actions are processed.}
\ansno43:
{^^{gas mask}^^{`Curses'}^^{silence, imposition on player}
^^{talking, preventing player from}^^{exercises: silencing player}
\beginlines
| orders|
| [; if (gasmask hasnt worn) rfalse;|
| if (actor==self && action~=##Answer or ##Tell or ##Ask) rfalse;|
| "Your speech is muffled into silence by the gas mask.";|
| ],|
\endlines}
\ansno44:
{^^{exercises: the player's wayhel}
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.",|
| orders|
| [; Go, Look, Examine, Eat, Smell, Taste, Touch: rfalse;|
| default: "Warthogs can't do anything as tricky as that!";|
| ],|
| has animate proper;|
\endlines^^{warthog}^^{nagual}
and we just |ChangePlayer(warthog);|. Note that the same |orders|
routine applies to the player-as-human typing ``warthog, listen''
as to the player-as-warthog typing just ``listen''.}
\ansno45:
{^^{Giant with a conscience}^^{exercises: Giant with conscience}
\beginlines
| orders|
| [; if (player==self)|
| { if (actor~=self)|
| "You only become tongue-tied and gabble.";|
| rfalse;|
| }|
| Attack: "The Giant looks at you with doleful eyes.|
| ~Me not be so bad!~";|
| default: "The Giant is unable to comprehend your instructions.";|
| ],|
\endlines}
\ansno46:
{^^{exercises: chessboard of rooms}
Give the ``^{chessboard}'' room a |short_name| routine (it probably
already has one, to print names like ``Chessboard d6'') and make it change
the short name to ``the gigantic Chessboard'' if and only if |action| is
currently set to |##Places|.}
\ansno47:
{^^{`Witness'}^^{prompt}^^{changing the prompt}^^{``What next?''}
^^{exercises: varying the prompt}
Put the following definition between inclusion of ``Parser'' and
``Verblib'':
\begintt
Object LibraryMessages
with before
[; Prompt: if (turns==1)
print "What should you, the detective, do now?^>";
else
print "What next?^>";
rtrue;
];
\endtt}
\ansno48:
{See the {\it Inform Translator's Manual}. One must provide
a new grammar file (generating the same actions but from different
syntax), tables showing how pronouns, possessives and articles work
in the new language, a sheaf of translated library messages and
so on. But it can be done.}
\ansno49:
{^^{accusative pronoun}^^{nominative pronoun}^^{pronouns}
^^{exercises: printing pronouns}Simply
define the following (for accusative, nominative and capitalised
nominative pronouns, respectively):
\beginlines
|[ PronounAcc i;|
| if (i hasnt animate) print "it";|
| else { if (i has female) print "her"; else print "him"; } ];|
|[ PronounNom i;|
| if (i hasnt animate) print "it";|
| else { if (i has female) print "she"; else print "he"; } ];|
|[ CPronounNom i;|
| if (i hasnt animate) print "It";|
| else { if (i has female) print "She"; else print "He"; } ];|
\endlines}
\ansno50:
{^^{ornate box}^^{exercises: ornate box (inventory inside)}
Use the |invent| routine to signal to |short_name|
and |article| routines to change their usual habits:
\beginlines
| invent|
| [; if (inventory_stage==1) give self general;|
| else give self ~general;|
| ],|
| short_name|
| [; if (self has general) { print "box"; rtrue; } ],|
| article|
| [; if (self has general) { print "that hateful"; rtrue; }|
| else print "a"; ],|
\endlines}
\ansno51:
{^^{exercises: very verbose mode}
This answer is cheating, as it needs to know about the library's
|lookmode| variable (set to 1 for normal, 2 for verbose or 3 for
superbrief). Simply include:
\beginlines
|[ TimePasses;|
| if (action~=##Look && lookmode==2) <Look>;|
|];|
\endlines^^{very verbose mode}}
\ansno52:
{^^{exercises: double inventory}
\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}}
\ansno53:
{^^{Scrabble pieces}^^{exercises: Scrabble pieces}
\beginlines
|Class Letter|
| with list_together|
| [; if (inventory_stage==1)|
| { print "the letters ";|
| if (~~(c_style & ENGLISH_BIT)) c_style = c_style + ENGLISH_BIT;|
| if (~~(c_style & NOARTICLE_BIT)) c_style = c_style + NOARTICLE_BIT;|
| if (c_style & NEWLINE_BIT) c_style = c_style - NEWLINE_BIT;|
| if (c_style & INDENT_BIT) c_style = c_style - INDENT_BIT;|
| }|
| else print " from a Scrabble set";|
| ],|
| short_name|
| [; if (listing_together ofclass Letter) rfalse;|
| print "letter ", (object) self, " from a Scrabble set"; rtrue;|
| ],|
| article "the";|
\endlines
and then as many letters as desired, along the lines of
\beginlines
|Letter -> "X" with name "x";|
\endlines}
\ansno54:
{^^{coins (listed together)}^^{three denominations of coin}
^^{exercises: three denominations of coin}
\beginlines
|Class Coin|
| with name "coin" "coins//p",|
| description "A round unstamped disc, presumably local currency.",|
| list_together "coins",|
| plural|
| [; print (string) (self.&name)-->0;|
| if (~~(listing_together ofclass Coin)) print " coins";|
| ],|
| short_name|
| [; if (listing_together ofclass Coin)|
| { print (string) (self.&name)-->0; rtrue; }|
| ],|
| article|
| [; if (listing_together ofclass Coin) print "one"; else print "a";|
| ];|
|Class Gold_coin class Coin with name "gold";|
|Class Silver_coin class Coin with name "silver";|
|Class Bronze_coin class Coin with name "bronze";|
|SilverCoin -> "silver coin";|
|... and so on|
\endlines}
\ansno55:
{^^{I Ching}^^{trigrams}^^{exercises: I Ching coins}
^^{coins (in I Ching trigrams)}
Firstly, a printing rule to print the state of coins. Coin-objects
will have a property called |way_up| which is always either 1 or 2:
\beginlines
|[ Face x; if (x.way_up==1) print "Heads"; else print "Tails"; ];|
\endlines
There are two kinds of coin but we'll implement them with three
classes: |Coin| and two sub-categories, |GoldCoin| and |SilverCoin|.
Since the coins only join up into trigrams when present in groups
of three, we need a routine to detect this:
\beginlines
|[ CoinsTogether cla i x y;|
| objectloop (i ofclass cla)|
| { x=parent(i);|
| if (y==0) y=x; else { if (x~=y) return 0; }|
| }|
| return y;|
|];|
\endlines
Thus |CoinsTogether(cla)| decides whether all objects of class |cla|
are in the same place. (|cla| will always be either |GoldCoin| or
|SilverCoin|.) We must now write the class definitions:
\beginlines
|Class Coin|
| with name "coin" "coins//p",|
| way_up 1, article "the",|
| after|
| [; Drop, PutOn:|
| self.way_up = random(2); print (Face) self;|
| if (CoinsTogether(self.which_class))|
| { print ". The ";|
| if (self.which_class == GoldCoin)|
| print "gold"; else print "silver";|
| " trigram is now ", (Trigram) self.which_class;|
| }|
| ".";|
| ];|
|[ CoinLT k i c;|
| if (inventory_stage==1)|
| { if (self.which_class == GoldCoin)|
| print "the gold"; else print "the silver";|
| print " coins ";|
| k=CoinsTogether(self.which_class);|
| if (k==location || k has supporter)|
| { objectloop (i ofclass self.which_class)|
| { print (name) i;|
| switch(++c)|
| { 1: print ", "; 2: print " and ";|
| 3: print " (showing the trigram ",|
| (Trigram) self.which_class, ")";|
| }|
| }|
| rtrue;|
| }|
| if (~~(c_style & ENGLISH_BIT)) c_style = c_style + ENGLISH_BIT;|
| if (~~(c_style & NOARTICLE_BIT)) c_style = c_style + NOARTICLE_BIT;|
| if (c_style & NEWLINE_BIT) c_style = c_style - NEWLINE_BIT;|
| if (c_style & INDENT_BIT) c_style = c_style - INDENT_BIT;|
| }|
| rfalse;|
|];|
|Class GoldCoin class Coin|
| with name "gold", which_class GoldCoin,|
| list_together [; return CoinLT(); ];|
|Class SilverCoin class Coin|
| with name "silver", which_class SilverCoin,|
| list_together [; return CoinLT(); ];|
\endlines
(There are two unusual points here. Firstly, the |CoinsLT| routine
is not simply given as the common |list_together| value in the |coin|
class since, if it were, all six coins would be grouped together:
we want two groups of three, so the gold and silver coins have to have
different |list_together| values. Secondly, if a trigram is together
and on the floor, it is not good enough to simply append text like
``showing Tails, Heads, Heads (change)'' at |inventory_stage| 2 since the
coins may be listed in a funny order: for example, in the order snake,
robin, bison. In that event, the order the coins are listed in
doesn't correspond to the order their values are listed in, which is
misleading. So instead |CoinsLT| takes over entirely at
|inventory_stage| 1 and prints out the list of three itself, returning
true to stop the list from being printed out by the library as well.)
To resume: whenever coins are listed together, they are grouped
into gold and silver. Whenever trigrams are visible they are to be
described by either |Trigram(GoldClass)| or |Trigram(SilverClass)|:
\beginlines
|Array gold_trigrams --> "fortune" "change" "river flowing" "chance"|
| "immutability" "six stones in a circle"|
| "grace" "divine assistance";|
|Array silver_trigrams --> "happiness" "sadness" "ambition" "grief"|
| "glory" "charm" "sweetness of nature"|
| "the countenance of the Hooded Man";|
|[ Trigram cla i k state;|
| objectloop (i ofclass cla)|
| { print (Face) i; if (k++<2) print ","; print " ";|
| state=state*2 + (i.way_up-1);|
| }|
| if (cla == GoldCoin) i=gold_trigrams; else i=silver_trigrams;|
| print "(", (string) i-->state, ")";|
|];|
\endlines
(These interpretations of the coins are quite bogus.) Finally,
we have to make the six actual coins:
\beginlines
|GoldCoin -> "goat" with name "goat";|
|GoldCoin -> "deer" with name "deer";|
|GoldCoin -> "chicken" with name "chicken";|
|SilverCoin -> "robin" with name "robin";|
|SilverCoin -> "snake" with name "snake";|
|SilverCoin -> "bison" with name "bison";|
\endlines}
\ansno56:
{^^{exercises: tomato in red or green}
\beginlines
|parse_name|
|[ i j w; if (self has general) j='red'; else j='green';|
| w=NextWord();|
| while (w==j or 'fried')|
| { w=NextWord(); i++;|
| }|
| if (w=='tomato') return i+1;|
| return 0;|
|],|
\endlines}
\ansno57:
{^^{Princess}^^{artiste formerly known as Princess}
^^{exercises: the artiste formerly known as Princess}
\beginlines
|Object -> "/?%?/ (the artiste formally known as Princess)"|
| with name "princess" "artiste" "formally" "known" "as",|
| short_name|
| [; if (self hasnt general) { print "Princess"; rtrue; }|
| ],|
| react_before|
| [; Listen: print_ret (name) self, " sings a soft siren song.";|
| ],|
| initial|
| [; print_ret (name) self, " is singing softly.";|
| ],|
| parse_name|
| [ x n; if (self hasnt general)|
| { if (NextWord()=='princess') return 1;|
| return 0;|
| }|
| x=WordAddress(wn);|
| if ( x->0 == '/' && x->1 == '?' && x->2 == '%'|
| && x->3 == '?' && x->4 == '/')|
| { while (wn<=parse->1 && WordAddress(wn++)<x+5) n++;|
| return n;|
| }|
| return -1;|
| ],|
| life|
| [; Kiss: give self general; self.life = NULL;|
| "In a fairy-tale transformation, the Princess |
| steps back and astonishes the world by announcing |
| that she will henceforth be known as ~/?%?/~.";|
| ],|
| has animate proper female;|
\endlines}
\ansno58:
{^^{exercises: drinks machine}
Something to note here is that the button can't be called just ``coffee''
when the player's holding a cup of coffee: this means the game responds sensibly
to the sequence ``press coffee'' and ``drink coffee''. Also note the way |itobj|
is set to the delivered drink, so that ``drink it'' works nicely.
\beginlines
|Object -> drinksmat "drinks machine",|
| with name "drinks" "machine",|
| initial|
| "A drinks machine here has buttons for Cola, Coffee and Tea.",|
| has static;|
|Object -> thebutton "drinks machine button"|
| has scenery|
| with parse_name|
| [ i flag type;|
| for (: flag == 0: i++)|
| { flag = 1;|
| switch(NextWord())|
| { 'button', 'for': flag = 0;|
| 'coffee': if (type == 0) { flag = 0; type = 1; }|
| 'tea': if (type == 0) { flag = 0; type = 2; }|
| 'cola': if (type == 0) { flag = 0; type = 3; }|
| }|
| }|
| if (type==drink.number && i==2 && type~=0 && drink in player)|
| return 0;|
| self.number=type; return i-1;|
| ],|
| number 0,|
| before|
| [; Push, SwitchOn:|
| if (self.number == 0)|
| "You'll have to say which button to press.";|
| if (parent(drink) ~= 0) "The machine's broken down.";|
| drink.number = self.number; move drink to player; itobj = drink;|
| print_ret "Whirr! The machine puts ", (a) drink, " into your \|
| glad hands.";|
| Attack: "The machine shudders and squirts cola at you.";|
| Drink: "You can't drink until you've worked the machine.";|
| ];|
|Object drink "drink"|
| with parse_name|
| [ i flag type;|
| for (: flag == 0: i++)|
| { flag = 1;|
| switch(NextWord())|
| { 'drink', 'cup', 'of': flag = 0;|
| 'coffee': if (type == 0) { flag = 0; type = 1; }|
| 'tea': if (type == 0) { flag = 0; type = 2; }|
| 'cola': if (type == 0) { flag = 0; type = 3; }|
| }|
| }|
| if (type ~= 0 && type ~= self.number) return 0;|
| return i-1;|
| ],|
| short_name|
| [; print "cup of ";|
| switch (self.number)|
| { 1: print "coffee"; 2: print "tea"; 3: print "cola"; }|
| rtrue;|
| ],|
| number 0,|
| before|
| [; Drink: remove self;|
| "Ugh, that was awful. You crumple the cup and responsibly \|
| dispose of it.";|
| ];|
\endlines}
\ansno59:
{^^{exercises: parsing adjectives}
Create a new property |adjective|, and move names which are
^{adjectives} to it: for instance,
\beginstt
name "tomato" "vegetable", adjective 'fried' 'green' 'cooked',
\endtt
(Recall that dictionary words can only be written in |"| quotes for
the |name| property.) Then (using the same |IsAWordIn| routine),
\beginstt
[ ParseNoun obj n m;
while (IsAWordIn(NextWord(),obj,adjective) == 1) n++; wn--;
while (IsAWordIn(NextWord(),obj,noun) == 1) m++;
if (m==0) return 0; return n+m;
];
\endtt}
\ansno60:
{^^{debugging: referring to objects by number}
^^{exercises: referring to objects by number}
\beginstt
[ ParseNoun obj;
if (NextWord() == 'object' && TryNumber(wn) == obj) return 2;
wn--; return -1;
];
\endtt^^{objects: referred to by number}}
\ansno61:
{^^{``{\tt \#}''}^^{wild-card}
^^{exercises: wild-card for a single object}
\beginstt
[ ParseNoun;
if (WordLength(wn)==1 && WordAddress(wn)->0 == '#') return 1;
return -1;
];
\endtt}
\ansno62:
{^^{``{\tt *}''}^^{wild-card}
^^{exercises: wild-card for multiple objects}
\beginstt
[ ParseNoun;
if (WordLength(wn)==1 && WordAddress(wn)->0 == '#') return 1;
if (WordLength(wn)==1 && WordAddress(wn)->0 == '*')
{ parser_action = ##PluralFound; return 1; }
return -1;
];
\endtt}
\ansno63:
{^^{fly in amber}The trick is to convert ``fly in amber''
into ``fly fly amber'' (a harmless name) before the parser gets
under way.^^{exercises: ``fly in amber''}
\beginlines
|[ BeforeParsing i j;|
| for (i=parse->1,j=2:j<i:j++)|
| { wn=j-1;|
| if (NextWord()=='fly' && NextWord()=='in' && NextWord()=='amber')|
| parse-->(j*2-1) = 'fly';|
| }|
|];|
\endlines}
\ansno64:
{^^{exercises: cherubim plural}
\beginlines
|Global c_warned = false;|
|Class Cherub|
| with parse_name|
| [ i j flag;|
| for (flag=true:flag:flag=false)|
| { j=NextWord();|
| if (j=='cherub' or j==self.name) flag=true;|
| if (j=='cherubs' && (~~c_warned))|
| { c_warned=true;|
| parser_action=##PluralFound; flag=true;|
| print "(I'll let this go once, but the plural of cherub is cherubim.)^";|
| }|
| if (j=='cherubim')|
| { parser_action=##PluralFound; flag=true; }|
| i++;|
| }|
| return i-1;|
| ];|
\endlines
Then again, Shakespeare even wrote ``cherubins'' in `Twelfth Night',
so who are we to censure?^^{cherubim}^^{William Shakespeare}}
\ansno65:
{Because the parser might go on to reject the line it's working on:
for instance, if the player typed ``shazam splurge'' then the message
``Shazam!'' followed by a parser complaint will be somewhat unedifying.}
\ansno66:
{^^{named rooms}
^^{exercises: moving to a room by typing its name}
The scheme will work like this: any room that ought to have a name
should have a |place_name| property set to a dictionary word;
say, the Bedquilt cave could be called |'bedquilt'|. Clearly
you should only be allowed to type this from adjacent rooms.
So we'll implement the following: you can only move by name to
those rooms listed in the current room's |to_places| property.
For instance, the Soft Room might have |to_places| set to
\beginlines
|to_places Bedquilt Slab_Room Twopit_Room;|
\endlines
Now the code: if the player's verb is not otherwise understood,
we'll check it to see if it's a place name of a nearby room,
and if so store that room's object number in |goto_room|, converting
the verb to |'go#room'| (which we'll deal with below).
\beginlines
|Global goto_room;|
|[ 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 ", (name) 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.'' in reply to, say, ``bedquilt the nugget''.) It remains
only to create 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'.}
\bigskip
\ansno67:
{^^{``white'' and ``black''}^^{``black'' and ``white''}
^^{genie}^^{lamp (of genie)}^^{exercises: genie muddling black and white}
\beginlines
|Object -> genies_lamp "brass lamp"|
| with name "brass" "lamp",|
| before|
| [; Rub: if (self hasnt general) give self general;|
| else give self ~general;|
| "A genie appears from the lamp, declaring:^^|
| ~Mischief is my sole delight:^|
| If white means black, black means white!~^^|
| She vanishes away with a vulgar wink.";|
| ];|
|Object -> white_stone "white stone" with name "white" "stone";|
|Object -> black_stone "black stone" with name "black" "stone";|
|...|
|[ BeforeParsing;|
| if (genies_lamp hasnt general) return;|
| for (wn=1::)|
| { switch(NextWordStopped())|
| { 'white': parse->(wn*2-3) = 'black';|
| 'black': parse->(wn*2-3) = 'white';|
| -1: return;|
| }|
| }|
|];|
\endlines^^|BeforeParsing|}
\ansno68:
{^^{footnotes}^^{exercises: footnotes}
\beginlines
|Constant MAX_FOOTNOTES 10;|
|Array footnotes_seen -> 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)|
| "No footnote [", noun, "] has been mentioned.";|
| if (noun==0) "Footnotes count upward from 1.";|
| n=footnotes_seen->(noun-1);|
| print "[",noun,"] ";|
| switch(n)|
| { 0: "This is a footnote.";|
| 1: "D.G.REG.F.D is inscribed around English coins.";|
| 2: "~Jackdaws love my big sphinx of quartz~, for example.";|
| }|
|];|
|Verb "footnote" "note" * number -> Footnote;|
\endlines^^{jackdaws}^^{The quick brown fox jumped over the lazy dog}
And then you can code, for instance,
\beginlines
| print "Her claim to the throne is in every pocket ", (Note) 1,|
| ", her portrait in every wallet.";|
\endlines}
\ansno69:
{^^{low numbers in French}^^{French numbers}
^^{exercises: low numbers in French}
The general parsing routine needed is:
\beginlines
|[ FrenchNumber n;|
| switch(NextWord())|
| { 'un', 'une': n=1;|
| 'deux': n=2;|
| 'trois': n=3;|
| 'quatre': n=4;|
| 'cinq': n=5;|
| default: return -1;|
| }|
| parsed_number = n; return 1;|
|];|
\endlines}
\ansno70:
{^^{exercises: floating-point numbers}
First we must decide how to store ^{floating-point numbers}
internally: in this case we'll simply store $100x$ to represent
$x$, so that ``$5.46$'' will be parsed as $546$.
\beginlines
|[ DigitNumber n type x;|
| x = NextWordStopped(); if (x==-1) return -1; wn--;|
| if (type==0)|
| { x = WordAddress(wn);|
| if (x->n>='0' && x->n<='9') return (x->n) - '0';|
| return -1;|
| }|
| if (x=='nought' or 'oh') { wn++; return 0; }|
| x = TryNumber(wn++); if (x==-1000 || x>=10) x=-1; return x;|
|];|
|[ FloatingPoint a x b w d1 d2 d3 type;|
| a = TryNumber(wn++);|
| if (a==-1000) return -1;|
| w = NextWordStopped(wn); if (w==-1) return a*100;|
| x = NextWordStopped(wn); if (x==-1) return -1; wn--;|
| if (w=='point') type=1;|
| else|
| { if (WordAddress(wn-1)->0~='.' || WordLength(wn-1)~=1)|
| return -1;|
| }|
| d1 = DigitNumber(0,type);|
| if (d1==-1) return -1;|
| d2 = DigitNumber(1,type); d3 = DigitNumber(2,type);|
| b=d1*10; if (d2>=0) b=b+d2; else d3=0;|
| if (type==1)|
| { x=1; while (DigitNumber(x,type)>=0) x++; wn--;|
| }|
| else wn++;|
| parsed_number = a*100 + b;|
| if (d3>=5) parsed_number++;|
| return 1;|
|];|
\endlines}
\ansno71:
{^^{exercises: phone numbers}
Again, the first question is how to store the
number dialled: in this case, into a |string| array. The token
is:^^{phone number parsing}^^{telephone number parsing}
\beginlines
|Constant MAX_PHONE_LENGTH = 30;|
|Array dialled_number string MAX_PHONE_LENGTH;|
|[ PhoneNumber f a l ch pp i;|
| pp=1; if (NextWordStopped()==-1) return 0;|
| do|
| { a=WordAddress(wn-1); l=WordLength(wn-1);|
| for (i=0:i<l:i++)|
| { ch=a->i;|
| if (ch<'0' || ch>'9')|
| { if (ch~='-') { f=1; if (i~=0) return -1; } }|
| else|
| { if (pp<MAX_PHONE_LENGTH)|
| dialled_number->(pp++)=ch-'0';|
| }|
| }|
| } until (f==1 || NextWordStopped()==-1);|
| if (pp==1) return -1;|
| dialled_number->0 = pp-1;|
| return 0;|
|];|
\endlines
To demonstrate this in use,
\beginlines
|[ DialPhoneSub i;|
| print "You dialled <";|
| for (i=1:i<=dialled_number->0:i++) print dialled_number->i;|
| ">";|
|];|
|Verb "dial" * PhoneNumber -> DialPhone;|
\endlines}
\ansno72:
{^^{time of day (parsing)}
^^{exercises: parsing times of day}
The time of day will
be returned as a number in the usual Inform time format:
as hours times 60 plus minutes (on the 24-hour clock, so
that the `hour' part is between 0 and 23).
\beginlines
|Constant TWELVE_HOURS = 720;|
|[ NumericTime hr mn word x;|
| if (hr>=24) return -1;|
| if (mn>=60) return -1;|
| x=hr*60+mn; if (hr>=13) return x;|
| x=x%TWELVE_HOURS; if (word=='pm') x=x+TWELVE_HOURS;|
| if (word~='am' or 'pm' && hr==12) x=x+TWELVE_HOURS;|
| return x;|
|];|
|[ MyTryNumber wordnum i j;|
| i=wn; wn=wordnum; j=NextWordStopped(); wn=i;|
| switch(j)|
| { 'twenty-five': return 25;|
| 'thirty': return 30;|
| default: return TryNumber(wordnum);|
| }|
|];|
|[ TimeOfDay i j k flag loop ch hr mn;|
| i=NextWord();|
| switch(i)|
| { 'midnight': parsed_number=0; return 1;|
| 'midday', 'noon': parsed_number=TWELVE_HOURS; return 1;|
| }|
| ! Next try the format 12:02|
| j=WordAddress(wn-1); k=WordLength(wn-1);|
| flag=0;|
| for (loop=0:loop<k:loop++)|
| { ch=j->loop;|
| if (ch==':' && flag==0 && loop~=0 && loop~=k-1) flag=1;|
| else { if (ch<'0') flag=-1; if (ch>'9') flag=-1; }|
| }|
| if (k<3) flag=0; if (k>5) flag=0;|
| if (flag==1)|
| { for (loop=0:j->loop~=':':loop++, hr=hr*10)|
| hr=hr+j->loop-'0';|
| hr=hr/10;|
| for (loop++:loop<k:loop++, mn=mn*10)|
| mn=mn+j->loop-'0';|
| mn=mn/10;|
| j=NextWordStopped();|
| parsed_number=NumericTime(hr, mn, j);|
| if (parsed_number<0) return -1;|
| if (j~='pm' or 'am') wn--;|
| return 1;|
| }|
| ! Next the format "half past 12"|
| j=-1; if (i=='half') j=30; if (i=='quarter') j=15;|
| if (j<0) j=MyTryNumber(wn-1); if (j<0) return -1;|
| if (j>=60) return -1;|
| k=NextWordStopped();|
| if (k==-1)|
| { hr=j; if (hr>12) return -1; jump TimeFound; }|
| if (k=='o^clock' or 'am' or 'pm')|
| { hr=j; if (hr>12) return -1; jump TimeFound; }|
| if (k=='to' or 'past')|
| { mn=j; hr=MyTryNumber(wn);|
| if (hr<=0)|
| { switch(NextWordStopped())|
| { 'noon', 'midday': hr=12;|
| 'midnight': hr=0;|
| default: return -1;|
| }|
| }|
| if (hr>=13) return -1;|
| if (k=='to') { mn=60-mn; hr=hr-1; if (hr==-1) hr=23; }|
| wn++; k=NextWordStopped();|
| jump TimeFound;|
| }|
| hr=j; mn=MyTryNumber(--wn);|
| if (mn<0) return -1; if (mn>=60) return -1;|
| wn++; k=NextWordStopped();|
| .TimeFound;|
| parsed_number = NumericTime(hr, mn, k);|
| if (parsed_number<0) return -1;|
| if (k~='pm' or 'am' or 'o^clock') wn--;|
| return 1;|
|];|
\endlines}
\ansno73:
{^^{exercises: spaceship control panel}
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) return -1;|
| w=NextWord(); if (w=='slide') w=NextWord();|
| switch(w)|
| { 'first', 'one': n=1;|
| 'second', 'two': n=2;|
| 'third', 'three': n=3;|
| 'fourth', 'four': n=4;|
| 'fifth', 'five': n=5;|
| default: return -1; ! Failure!|
| }|
| w=NextWord(); if (w~='slide') wn--; ! (Leaving word counter at the|
| ! first misunderstood word)|
| parsed_number=n;|
| return 1; ! Success!|
|];|
|Global slide_settings --> 5; ! A five-word array|
|[ 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}
\ansno74:
{^^{exercises: implementing parser primitives}
(See the |Parser| file.) ^|NextWord| roughly returns
|parse-->(w*2-1)| (but it worries a bit about commas and
full stops).
\beginlines
|[ WordAddress w; return buffer + parse->(w*4+1); ];|
|[ WordLength w; return parse->(w*4); ];|
\endlines^^|WordAddress|^^|WordLength|}
\ansno75:
{^^{exercises: parsing any quoted text}
^^{parser: parsing quoted strings}
(Cf. the ^{blackboard} code in ^{`Toyshop'}.)
\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 0;|
| }|
| 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 text is treated as though it
were a preposition, and the positions where the quoted text starts and
finishes in the raw text ^|buffer| are recorded, 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}^^{tokenising}}
\ansno76:
{^^{token never matching anything}
^^{exercises: tokens which never match}
\beginlines
|[ NeverMatch; return -1; ];|
\endlines}
\ansno77:
{Perhaps to arrange better error messages when the text
has failed all the `real' grammar lines of a verb (see
^{`Encyclopaedia Frobozzica'} for an example).}
\ansno78:
{^^{third parameter for parser}
^^{exercises: third noun for parser}
(See the ^|NounDomain| specification in \S A9.) This routine passes
on any |REPARSE_CODE|, as it must, but keeps a matched object in
its own |third| variable, returning the `skip this text' code to
the parser. Thus the parser never sees any third parameter.
\beginlines
|Global third;|
|[ ThirdNoun x;|
| x=NounDomain(player,location,0);|
| if (x==REPARSE_CODE) return x; if (x==0) return -1; third = x;|
| return 0;|
|];|
\endlines^^|REPARSE CODE|}
\ansno79:
{^^{``scope'' verb exercise}^^{exercises: ``scope'' verb}
\beginlines
|Global scope_count;|
|[ PrintIt obj; print_ret ++scope_count, ": ", (a) obj, " (", obj, ")"; ];|
|[ ScopeSub; LoopOverScope(PrintIt);|
| if (scope_count==0) "Nothing is in scope.";|
|];|
|Verb meta "scope" * -> Scope;|
\endlines}
\ansno80:
{^^{``megalook'' verb}^^{exercises: ``megalook'' verb}
\beginlines
|[ MegaExam obj; print "^", (a) obj, ": "; <Examine obj>; ];|
|[ MegaLookSub; <Look>; LoopOverScope(MegaExam); ];|
|Verb meta "megalook" * -> MegaLook;|
\endlines}
\medskip
\ansno81:
{^^{exercises: putting everything in scope}
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.
But here's how it could be done:
\beginlines
|[ Anything i;|
| if (scope_stage==1) rfalse;|
| if (scope_stage==2)|
| { objectloop (i ofclass Object) 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'.}
\ansno82:
{^^{divided room}^^{room divided in half}^^{glass window}
^^{exercises: room divided by glass window}
Note the sneaky way looking through the window is implemented, and that
the `on the other side' part of the room description isn't printed
in that case.
\beginlines
|Property far_side;|
|Class Window_Room|
| with description|
| "This is one end of a long east/west room.",|
| before|
| [; Examine, Search: ;|
| default:|
| if (inp1~=1 && noun~=0 && noun in self.far_side)|
| print_ret (The) noun, " is on the far side of|
| the glass.";|
| if (inp2~=1 && second~=0 && second in self.far_side)|
| print_ret (The) second, " is on the far side of|
| the glass.";|
| ],|
| after|
| [; Look:|
| if (ggw has general) rfalse;|
| print "^The room is divided by a great glass window";|
| if (location.far_side hasnt light) " onto darkness.";|
| print ", stretching from floor to ceiling.^";|
| if (Locale(location.far_side,|
| "Beyond the glass you can see",|
| "Beyond the glass you can also see")~=0) ".";|
| ],|
| has light;|
|Window_Room window_w "West of Window"|
| with far_side window_e;|
|Window_Room window_e "East of Window"|
| with far_side window_w;|
|Object ggw "great glass window"|
| with name "great" "glass" "window",|
| before|
| [ place; Examine, Search: place=location;|
| if (place.far_side hasnt light)|
| "The other side is dark.";|
| give self general;|
| PlayerTo(place.far_side,1); <Look>; PlayerTo(place,1);|
| give self ~general;|
| give place.far_side ~visited; rtrue;|
| ],|
| found_in window_w window_e,|
| has scenery;|
\endlines
A few words about ^|inp1| and ^|inp2| are in order. |noun| and
|second| can hold either objects or numbers, and it's sometimes useful
to know which. |inp1| is equal to |noun| if that's an object,
or 1 if that's a number; likewise for |inp2| and |second|. (In this
case we're just being careful that the action |SetTo eggtimer 35|
wouldn't be stopped if object 35 happened to be on the other side of
the glass.) We also need:
\beginlines
|[ InScope actor;|
| if (actor in window_w && window_e has light) ScopeWithin(window_e);|
| if (actor in window_e && window_w has light) ScopeWithin(window_w);|
| rfalse;|
|];|
\endlines}
\ansno83:
{^^{exercises: dwarf breathing in dark}
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}
^^{darkness: changing scope within}
\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;|
||
|Object -> 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;|
||
|Object -> diamond "shiny diamond"|
| with name "shiny" "diamond"|
| has scored;|
||
|Object -> 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.}
\ansno84:
{^^{exercises: nose attached to player}
In the |Initialise| routine, move |newplay| somewhere and
|ChangePlayer| to it, where:
\beginlines
|Object newplay "yourself"|
| with description "As good-looking as ever.", number 0,|
| add_to_scope nose,|
| capacity 5,|
| before|
| [; Inv: if (nose has general) print "You're holding your nose. ";|
| Smell: if (nose has general)|
| "You can't smell a thing with your nose held.";|
| ],|
| has concealed animate proper transparent;|
||
|Object nose "nose"|
| with name "nose", article "your",|
| before|
| [; Take: if (self has general)|
| "You're already holding your nose.";|
| if (children(player) > 1) "You haven't a free hand.";|
| give self general; player.capacity=1;|
| "You hold your nose with your spare hand.";|
| Drop: if (self hasnt general) "But you weren't holding it!";|
| give self ~general; player.capacity=5;|
| print "You release your nose and inhale again. ";|
| <<Smell>>;|
| ],|
| has scenery;|
\endlines^^{`A Nasal Twinge'}^^{nose}}
\ansno85:
{^^{exercises: sterilising machine}
\beginlines
|Object steriliser "sterilising machine"|
| with name "washing" "sterilising" "machine",|
| add_to_scope top_of_wm go_button,|
| before|
| [; PushDir: AllowPushDir(); rtrue;|
| Receive:|
| if (receive_action==##PutOn)|
| <<PutOn noun top_of_wm>>;|
| SwitchOn: <<Push go_button>>;|
| ],|
| after|
| [; PushDir: "It's hard work, but the steriliser does roll.";|
| ],|
| initial|
| [; print "There is a sterilising machine on casters here (a kind of|
| chemist's washing machine) with a ~go~ button. ";|
| if (children(top_of_wm)~=0)|
| { print "On top";|
| WriteListFrom(child(top_of_wm), ISARE_BIT + ENGLISH_BIT);|
| print ". ";|
| }|
| if (children(self)~=0)|
| { print "Inside";|
| WriteListFrom(child(self), ISARE_BIT + ENGLISH_BIT);|
| print ". ";|
| }|
| ],|
| has static container open openable;|
|Object top_of_wm "top of the sterilising machine",|
| with article "the",|
| has static supporter;|
|Object go_button "~go~ button"|
| with name "go" "button",|
| before [; Push, SwitchOn: "The power is off."; ],|
| has static;|
\endlines^^{`A Nasal Twinge'}^^{sterilising machine}}
\ansno86:
{^^{red sticky label}^^{label, red sticky}
^^{exercises: red sticky label}
The label object itself is not too bad:
\beginlines
|Object -> label "red sticky label"|
| with name "red" "sticky" "label",|
| number 0,|
| before|
| [; PutOn, Insert:|
| if (self.number~=0)|
| { print "(first removing the label from ",|
| (the) self.number, ")^"; self.number=0; move self to player;|
| }|
| if (second==self) "That would only make a red mess.";|
| self.number=second; remove self;|
| print_ret "You affix the label to ", (the) second, ".";|
| ],|
| react_after|
| [ x; x=self.number; if (x==0) rfalse;|
| Look: if (x in location)|
| print "^The red sticky label is stuck to ", (the) x, ".^";|
| Inv: if (x in player) |
| print "^The red sticky label is stuck to ", (the) x, ".^";|
| ],|
| each_turn|
| [; if (parent(self)~=0) self.number=0; ];|
\endlines
Note that |label.number| holds the object the label is stuck to, or
0 if it's unstuck: and that when it is stuck, it is removed from the
object tree. It therefore has to be moved into scope, so we need the
rule: if the labelled object is in scope, then so is the label.
\beginlines
|Global disable_self;|
|[ InScope actor i1 i2;|
| if (label.number==0) rfalse; if (disable_self==1) rfalse;|
| disable_self=1;|
| i1 = TestScope(label, actor);|
| i2 = TestScope(label.number, actor);|
| disable_self=0;|
| if (i1~=0) rfalse;|
| if (i2~=0) PlaceInScope(label);|
| rfalse;|
|];|
\endlines
This routine has two interesting points: firstly, it disables itself
while testing scope (since otherwise the game would go into an endless
recursion), and secondly it only puts the label in scope if it isn't
already there. This is just a safety precaution to prevent the label
reacting twice to actions (and isn't really necessary since the label
can't already be in scope, but is included for the sake of example).}
\ansno87:
{^^{``lock'' and ``unlock'' disambiguation}^^{disambiguation}
^^{exercises: ``lock'' and ``unlock'' inferring keys}
Firstly, create an attribute |is_key| and give it to all the keys in
the game. Then:
\beginlines
|Global assumed_key;|
|[ DefaultLockSub;|
| print "(with ", (the) assumed_key, ")^"; <<Lock noun assumed_key>>;|
|];|
|[ DefaultLockTest i count;|
| if (noun hasnt lockable) rfalse;|
| objectloop (i in player)|
| if (i has is_key) { count++; assumed_key = i; }|
| if (count==1) rtrue; rfalse;|
|];|
|Extend "lock" first * noun = DefaultLockTest -> DefaultLock;|
\endlines
(and similar code for ``unlock''). Note that ``lock strongbox''
is matched by this new grammar line only if the player only has one
key: the |DefaultLock strongbox| action is generated: which is
converted to, say, |Lock strongbox brass_key|.}
\ansno88:
{^^{exercises: quotations in boxes}
\beginlines
|Array quote_done -> 50;|
|Global next_quote = -1;|
|[ Quote i;|
| if (quote_done->i==0) { quote_done->i = 1; next_quote = i; }|
|];|
|[ AfterPrompt;|
| switch(next_quote)|
| { 0: box "His stride is wildernesses of freedom:"|
| "The world rolls under the long thrust of his heel."|
| "Over the cage floor the horizons come."|
| ""|
| "-- Ted Hughes, ~The Jaguar~";|
| 1: ...|
| }|
| next_quote = -1;|
|];|
\endlines^^{Ted Hughes}}
\ansno89:
{^^{exercises: Invisiclues hints}
Note the magic line of assembly code here, which only works for
Advanced games:
\beginlines^^{``Invisiclues''}
|[ GiveHint hint keypress;|
| print (string) 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}
\ansno90:
{^^{saving the character}^^{role-playing games}
^^{campaigns and scenarios}^^{exercises: saving the character}
By encoding the character into a byte array and using |@save|
and |@restore|. The numbers in this array might contain the character's
name, rank and abilities, together with some coding system to show what
possessions the character has (a brass lamp, 50 feet of rope, etc.)}
\ansno91:
{^^{title page}^^{`Ruins'}^^{exercises: title page}
Note that we wait for a space character
(32) or either kind of new-line which typical ASCII keyboards produce
(10 or 13), just to be on the safe side:
\beginlines
|[ TitlePage i;|
| @erase_window -1; print "^^^^^^^^^^^^^";|
| i = 0->33; if (i==0) i=80; i=(i-50)/2;|
| style bold; font off; spaces(i);|
| print " RUINS^";|
| style roman; print "^^"; spaces(i);|
| print " [Please press SPACE to begin.]^";|
| font on;|
| box "And make your chronicle as rich with praise"|
| "As is the ooze and bottom of the sea"|
| "With sunken wreck and sumless treasures."|
| ""|
| "-- William Shakespeare, ~Henry V~ I. ii. 163";|
| do { @read_char 1 0 0 i; } until (i==32 or 10 or 13);|
| @erase_window -1;|
|];|
\endlines^^{William Shakespeare}}
\ansno92:
{^^{invisible status line}^^{exercises: status line invisible}
First put the directive
|Replace DrawStatusLine;| before including the library; define
the global variable |invisible_status| somewhere. Then give
the following redefinition:
\beginlines
|[ DrawStatusLine i width posa posb;|
| if (invisible_status==1) return;|
| @split_window 1; @set_window 1; @set_cursor 1 1; style reverse;|
| width = 0->33; posa = width-26; posb = width-13;|
| spaces (width-1);|
| @set_cursor 1 2; PrintShortName(location);|
| if (width > 76)|
| { @set_cursor 1 posa; print "Score: ", sline1;|
| @set_cursor 1 posb; print "Moves: ", sline2;|
| }|
| if (width > 63 && width <= 76)|
| { @set_cursor 1 posb; print sline1, "/", sline2;|
| }|
| @set_cursor 1 1; style roman; @set_window 0;|
|];|
\endlines}
\ansno93:
{^^{exercises: status line showing treasure}
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^^|DrawStatusLine|^^{treasures on status line}^^{status line}}
\ansno94:
{^^{compass rose}^^{exercises: status line with compass rose}
|Replace| with the following. (Note the use of
|@@92| as a string escape, to include a literal backslash character,
and |@@124| for a vertical line.)
\beginlines
|Constant U_POS 28; Constant W_POS 30; Constant C_POS 31;|
|Constant E_POS 32; Constant IN_POS 34;|
|[ DrawStatusLine i;|
| @split_window 3; @set_window 1; style reverse; font off;|
| @set_cursor 1 1; spaces (0->33)-1;|
| @set_cursor 2 1; spaces (0->33)-1;|
| @set_cursor 3 1; spaces (0->33)-1;|
| @set_cursor 1 2; print (name) location;|
| @set_cursor 1 51; print "Score: ", sline1;|
| @set_cursor 1 64; print "Moves: ", sline2;|
| if (location ~= thedark)|
| { ! First line|
| if (location.u_to ~= 0) { @set_cursor 1 U_POS; print "U"; }|
| if (location.nw_to ~= 0) { @set_cursor 1 W_POS; print "@@92"; }|
| if (location.n_to ~= 0) { @set_cursor 1 C_POS; print "@@124"; }|
| if (location.ne_to ~= 0) { @set_cursor 1 E_POS; print "/"; }|
| if (location.in_to ~= 0) { @set_cursor 1 IN_POS; print "I"; }|
| ! Second line|
| if (location.w_to ~= 0) { @set_cursor 2 W_POS; print "-"; }|
| @set_cursor 2 C_POS; print "o";|
| if (location.e_to ~= 0) { @set_cursor 2 E_POS; print "-"; }|
| ! Third line|
| if (location.d_to ~= 0) { @set_cursor 3 U_POS; print "D"; }|
| if (location.sw_to ~= 0) { @set_cursor 3 W_POS; print "/"; }|
| if (location.s_to ~= 0) { @set_cursor 3 C_POS; print "@@124"; }|
| if (location.se_to ~= 0) { @set_cursor 3 E_POS; print "@@92"; }|
| if (location.out_to ~= 0){ @set_cursor 3 IN_POS; print "O"; }|
| }|
| @set_cursor 1 1; style roman; @set_window 0; font on;|
|];|
\endlines}
\ansno95:
{^^{centred status line}
^^{exercises: status line with centred room}
The tricky part is working out the
number of characters in the location name, and this is where
|@output_stream| is so useful. This time |Replace| with:
\beginlines
|Array printed_text table 64;|
|[ DrawStatusLine i j;|
| i = 0->33; if (i==0) i=80;|
| font off;|
| @split_window 1; @buffer_mode 0; @set_window 1;|
| style reverse; @set_cursor 1 1; spaces(i);|
| printed_text-->0 = 64;|
| @output_stream 3 printed_text;|
| print (name) location;|
| @output_stream -3;|
| j=(i-(printed_text-->0))/2;|
| @set_cursor 1 j; print (name) location; spaces(j-1);|
| style roman;|
| @buffer_mode 1; @set_window 0; font on;|
|];|
\endlines
Note that the table can hold 128 characters (plenty for this purpose),
and that these are stored in |printed_text->2| to |printed_text->129|;
the length printed is held in |printed_text-->0|.
(^{`Trinity'} actually does this more crudely, storing away
the width of each location name.)}
\ansno96:
{^^{printf exercise}^^{exercises: printf routine}
The following implementation is limited to a format
string $2\times 64 = 128$ characters long, and six subsequent arguments.
|%d| becomes a decimal number, |%e| an English one; |%c|
a character, |%%| a (single) percentage sign and |%s|
a string.
\beginlines
|Array printed_text table 64;|
|Array printf_vals --> 6;|
|[ Printf format p1 p2 p3 p4 p5 p6 pc j k;|
| printf_vals-->0 = p1; printf_vals-->1 = p2; printf_vals-->2 = p3;|
| printf_vals-->3 = p4; printf_vals-->4 = p5; printf_vals-->5 = p6;|
| printed_text-->0 = 64; @output_stream 3 printed_text;|
| print (string) format; @output_stream -3;|
| j=printed_text-->0;|
| for (k=2:k<j+2:k++)|
| { if (printed_text->k == '%')|
| { switch(printed_text->(++k))|
| { '%': print "%";|
| 'c': print (char) printf_vals-->pc++;|
| 'd': print printf_vals-->pc++;|
| 'e': print (number) printf_vals-->pc++;|
| 's': print (string) printf_vals-->pc++;|
| default: print "<** Unknown printf escape **>";|
| }|
| }|
| else print (char) printed_text->k;|
| }|
|];|
\endlines}
\tenpoint
\vfill\eject
\answersfalse
%
\titletrue
\sectionx{Index}
\bigskip
\ninepoint
\beginindex
{{\tt *}}, 172.
{{\tt ++}}, 18.
{{\tt --}}, 18.
{{\tt -->}}, 38.
{{\tt ->}}, 153.
{{\tt /}}, 157.
{{\tt ::}}, 57.
{{\tt =}}, 16.
{{\tt @}}, 32, 175.
{{\tt @@}}, 175.
`A Nasal Twinge', 167, 249, 250.
`A Scenic View', 102.
{{\tt Abbreviate}}, 75.
abbreviations, 72, 174.
{{\tt absent}}, 187.
``abstract'' verb, 171.
accented characters, 32.
accusative pronoun, 137, 231.
Ace of Hearts, 40.
`Acheton', 9.
{{\tt Achieved}}, 196.
{{\tt Achieved(task)}}, 131.
Acorn Risc PC 700, 65.
acquisitive bag, 104, 216.
{{\tt action\_to\_be}}, 152, 169.
actions, 92.
\quad creation of, 95.
\quad defined in Library, 198.
\quad diversion of, 101.
\quad groups of, 94.
\quad how the parser chooses, 152.
\quad in debugging suite, 198.
\quad list of group 1, 198.
\quad of the five senses, 101.
\quad sequence of processing, 96.
\quad statements to cause, 93.
\quad validation (exercise), 97, 214.
``actions'' verb, 171.
actor, 163.
{{\tt actor}}, 152, 165.
acute accents, 32.
adaptive hints, 177.
{{\tt add\_to\_scope}}, 105, 166, 190.
additive, 91.
{{\tt (address)}}, 34.
{{\tt AddToScope}}, 196.
adjectives, 148, 237.
Advanced games, 173.
`Advent', 8, 73, 91, 97, 102, 105, 107, 108, 120, 122, 123, 126, 129, 155, 156, 172, 177, 181, 209, 253.
`Adventureland', 8, 105, 126, 142.
AEsop, 32.
{{\tt after}}, 85, 100, 190.
{{\tt AfterLife}}, 129, 203.
{{\tt AfterPrompt}}, 176, 203.
{{\tt AfterRoutines}}, 95.
alarm clock, 119, 222.
Aldebaran brandy, 119.
`Alice Through The Looking\---Glass', 8, 91, 105, 111, 120, 148, 156.
`Alice', 8.
``all'', 169.
{{\tt AllowPushDir}}, 110, 196.
altar, 109.
ambiguity, 169.
ambiguous inputs, 168.
{{\tt Amusing}}, 203.
{{\tt AMUSING\_PROVIDED}}, 130.
ancient honeycomb, 91.
Andrew Clover, 120, 126, 136, 161.
Andrew Plotkin, 181.
animals, 116.
{{\tt animate}}, 137, 188.
{{\tt Answer}}, 114.
appallingly convenient verb, 158.
archaeological dig, 125.
``Area 400", 139.
{{\tt @aread}}, 179.
arguments, 19.
arithmetic expressions, 16.
array bounds, 40.
array of {\fam \ttfam \tentt name}s, 145.
arrays, 38.
arrays as property values, 50.
{{\tt article}}, 138, 190.
{{\tt articles}}, 191.
artiste formerly known as Princess, 147, 235.
Arvo P{\accent "7F a}rt, 31.
{{\tt Ask}}, 114.
asking questions, 164.
assembly language, 177.
\quad tracing switches, 72.
assignments, 18.
associativity, 182.
at character, 175.
{{\tt Attack}}, 114.
{{\tt Attribute}}, 52, 69.
attribute, definition of, 52.
attributes, 85.
\quad defined in library, 187.
\quad maximum number of, 174.
audibility, 124.
{{\tt autosearch}}, 190.
Aviary, 54.
background colour, 179.
background daemon, 123.
backslash character, 175.
bag of six coins, 149.
`Balances', 8, 91, 105, 111, 116, 120, 126, 129, 136, 142, 145, 148, 150, 151, 154, 156, 167, 169.
ball and chain, 228.
ball of pumice, 111, 218.
banana, 158.
base (of numbers), 14.
battery power, 108.
beach full of stones, 61.
{{\tt before}}, 191.
{{\tt BeforeParsing}}, 151, 203, 240.
Beretta pistol, 115.
``Beware of the Dog", 176.
`Beyond Zork', 175.
Bible, 113, 218.
binary numbers, 14.
birds of prey, 54.
Bitwise operators, 19.
Black Forest gateau, 169.
``black'' and ``white'', 156, 240.
blackboard, 245.
Blake's 7, 118, 224.
blindfold Adventure, 135.
Blofeld, Ernst Stavro, 115.
{{\tt Blorple}}, 95.
blue liquid, 139.
boldface, 177.
Bond, James, 115.
Boris J. Parallelopiped, 68.
bounds of arrays, 40.
{{\tt box}}, 30, 176.
brackets (arithmetic), 17.
brain transference machine, 128.
{{\tt break}}, 25.
bridge which collapses, 107, 217.
``brief'', 198.
broth (smell of), 101.
{{\tt buffer}}, 161, 246.
{{\tt @buffer\_mode}}, 179.
built-in functions, 35.
byte arrays, 38.
{{\tt c\_style}}, 144.
C. P. Snow, 121.
C. S. Lewis, 98, 123.
`Caf{\accent 19 e} Inform', 147.
caged animals, 159.
{{\tt call}}, 60.
Cambridge University, 9.
campaigns and scenarios, 181, 252.
cannon-fire, 128.
{{\tt cant\_go}}, 100, 191.
{{\tt capacity}}, 103, 128, 191.
Captain Picard, 120, 225.
cartoon, 216.
carved inscriptions, 99.
case sensitivity, 34.
case sensitivity of dictionary, 146, 173.
catachrestic words, 145.
{{\tt @catch}}, 180.
{{\tt CDefArt}}, 196.
cedilla accents, 32.
``ceiling'', 196.
centred status line, 181, 254.
Chambers English Dictionary, 145.
{{\tt ChangeDefault}}, 134, 196.
{{\tt ChangePlayer}}, 128, 141, 196.
changing articles, 138.
changing library messages, 134.
changing room, 127.
changing scope, 165.
changing short names, 138.
changing the player, 128.
changing the prompt, 135, 231.
{{\tt (char)}}, 34.
character (in sense of text), 14.
character graphic, 175.
characters, 207.
Charlotte's game, 118, 220.
chemical reaction, 138.
cherubim, 151, 239.
chessboard, 132, 230.
{{\tt child}}, 46, 172.
{{\tt children}}, 46, 172.
{{\tt ChooseObjects}}, 169, 203.
`Christminster', 120.
circumflex accents, 32.
clapping game, 118, 220.
{{\tt Class}}, 45, 53.
class, definition of, 45.
\quad and additive properties, 91.
\quad and subclasses, 91.
\quad inheritance rules, 91.
clearing the screen, 179.
closing credits, 130.
{{\tt clothing}}, 188.
clues, 176.
code blocks, 23.
coding mazes, 102.
coiled snake, 116.
coins (in I Ching trigrams), 145, 233.
coins (listed together), 145, 233.
`Colossal Cave', 155.
colours, 179.
command buffer, 146.
command line, 65.
command line syntax, 65.
comments, 11.
common properties, 62.
communications badge, 119, 223.
`companion volumes', 9.
{{\tt compass}}, 102, 196.
compass rose, 181, 254.
compilation, 10.
compiler switches, 71.
component parts of objects, 166.
computer (voice-activated), 117, 220.
``computer, 143", 114.
{{\tt concealed}}, 141, 163, 188.
conditional compilation, 67.
conditions, 20.
conditions as values, 22.
Connie Booth, 175.
constant, 14.
{{\tt Constant}}, 38.
{{\tt consult\_from}}, 112.
{{\tt consult\_words}}, 112.
{{\tt container}}, 103, 188.
{{\tt continue}}, 25.
copyright, 8.
copyright message, 84.
cow pie, 221.
crashing the interpreter, 171.
creating data structures, 37.
creating objects, 61.
\cstok{creature} token, 157.
crowns, 150.
Crowther and Woods, 156.
cubes of integers, 20.
cuckoo, 230.
cultural value, 90.
`Curses', 73, 128, 174, 230.
cursor keys, 180.
{{\tt daemon}}, 123, 191.
daemons, 123.
\quad clash with timers, 124.
\quad maximum number active, 124.
\quad running order, 229.
\quad starting and stopping, 123.
Dalek, 95.
darkness, 121.
\quad abolition of, 121.
\quad affecting scope, 163.
\quad changing scope within, 166, 248.
\quad moving through, 122.
\quad nightfall, 125, 229.
\quad special object, 122.
\quad when it occurs, 121.
{{\tt DarkToDark}}, 122, 204.
dartboard, 96.
data structures, 36.
David M. Baggett, 129, 159.
David Seal, 9.
David Wagner, 102.
daylight, 125, 229.
{{\tt deadflag}}, 86, 129.
deafness, a period of, 128.
death, 129.
\quad and resurrection, 129.
{{\tt DeathMessage}}, 129, 204.
{{\tt DEBUG}}, 72, 170.
debugging, 170.
\quad information file, 72, 171.
\quad referring to objects by number, 148, 238.
\quad suite of verbs, 171.
\quad switches to help assembly language debugging, 72.
\quad tracing calls to every routine in game, 72.
\quad using Infix, 72, 171.
`debugging code', 172.
debugging suite actions, 198.
decimal numbers, 14.
decimal places, 160.
declared but not used, 13.
decrement, 18.
{{\tt DefArt}}, 196.
{{\tt Default}}, 67, 99.
defined constants, 38.
deleting objects, 61.
``delores, yes'', 116.
Dennis Spooner, 107.
{{\tt describe}}, 108, 140, 141, 191.
{{\tt description}}, 191.
desiccated priest, 115.
desktop (RISC OS), 65.
diaereses, 32.
dictionary, 207.
\quad characters which can be part of words in, 146.
\quad maximum size of, 173.
\quad resolution and case sensitivity, 173.
\quad tokenisation using, 180.
\quad untypeable words in, 146.
dictionary of Mayan glyphs, 113.
dictionary, as a data structure, 40.
directions, 99, 163.
\quad compiling without the usual, 102.
\quad direction objects, 102, 196, 215.
\quad direction properties, 190.
directives, 37.
\quad Array, 38.
\quad Attribute, 52.
\quad Class, 53.
\quad Constant, 38.
\quad Extend, 154.
\quad Global, 38.
\quad Object, 46.
\quad Property, 63.
\quad Release, 42.
\quad Serial, 42.
\quad summary table of, 185.
\quad Verb, 153.
dirty tricks, 177.
disambiguation, 169, 251.
diverting actions, 101.
divided room, 166, 247.
division, 16.
division by zero, 17.
{{\tt do}}, 25.
Doctor Who, 107.
{{\tt DoMenu}}, 176, 196.
Don Woods, 9.
Donna Tartt, 92.
{{\tt door}}, 105, 188.
{{\tt door\_dir}}, 105, 106, 192.
{{\tt door\_to}}, 105, 192.
doors, 105.
\quad trapping movement through, 107.
\quad two-way, 106.
Dorothy Parker, 176.
double inventory, 144, 232.
double spacing, 72.
double-quote, 246.
drawings, 175.
{{\tt DrawStatusLine}}, 175, 253.
`drunk player object', 128.
dummy verb, 240.
dye, 138.
Dylan Thurston, 40.
dynamic memory allocation, 174.
Dyslexic Dan, 118, 221.
{{\tt each\_turn}}, 124, 192.
{{\tt EACHTURN\_REASON}}, 166.
Earl Grey tea, 119.
earshot, 124.
east lintel, 99.
eating edible things for preference, 169.
eating worms, 49.
`economy' mode, 72.
{{\tt edible}}, 188.
eight-foot pumice ball, 111, 218.
Elizabeth Eisenstein, 111.
{{\tt else}}, 23.
Elsinore, 12.
embedded routines, 51.
``employ'' verb, 158.
encapsulation, 44.
encapsulation, setting up, 51.
`Enchanter', 105.
`Enchanter' trilogy, 136.
{{\tt @encode\_text}}, 180.
`Encyclopaedia Frobozzica', 113, 120, 246.
{{\tt Endif}}, 67.
English verb words, 152.
{{\tt EnglishNumber}}, 196.
{{\tt Enter}}, 107.
{{\tt enterable}}, 109, 188.
entry points, 203.
epigrams, 176.
{{\tt @erase\_window}}, 179.
Ernst Stavro Blofeld, 115.
error, 74.
error messages, 13.
\quad fatal errors, 74.
\quad memory allocation, 73, 75.
error messages (list of), 74.
error numbers used by parser, 168.
escape character, 32.
escape characters, 175.
{{\tt etype}}, 117.
``examine'' v. ``read'', 113.
exchanges of cards, 41.
exercises, 8.
\quad ``fly in amber'', 148, 238.
\quad ``lock'' and ``unlock'' inferring keys, 169, 251.
\quad ``megalook'' verb, 163, 246.
\quad ``scope'' verb, 163, 246.
\quad acquisitive bag, 104, 216.
\quad action validation, 97, 214.
\quad alarm clock, 119, 222.
\quad bearded psychiatrist, 116, 219.
\quad before on second noun, 96, 214.
\quad cage to open and enter, 109, 218.
\quad car that won't go east, 110, 218.
\quad Charlotte playing Simon Says, 118, 220.
\quad Charlotte's clapping game, 118, 220.
\quad cherubim plural, 151, 239.
\quad chessboard of rooms, 132, 230.
\quad communications badge, 119, 223.
\quad computer (voice-activated), 117, 220.
\quad double inventory, 144, 232.
\quad drinks machine, 147, 236.
\quad dwarf breathing in dark, 166, 248.
\quad Dyslexic Dan, 118, 221.
\quad exchanging ``east''/``west'', 102, 215.
\quad extensions for one actor only, 119, 221.
\quad floating-point numbers, 160, 241.
\quad footnotes, 159, 240.
\quad genie muddling black and white, 156, 240.
\quad Giant with conscience, 129, 230.
\quad glass and steel boxes, 104, 217.
\quad I Ching coins, 145, 233.
\quad implementing parser primitives, 161, 245.
\quad Invisiclues hints, 177, 252.
\quad long time-scale game, 125, 229.
\quad low numbers in French, 160, 241.
\quad macram{\accent 19 e} bag, 105, 217.
\quad Martha the telepath, 120, 225.
\quad Mayan directions, 102, 215.
\quad mid-air location, 125, 229.
\quad midnight, 125, 229.
\quad moving to a room by typing its name, 156, 239.
\quad mushroom picking, 87, 214.
\quad nightfall and daybreak, 125, 229.
\quad nose attached to player, 167, 249.
\quad opening medicine bottle, 89, 214.
\quad orange cloud surrounding player, 102, 215.
\quad ornate box (inventory inside), 140, 231.
\quad parsing adjectives, 148, 237.
\quad parsing any quoted text, 161, 245.
\quad parsing times of day, 161, 243.
\quad pet moth escapes in the dark, 122, 226.
\quad phone numbers, 160, 242.
\quad Picard and Maharg, 120, 225.
\quad plank bridge, 107, 217.
\quad player reacting before, 128, 230.
\quad printf routine, 181, 255.
\quad printing pronouns, 137, 231.
\quad pushing pumice ball uphill, 111, 218.
\quad putting everything in scope, 165, 247.
\quad quotations in boxes, 176, 252.
\quad red sticky label, 167, 250.
\quad referring to objects by number, 148, 238.
\quad reflecting the map east-west, 102, 215.
\quad removing conversation actions, 117, 219.
\quad replicator, 119, 223.
\quad room divided by glass window, 166, 247.
\quad saving the character, 181, 252.
\quad Scrabble pieces, 144, 232.
\quad scuttling claws, 124, 228.
\quad silencing player, 128, 230.
\quad spaceship control panel, 161, 244.
\quad status line invisible, 181, 253.
\quad status line showing treasure, 181, 253.
\quad status line with centred room, 181, 254.
\quad status line with compass rose, 181, 254.
\quad sterilising machine, 167, 250.
\quad television set, 104, 216.
\quad the artiste formerly known as Princess, 147, 235.
\quad the player's wayhel, 129, 230.
\quad thief who wanders, 123, 226.
\quad third noun for parser, 162, 246.
\quad three denominations of coin, 145, 233.
\quad title page, 181, 252.
\quad tokens which never match, 162, 246.
\quad tomato in red or green, 147, 235.
\quad tricorder, 119, 222.
\quad troll afraid of the dark, 122, 226.
\quad Tyndale's Bible, 113, 218.
\quad varying the prompt, 135, 231.
\quad very verbose mode, 142, 231.
\quad weight--watching daemon, 123, 227.
\quad wild-card for a single object, 148, 238.
\quad wild-card for multiple objects, 148, 238.
\quad Zen flight computer, 119, 224.
exotic forms of death, 129.
expressions, 16.
{{\tt Extend}}, 154.
extensions for one actor only, 119, 221.
extensions of the library, 133.
external program, 69.
factorials, 23.
{{\tt Fake\_Action}}, 96.
fake actions, 150.
\quad defined in library, 199.
fake fake actions, 119.
{{\tt false}}, 14, 20.
``{\fam \ttfam \ninett *}'', 148, 238.
``{\fam \ttfam \ninett \#}'', 148, 238.
{\fam \ttfam \tentt Consult} action, 111.
{\fam \ttfam \tentt IsAWordIn} (example), 148.
fatal error, 74.
fatigue daemon, 227.
Fawlty Towers, 175.
{{\tt female}}, 138, 188.
filename translation, 65.
{{\tt first}}, 155.
five senses, 101.
fixed-pitch font, 175.
flag variables, 22.
flexible verbs, 156.
flight computer, 118, 224.
floating objects, 127, 187.
floating-point numbers, 160, 241.
``floor'', 196.
fluorescent jellyfish, 122.
fly in amber, 148, 238.
`focus' of game, 128.
`Follow my leader', 120.
``follower.h'', 120.
{{\tt font}}, 31, 175.
foodstuffs, 144.
footnotes, 159, 240.
{{\tt for}}, 25.
foreground colour, 179.
foreign languages, 135.
formatted text, 179.
{{\tt found\_in}}, 101, 127, 192.
four Gospels, 113, 218.
Frank Booth, 39.
Frankenstein, 128.
``free'' verb, 159.
`Freefall', 181.
French numbers, 160, 241.
fried green tomato, 145.
Frotz, 177, 178.
ftp site, 8.
\quad maximum number of, 174.
function keys, 180.
functions, 19.
\quad child, 46.
\quad children, 46.
\quad indirect, 35.
\quad metaclass, 46.
\quad parent, 46.
\quad random, 35.
\quad sibling, 46.
functions, built-in, 35.
fuses, 124.
G. K. Chesterton, 137.
Game Over choice, 135.
game transcript, 176.
{{\tt GamePostRoutine}}, 204.
{{\tt GamePreRoutine}}, 96, 204.
Gareth Rees, 8, 113, 120, 137, 145.
gas mask, 128, 230.
gender in parsing, 138.
{{\tt general}}, 85, 188.
general parsing routines, 160, 197.
genie, 156, 240.
gentleman thief, 123, 226.
Geoffrey's book, 139.
George Bernard Shaw, 162.
German `sz', 32.
giant magnet, 115.
Giant with a conscience, 129, 230.
girl playing Simon Says, 118, 220.
{{\tt Give}}, 114.
glass box, 104.
glass window, 166, 247.
\quad maximum number of, 174.
glue, 18.
glyphs, 112.
{{\tt Go}}, 100, 110.
goldfish bowl, 122.
``gonear'' verb, 171.
Gotham City, 107.
``goto'' verb, 171.
Graham Nelson, 8.
grammar, 152.
{{\tt Grammar}}, 83, 118, 192.
\quad definition of verbs, 153.
\quad extension of, 154.
\quad limits on, 173.
\quad lines of, 152.
\quad replacement of, 155.
\quad summary of rules about, 186.
\quad tokens of, 156.
Grantland Rice, 130.
grave accents, 32.
grouping of non-identical items in lists, 144.
groups of actions, 94.
\quad group 1, 198.
\quad group 2, 199.
\quad group 3, 199.
grues, 164.
Gustave Flaubert, 10.
hacker and urchin, 116.
Hamlet, 12.
hanging elses, 24.
{{\tt has}}, 52, 87.
`has light', 121.
{{\tt HasLightSource}}, 121, 196.
heaps of food, 144.
hearing (sense), 101.
\cstok{held} token, 157.
Hello World, 11.
help information, 65.
{{\tt herobj}}, 168.
hexadecimal numbers, 14.
hexadecimal, printing out, 34.
{{\tt himobj}}, 168.
``his'', 137.
hissing snake, 116.
hole in wall, 148.
holy searchlight, 107.
home page, 8.
honeycomb, 91.
horrid sludge, 139.
I Ching, 145, 233.
IBM PC, ugliness of, 179.
Icelandic characters, 32.
ICL, 64.
identifiers, 15.
{{\tt Ifdef}}, 67.
{{\tt Iffalse}}, 67.
{{\tt Ifndef}}, 67.
{{\tt Ifnot}}, 67.
{{\tt Iftrue}}, 67.
implicit taking, 158.
in scope, 162.
{{\tt Include}}, 66.
increment, 18.
{{\tt InDefArt}}, 196.
indefinite article, 138.
indexed variables, 38.
{{\tt indirect}}, 35, 171.
`indistinguishable', 149.
individual properties, 62.
Infix, 72, 171.
``Infoclues'', 177.
Infocom, Inc., 9.
Inform Command Language (ICL), 64.
Inform home page, 8, 136.
InfoTaskForce, 177.
inheritance, 52.
{{\tt initial}}, 85, 127, 192.
initial possessions, 126.
{{\tt Initialise}}, 84, 125, 126, 203, 204.
{{\tt inp1}}, 93, 248.
{{\tt inp2}}, 93, 248.
{{\tt @input\_stream}}, 180.
{{\tt InScope}}, 204, 226.
inside description, 109.
{{\tt inside\_description}}, 192.
instances, 52.
internal text format, 180.
interpreter, 11.
interpreters, 177.
{{\tt invent}}, 139, 193.
inventories, 139.
{{\tt inventory\_stage}}, 139, 144.
{{\tt inversion}}, 30.
invisible status line, 181, 253.
``Invisiclues'', 176, 177, 252.
irregular nouns, 191.
{{\tt item\_name}}, 177.
{{\tt item\_width}}, 177.
{{\tt itobj}}, 168.
Ivan O. Ideas, 130.
jackdaws, 241.
James Bond, 115.
James Shirley, 92.
Japanese cartoon, 216.
Jean de la Bruy{\accent 18 e}re, 126.
Jean Frederic Waldeck, 113.
Jekyll and Hyde, 69.
`Jigsaw', 73.
Joachim Baumann, 181.
John Christopher, 98.
John Cleese, 175.
John Donne, 9.
Jonathan Thackray, 9.
{{\tt jump}}, 28.
``junior astronaut", 204.
{{\tt keep\_silent}}, 95.
kestrels, 54.
keyboard, 179.
keyboard buffer, 146.
keyboard input (direct access to), 36.
King of Spades, 40.
{{\tt Kiss}}, 114.
`Knight of Ages', 125.
label, red sticky, 167, 250.
676 labelled buttons, 154.
labels (in programs), 29.
lamp (of genie), 156, 240.
large memory, 73.
{{\tt last}}, 155.
last resort, 135.
left/right associativity, 182.
legibility, 113.
{{\tt LetGo}}, 104.
library routines, 196.
{{\tt LibraryMessages}}, 97, 134.
{{\tt life}}, 114, 193.
ligatures, 32.
light, 121.
{{\tt light}}, 188.
\quad daylight, 125, 229.
\quad when it occurs, 121.
light switch, 166, 248.
limitations, 173.
line of sight, 124.
lines, 152.
{{\tt Link}}, 69.
linking, 69.
linking the library, 69.
{{\tt "linklpa.h"}}, 69.
{{\tt "linklv.h"}}, 70.
`List Property', 144.
list style, 142.
{{\tt list\_together}}, 193.
literal characters, 175.
little red car, 110, 218.
local variables, 15.
{{\tt Locale}}, 142, 197.
{{\tt location}}, 127.
``lock'' and ``unlock'' disambiguation, 169, 251.
{{\tt lockable}}, 188.
{{\tt locked}}, 103, 188.
Long Count, 164.
long description, 141.
long jump, 180.
{{\tt Look}}, 140.
``look inside'', 104.
{{\tt LookRoutine}}, 141, 204.
{{\tt LoopOverScope}}, 197.
{{\tt LOOPOVERSCOPE\_REASON}}, 166.
Lord Byron, 83.
Louis MacNeice, 7, 214.
low mist, 101.
low numbers in French, 160, 241.
{{\tt Lowstring}}, 215.
Ludwig Wittgenstein, 114, 137.
Macbeth, 126.
macram{\accent 19 e} bag, 105, 217.
magpie, 49.
Mahu, 227.
mainframe `Adventure', 8.
making grammar, 95.
{{\tt male}}, 138, 188.
Manga, 216.
map, 105.
map connection, 99.
Marc Blank, 105, 109.
Martha, 120, 225.
``master catburglar", 204.
matchbook, 140.
Max Beerbohm, 162.
{{\tt MAX\_CARRIED}}, 130.
{{\tt MAX\_SCORES}}, 131.
{{\tt MAX\_TIMERS}}, 124.
Mayan dictionary, 113.
Mayan directions, 102, 215.
``me'', 128.
meadow example, 46.
medicine bottle, 89.
medieval French, 135.
``megalook'' verb, 163, 246.
members, 52.
memory, 73.
\quad compiler settings, 73.
\quad dynamic allocation, 174.
\quad maximum size of game, 173.
\quad small, large or huge, 73.
\quad typical consumption of by compiler, 73.
memory settings, 64.
{{\tt menu\_item}}, 177.
menu of text options, 176.
message, 44.
{{\tt Message}}, 68.
message numbers, 135.
messages, 54.
\quad call, 60.
\quad copy, 61.
\quad create, 61.
\quad destroy, 61.
\quad parrot example, 89.
\quad print, 60.
\quad print to array, 60.
\quad recreate, 61.
\quad remaining, 61.
\quad to routines, strings and classes, 60.
``messages'', 55.
``messages'' verb, 171.
{{\tt meta}}, 153.
`meta' actions, 94.
metaclass, 210.
{{\tt metaclass}}, 45.
metaclass, definition of, 45.
Metropolitan Museum, 90.
Michel de Montaigne, 113.
microphones, 117.
mid-air location, 125.
midnight, 125.
Modo, 227.
Modular extensions, 133.
modules, 69.
Moli{\accent 18 e}re, 151.
Monty Python's Flying Circus, 103.
{{\tt moved}}, 166, 189.
moving room, 127.
Mrofni, 120, 225.
\cstok{multiexcept} token, 157.
\cstok{multiheld} token, 157.
multiple inheritance, 54.
mummified priest, 115.
`Museum of Inform', 8.
mushroom, 84.
``myself'', 128.
nagual, 129, 230.
{{\tt name}}, 50, 99, 145, 194.
named rooms, 156, 239.
names per object (limit), 174.
Naming of Cats, 145.
narrow inventory, 143.
neo-Platonist philosophy, 123.
NetHack, 178.
{{\tt neuter}}, 138, 189.
New Testament, 113, 218.
{{\tt NewRoom}}, 127, 204.
{{\tt NextWord}}, 146, 160, 161, 197, 245.
{{\tt NextWordStopped}}, 160, 197.
nightfall, 125, 229.
{{\tt @nn}}, 215.
{{\tt NO\_PLACES}}, 132.
nominative pronoun, 137, 231.
normal rules, 187.
{{\tt NormalWorld}}, 215.
`northness', 196.
nose, 167, 249.
Noslen Maharg, 120, 225.
{{\tt nothing}}, 45, 172.
{{\tt notify\_mode}}, 132.
``notify'' verb, 132.
{{\tt NotUnderstood}}, 116, 117.
{{\tt noun}}, 100.
\cstok{noun} token, 157.
{{\tt NounDomain}}, 197, 246.
{{\tt NULL}}, 87.
{{\tt number}}, 85, 194.
number base, 14.
number puzzle, 28.
{{\tt NUMBER\_TASKS}}, 131.
\cstok{number} token, 157.
number-parsing, 159.
numbers, 13.
{{\tt Object}}, 45, 87.
object 31, 148.
object orientation, 10.
\quad virtue of, 44.
{{\tt OBJECT\_SCORE}}, 131.
object tree, 45.
\quad setting up initial state, 46.
{{\tt ObjectIsUntouchable}}, 197.
{{\tt ObjectIsUntouchable(obj)}}, 164.
objects, 44, 84.
\quad child, sibling and parent of, 46.
\quad creation and deletion during play, 61.
\quad defined in library, 196.
\quad definite articles of, 138.
\quad direction and compass objects, 102.
\quad duplicate and plural, 149.
\quad encapsulation of, 51.
\quad giving attributes to, 52.
\quad giving properties to, 49.
\quad grouping of in lists, 144.
\quad indefinite articles of, 138.
\quad inheritance from classes, 52.
\quad inventory entries of, 139.
\quad listed in room descriptions, 141.
\quad maximum number of, 174.
\quad maximum number of names for, 174.
\quad metaclass of, 45.
\quad moving around the tree, 47.
\quad names of, 145.
\quad philosophy of, 57.
\quad printing lists of, 142.
\quad referred to by number, 148, 238.
\quad removing from tree, 48.
\quad sending messages to, 54.
\quad short names of, 137.
\quad the four kinds of, 44.
``objects'' verb, 132.
obsolete interpreters, 181.
obsolete usages, 82.
Occitan, 135.
Octagonal Room, 56.
{{\tt ofclass}}, 54.
`offers light', 121.
{{\tt OffersLight}}, 121, 197.
ogre with limited patience, 124.
Oliver Goldsmith, 173.
{{\tt on}}, 107, 189.
``on'', ``at'' or ``in'', 160.
once-only rules, 87.
{{\tt only}}, 155.
{{\tt open}}, 103, 189.
{{\tt openable}}, 103, 189.
operands, 16.
operator precedence, 17.
operators, 16.
\quad full table of, 182.
orange cloud, 102, 215.
{{\tt Order}}, 114.
{{\tt orders}}, 116, 128, 193.
ornate box, 140, 231.
other four senses, 101.
``out'' verb, 110.
{{\tt @output\_stream}}, 180.
{{\tt //p}}, 150.
P. David Lebling, 103, 105, 109, 119.
pack of cards, shuffling, 40.
packing case, 104.
pairs of verbs to separate, 155.
Palladas of Alexandria, 64.
{{\tt parent}}, 46, 172.
parentheses, 17.
parrot, 89.
{{\tt parse}}, 161.
{{\tt parse\_name}}, 147, 150, 163, 194.
{{\tt parsed\_number}}, 160, 187.
{{\tt ParseNoun}}, 148, 204.
{{\tt ParseNumber}}, 159, 204.
parser, 146.
{{\tt Parser}}, 83.
\quad breaking up text into word stream, 146.
\quad error numbers, 168.
\quad parsing quoted strings, 161, 245.
\quad parsing the player's questions, 164.
\quad tidying up questions asked by, 156.
\quad tracing and levels, 172.
{{\tt parser\_one, parser\_two, parser\_action}}, 150.
{{\tt ParserError}}, 168, 204.
\quad text buffer holding commands, 146, 161.
{{\tt PARSING\_REASON}}, 166.
path variables, 64.
peculiar book, 139.
Pepper Room, 92.
Percy Bysshe Shelley, 123.
perfectionism, 99.
persona of player, 128.
pet moth, 122, 226.
philosophy of objects, 57.
phone number, 146.
phone number parsing, 160, 242.
pidgin English, 142.
pinfocom, 177.
{{\tt PlaceInScope}}, 165, 197.
``places'' verb, 132.
plagiarism, 130.
plank bridge, 107, 217.
platinum pyramid, 140.
Plato, 123.
player's origin, 126.
player-object, 196.
{{\tt PlayerTo}}, 127, 197.
{{\tt plural}}, 149, 194.
plural markings on words, 150.
plural objects, 149.
{{\tt pluralname}}, 138, 189.
``pluralobj.h'', 136.
portability, 10.
precedence of class inheritance, 91.
precedence of operators, 17.
prepositions, 157.
{{\tt pretty\_flag}}, 176.
priest, 114.
Prince of darkness, 227.
Princess, 147, 235.
{{\tt print}}, 60, 100.
{{\tt print (a) obj}}, 137.
{{\tt print (address)}}, 172.
{{\tt print (name) obj}}, 137.
{{\tt print (string)}}, 172.
{{\tt print (The) obj}}, 137.
{{\tt print object}}, 138, 172.
{{\tt print\_to\_array}}, 60.
printf exercise, 181, 255.
printing hexadecimal numbers, 34.
printing output, 29.
printing routines, 137.
printing rules, 34.
{{\tt PrintRank}}, 131, 204.
{{\tt PrintShortName}}, 197.
{{\tt PrintTaskName}}, 131, 204.
{{\tt PrintVerb}}, 156, 204.
{{\tt private}}, 51.
procedural language, 10.
prompt, 135, 176, 231.
pronouns, 116, 137, 168, 231.
{{\tt PronounValue}}, 168.
{{\tt proper}}, 138, 189.
proper noun, 138.
properties, 85.
\quad additive, 91.
\quad common vs individual, 62.
\quad defined in library, 190.
\quad defining new common, 134.
\quad definition of, 49.
\quad encapsulation of, 51.
\quad holding arrays, 50.
\quad holding routines, 51, 89.
\quad maximum number of common, 174.
{{\tt Property}}, 69.
proportional font, 175.
{{\tt provides}}, 49, 51.
pumice ball, 111, 218.
punctuation in dictionary words, 146.
``purloin'' verb, 165, 171, 247.
purple liquid, 139.
{{\tt PushDir}}, 110.
pygmy statuette, 90.
questionable practices, 82.
questions, asking yes or no, 175.
questions, parsing the player's, 164.
{{\tt quit}}, 28.
quotation marks (continental European), 32.
quotations beautiful, 176.
quoted text, 246.
``quotes off'' verb, 176.
R. B. Sheridan, 132.
radio, 124.
radix, 14.
{{\tt random}}, 35, 171.
``random'' verb, 171.
raw text, 161.
reached, statement which cannot be, 33.
{{\tt react\_after}}, 115, 194.
{{\tt REACT\_AFTER\_REASON}}, 166.
{{\tt react\_before}}, 101, 115, 194.
{{\tt REACT\_BEFORE\_REASON}}, 166.
{{\tt read}}, 36, 43.
{{\tt @read\_char}}, 180.
``read'' v. ``examine'', 113.
reading books, 111.
{{\tt real\_location}}, 127.
real time, 179.
reasons for scope searching, 166.
{{\tt Receive}}, 104.
{{\tt receive\_action}}, 104.
receiving messages, 55.
``recording'' verb, 171.
recursion, 23.
recursion (limit), 174.
red sticky label, 167, 250.
red-tailed parrot, 89.
reflecting the map, 102, 215.
remainder, 16.
removing conversation actions, 117, 219.
removing rules, 87.
{{\tt REPARSE\_CODE}}, 197, 246.
{{\tt Replace}}, 135, 155.
replacing grammar, 155.
``replay'' verb, 171.
replicator, 119, 223.
resolution, 146, 173.
resolving ambiguity, 169.
{{\tt @restore}}, 181.
restoring data, 181.
resurrection, 129.
return values, 19.
{{\tt reverse}}, 154, 186.
reverse video, 177.
{{\tt ReversedWorld}}, 215.
Richard Barnett, 102.
ring accents, 32.
`Robots', 181.
role-playing games, 181, 252.
roman text, 177.
`Romeo and Juliet', 30.
room descriptions, 108, 140.
room divided in half, 166, 247.
{{\tt ROOM\_SCORE}}, 131.
Rosencrantz, 12.
{{\tt Routine}}, 45.
routines, 19.
\quad as property values, 89.
\quad maximum depth of recursion, 174.
\quad simple example of, 86.
\quad tracing calls to, 172.
routines as property values, 51.
``routines'' verb, 171.
Royal Society For Putting Things On Top Of Other Things, 103.
rucksack, 158.
`Ruins', 8, 83, 87, 88, 89, 90, 92, 98, 101, 103, 104, 105, 107, 109, 110, 112, 114, 124, 126, 130, 131, 181, 218, 228, 252.
run-time crashes, 17, 171.
run-time format, 173.
running out of memory, 75.
{{\tt SACK\_OBJECT}}, 130.
Sam Hulick, 125.
satchel, 130.
{{\tt @save}}, 180.
saving data, 180.
saving the character, 181, 252.
{{\tt scenery}}, 99, 141, 189.
scenery penalised, 169.
scope, 162.
\quad addition to, 105, 166.
\quad looping over, 163.
\quad testing, 163.
{{\tt scope\_reason}}, 120, 124, 166.
{{\tt scope\_stage}}, 164.
``scope'' verb, 171.
``scope'' verb exercise, 163, 246.
{{\tt ScopeWithin}}, 197.
score notification, 132.
``score'' verb, 153.
{{\tt scored}}, 189.
scoring in `Ruins', 90.
scoring systems, 130.
Scott Adams, 8, 142.
Scrabble pieces, 144, 232.
screen, 120, 225.
script of player's commands, 180.
scrolling screen, 176.
scuttling claws, 124, 228.
sealed room, 120, 225.
{{\tt Search}}, 94, 104.
searchlight, 107.
{{\tt second}}, 100.
`see-through', 162.
{{\tt self}}, 53, 56.
{{\tt selfobj}}, 196.
semicolons, 11.
{{\tt sender}}, 56.
senses, 101.
{{\tt @set\_colour}}, 179.
{{\tt @set\_cursor}}, 179.
{{\tt @set\_window}}, 179.
{{\tt SetTime}}, 125, 197.
shaft of sunlight, 99.
``shazam'' verb, 156.
`Shell', 83.
shopping mall, 135.
{{\tt short\_name}}, 138, 195.
{{\tt short\_name\_indef}}, 195.
{{\tt Show}}, 114.
``showobj'' verb, 171.
{{\tt ShowR}}, 225.
``showverb'', 153.
``showverb'' verb, 171.
Shrine, 114, 116.
shuffling a pack of cards, 40.
{{\tt sibling}}, 46.
silence, imposition on player, 128, 230.
silent actions, 95.
Simon Says, 118, 220.
`Skyfall' setup file, 66.
slash accents, 32.
small memory, 73.
small prime numbers, 39.
Smalltalk-80, 45, 57, 59.
``smartcantgo.h'', 102.
smell (sense), 101.
snake, 116.
``snavig'' spell, 128.
sodium lamp, 108.
`Sorcerer', 126, 170.
sound of scuttling claws, 124, 228.
source-level debugger, 171.
Space Invaders, 178.
{{\tt spaces}}, 30.
spaceship control panel, 161, 244.
Spanish punctuation, 32.
{{\tt special\_number}}, 114.
special objects, 196.
\cstok{special} token, 157.
speckled mushroom, 84.
`Spellbreaker cubes', 150.
`Spellbreaker', 102, 128, 198.
spiny trees, 100.
{{\tt @split\_window}}, 179.
Square Chamber, 99.
squawking, 89.
St John Passion, 31.
St Peter, 151.
stack frame, 180.
stack usage (limit), 174.
Standard games, 173.
Standard interpreters, 181.
Star Trek: The Next Generation, 119, 120, 222, 223, 225.
`Starcross', 117, 118, 220.
Starship Enterprise, 120, 225.
{{\tt StartDaemon}}, 123, 197.
{{\tt StartTimer}}, 124, 197.
statement cannot be reached, 33, 81.
statements, 12.
\quad box, 30.
\quad do...until..., 26.
\quad font, 31.
\quad for, 26.
\quad give, 52.
\quad if, 21.
\quad if...else..., 24.
\quad inversion, 30.
\quad jump, 29.
\quad move, 47.
\quad new line, 30.
\quad objectloop, 48.
\quad print, 12, 33.
\quad quit, 29.
\quad read, 36, 42.
\quad remove, 48.
\quad restore, 29.
\quad return, 20.
\quad save, 29.
\quad spaces, 30.
\quad style, 31.
\quad summary table of, 184.
\quad switch...default..., 25.
\quad while, 26.
{{\tt static}}, 106, 189.
statistics, 72.
status line, 175, 253.
{{\tt Statusline}}, 125.
stealing actions, 101.
steel box, 104.
steel grate, 106.
Stephen Fry, 57.
sterilising machine, 167, 250.
stone altar, 109.
stone door, 105.
stone-cut steps, 87, 88.
{{\tt StopDaemon}}, 123, 198.
{{\tt StopTimer}}, 124, 198.
story files, 7.
stream of words, 146.
stream running through forest, 124.
streams of input/output, 180.
{{\tt string}}, 39, 45, 215.
{{\tt (string)}}, 34.
strings of characters, 39.
structures of data, 36.
{{\tt Stub}}, 68.
{{\tt style}}, 31, 177.
style of list, 142.
sub-objects, 105, 166.
subclasses, 54.
summary of grammar, 186.
sunrise and sunset, 125, 229.
``superbrief'', 198.
superclass operator, 57.
superclass, definition of, 57.
{{\tt supporter}}, 103, 109, 189.
supporting scenery, 141.
{{\tt switch}}, 23.
{{\tt switchable}}, 107, 189.
{{\tt Switches}}, 71.
switches (command line), 64.
switches (on command line), 71.
sword, 124.
synonyms, 152.
{{\tt System\_file}}, 68, 82, 133.
T. S. Eliot, 145.
{{\tt table}}, 39.
``take all'', 169.
``take'' verb, 153.
{{\tt talkable}}, 117, 189.
{{\tt TALKING\_REASON}}, 120, 166.
talking, preventing player from, 128, 230.
tape recorders, 117.
tapestry and key, 87.
{{\tt task\_scores}}, 131.
{{\tt TASKS\_PROVIDED}}, 131.
taste (sense), 101.
team of four adventurers, 128.
Ted Hughes, 252.
tedium of magpies, the, 52.
telegraphese, 142.
telekinesis, 120, 225.
telepathic contact, 120, 225.
telephone number parsing, 160, 242.
teleportation, 127.
television set, 104, 216.
{{\tt Tell}}, 114.
temperature dial, 166.
Tera, 9.
{{\tt TestScope}}, 198.
{{\tt TESTSCOPE\_REASON}}, 166.
text buffer (of buffer), 146.
text buffer (of parser), 161.
text buffers, 39.
text cursor, 179.
text formatting, 179.
text of a command, 146.
text style, 177.
`The Legend Lives', 159.
The Prisoner, 110.
The quick brown fox jumped over the lazy dog, 241.
the Sun, 101.
`The Thief', 120, 145, 226.
`The Witness', 135.
{{\tt thedark}}, 127, 196.
{{\tt TheSame}}, 150.
thief in `Zork', 123, 124, 226.
third parameter for parser, 162, 246.
three denominations of coin, 145, 233.
{{\tt @throw}}, 180.
``throw rock at dalek'', 95.
{{\tt ThrowAt}}, 96, 114.
{{\tt ThrownAt}}, 96.
tidying-up operations, 123.
tilde, 52.
tilde accents, 32.
{{\tt time\_left}}, 195.
time of day, 125.
time of day (parsing), 161, 243.
{{\tt time\_out}}, 124, 195.
time sequence, 125.
timed input, 179.
{{\tt TimePasses}}, 204.
timers, 124.
\quad clash with daemons, 124.
\quad maximum number active, 124.
\quad starting and stopping, 124.
``timers'' verb, 171.
`timewait.h', 126, 161.
Timothy Anderson, 109.
title page, 181, 252.
{{\tt TitlePage}}, 127.
toadstool poisoning, 86.
token for `any object', 247.
token never matching anything, 162, 246.
{{\tt @tokenise}}, 180.
tokenising, 179, 246.
tokens, 152, 156, 197.
tomato, 145.
Tony Harrison, 64.
too many errors, 74.
toothed bag, 104, 216.
\cstok{topic} token, 160.
Torbj\o rn Andersson, 181.
touch (sense), 101.
touchability, 163.
`Toyshop', 8, 91, 102, 105, 120, 126, 130, 131, 140, 245.
``trace'' verb, 171.
tracing a routine, 172.
tracing routines, actions, daemons and timers, 171.
tracing the parser, 172.
transcript, 176, 179, 180.
translating Inform to foreign languages, 135.
{{\tt transparent}}, 104, 116, 189.
treasure class, 90.
treasures on status line, 181, 253.
treating {\fam \ttfam \tentt name} as a word array, 145.
``tree'' verb, 171.
tricorder, 119, 222.
trigrams, 145, 233.
`Trinity', 102, 181, 255.
troll, 122.
{{\tt true}}, 14, 20.
{{\tt TryNumber}}, 146, 198.
two-way door, 106.
txd (disassembler), 171.
UHS format hints, 177.
umlaut accents, 32.
unary minus, 18.
underlining, 177.
``undo'' verb, 174, 177.
{{\tt UnknownVerb}}, 156, 204.
{{\tt UnsignedCompare}}, 198.
{{\tt until}}, 25.
untouchability, 164.
untypeable verbs, 119.
untypeable words, 146.
upper-level window, 179.
urchin and hacker, 116.
``use'' verb, 158.
{{\tt vague\_obj}}, 168.
{{\tt vague\_word}}, 168.
values as conditions, 22.
vampire, 125.
variable strings, 215.
variables, 13.
variables (concept of), 15.
vehicles, 110.
{{\tt Verb}}, 153.
{{\tt verb\_num}}, 118.
{{\tt verb\_word}}, 152, 169.
{{\tt VerbLib}}, 83.
verbose mode, 142.
``verbose", 141.
``verbose'', 198.
verbs (Inform and English), 152.
versions of the Z-machine, 173.
very verbose mode, 142, 232.
{{\tt visited}}, 189.
{{\tt VN\_****}}, 68.
vocabulary size (limit), 173.
voice-activated computers, 117.
vowel-contraction, 191.
VT100, 177.
W. H. Auden, 105.
W. S. Gilbert, 142.
{{\tt WakeOther}}, 114.
Waldeck's Mayan dictionary, 113.
walking into walls, 134.
walls, 196.
`wandering monsters', 123.
warning, 74.
warning messages, 13.
warning messages (list), 80.
warthog, 230.
washing-machine, 166.
weights, 123.
weird thing, 147.
`welcome' message, 84.
``what is a grue'', 164.
``What next?'', 135, 231.
{{\tt when\_closed}}, 106, 195.
{{\tt when\_off}}, 195.
{{\tt when\_on}}, 195.
{{\tt when\_open}}, 106, 195.
{{\tt while}}, 25.
white space, 11.
``white'' and ``black'', 156, 240.
wide inventory, 143.
wild boar, 228.
wild-card, 148, 238.
Will Crowther, 9.
William J. Clinton, 32.
William Shakespeare, 30, 126, 162, 227, 239, 253.
William Tyndale, 113, 218.
window 0, 179.
wingspan, 49.
{{\tt with}}, 49, 87.
{{\tt with\_key}}, 103, 195.
{{\tt WITHOUT\_DIRECTIONS}}, 102.
`Witness', 135, 231.
wizened man, 146.
woodpecker, 170.
word array, 145.
word arrays, 38.
word breaking, 146, 179.
word stream, 146.
{{\tt WordAddress}}, 146, 161, 198, 245.
{{\tt WordLength}}, 146, 161, 198, 245.
{{\tt workflag}}, 189.
world colours, 102, 215.
World Wide Web, 8.
{{\tt worn}}, 189.
{{\tt WriteListFrom}}, 142, 198.
``xyzzy'' verb, 154.
yes or no questions, primitive routine to ask, 43.
{{\tt YesOrNo}}, 175, 198.
``you don't need to refer to'', 99.
Z-encoded text, 180.
\quad testing, 181.
Zen, 117, 224.
``zero'', 159.
Zip, 177, 178.
`Zork I', 124.
`Zork', 120, 123.
{{\tt ZRegion}}, 198.
zterp, 177.
\endindex
\tenpoint
%\closeout\conts
\end
% --------------------------------------------------------------------------