-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathLearningZIL.tex
More file actions
4465 lines (3777 loc) · 182 KB
/
LearningZIL.tex
File metadata and controls
4465 lines (3777 loc) · 182 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
%% LyX 2.3.1-1 created this file. For more info, see http://www.lyx.org/.
%% Do not edit unless you really know what you are doing.
\documentclass[ngerman,english,openany]{scrbook}
\renewcommand{\ttdefault}{cmtt}
\usepackage[T1]{fontenc}
\usepackage[a4paper]{geometry}
\geometry{verbose,tmargin=2cm,bmargin=2cm,lmargin=2.5cm,rmargin=2cm,headheight=1cm,headsep=0.5cm,footskip=1cm}
\usepackage{fancyhdr}
\pagestyle{fancy}
\setcounter{secnumdepth}{3}
\setcounter{tocdepth}{3}
\usepackage{babel}
\usepackage{textcomp}
\PassOptionsToPackage{normalem}{ulem}
\usepackage{ulem}
\usepackage[unicode=true,
bookmarks=true,bookmarksnumbered=false,bookmarksopen=false,
breaklinks=false,pdfborder={0 0 0},pdfborderstyle={},backref=false,colorlinks=false]
{hyperref}
\hypersetup{pdftitle={Learning ZIL},
pdfauthor={Steven Eric Meretzky},
pdfsubject={Everything You Always Wanted to KnowAbout Writing Interactive FictionBut Couldn't Find Anyone Still Working Here to Ask},
pdfkeywords={Infocom ZIL Zork IF IntFiction Interactive Fiction}}
\makeatletter
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% LyX specific LaTeX commands.
\newcommand{\noun}[1]{\textsc{#1}}
%% Because html converters don't know tabularnewline
\providecommand{\tabularnewline}{\\}
\makeatother
\usepackage{listings}
\lstset{xleftmargin=25pt}
\addto\captionsenglish{\renewcommand{\lstlistingname}{Listing}}
\addto\captionsngerman{\renewcommand{\lstlistingname}{Listing}}
\renewcommand{\lstlistingname}{Listing}
\begin{document}
\title{Learning ZIL}
\subtitle{or\\
~\\
Everything You Always Wanted to Know\\
About Writing Interactive Fiction\\
But Couldn't Find Anyone Still Working Here to Ask}
\author{Steven Eric Meretzky (SEM)}
\date{8/1/95}
\publishers{Copyright \textcopyright 1989 Infocom, Inc. \\
For internal use only. \\
Comments to SEM}
\maketitle
\tableofcontents{}
\chapter{The Basics}
\section{The Basic Ingredients}
When you write interactive fiction (hereafter IF), you will mostly
be dealing with two kinds of things: objects and routines. There are
two major categories of objects: rooms (such as the Living Room in
\emph{\noun{Zork I}} or Joe's Bar in \emph{\noun{Leather Goddesses}}),
and objects you can refer to, such as the brass lantern in \emph{\noun{Zork
I}} or the dressing gown in \emph{\noun{Hitchhiker's Guide}}.
Routines are little sub-programs which perform a whole variety of
functions. There are many kinds of routines, but the kind you'll be
concerned with first are called action routines. These are directly
linked to a room or object. Much more detail on objects and routines
in subsequent chapters.
\section{The Handler}
In IF, the player types an input, and the game must produce a response:
\begin{lstlisting}[basicstyle={\ttfamily},xleftmargin=25pt]
>HIT UNCLE OTTO WITH THE HAMMER
You knock some sense back into Uncle Otto, and he stops
insisting that he's Napoleon Bonaparte.
\end{lstlisting}
Somewhere, the game decided to print that response. The part of the
game that printed that response is said to have handled the input.
The input must be handled at some point; a non-response is always
a no-no:
\begin{lstlisting}[basicstyle={\ttfamily},xleftmargin=25pt]
>UNCLE OTTO, REMOVE YOUR HAND FROM YOUR SHIRT
>
\end{lstlisting}
\section{The Parser's Role}
There's a notorious part of every IF program called the parser. It
gets the first look at the input. If it decides that the input is
indecipherable, for any of several reasons, it handles the input.
For example:
\begin{lstlisting}[basicstyle={\ttfamily},xleftmargin=25pt]
>EXAMINE THE FLEECY CLOUD
[I don't know the word "fleecy."]
>ASK UNCLE OTTO ABOUT MOSCOW AND WATERLOO
[You can't use multiple objects with the verb "ask."]
\end{lstlisting}
Cases like these are called parser failures. (This is not to be confused
with those times when the parser fails, which are called parser bugs.)
If the parser succeeds in digesting the input, it passes three pieces
of information on to the rest of the program: the verb, the direct
object, and the indirect object. Internally, these are called PRSA,
PRSO, and PRSI. In the first example in section 1.1, PRSA is HIT,
PRSO is the UNCLE OTTO object, and PRSI is the HAMMER object.
Not every input has a PRSI. For example, in:
\begin{lstlisting}[basicstyle={\ttfamily},xleftmargin=25pt]
>CALL THE FUNNY FARM
Men in white coats arrive and hustle Uncle Otto into
the wagon.
\end{lstlisting}
the verb is CALL and the PRSO is the FUNNY FARM object. In such a
case, when there is no PRSI, the parser sets the value of PRSI to
false. Furthermore, not every input has a PRSO. Some examples of inputs
where PRSO and PRSI are both false:
\begin{lstlisting}[basicstyle={\ttfamily},xleftmargin=25pt]
>YELL
>PANIC
>INVENTORY
\end{lstlisting}
Note that you cannot have a PRSI without also having a PRSO. Also
note that every input has a PRSA.
\section{The Basic Handling Sequence}
After the parser identifies PRSA, PRSO, and PRSI, the game gets to
decide who will handle the input. By convention, PRSI gets the first
crack (providing there is a PRSI, of course).
What this means, is that if PRSI has an associated object action routine,
that action routine tries to handle the input. If it does so, the
current turn is considered to be complete. If not, then the PRSO's
action routine is given the opportunity next. The PRSO and PRSI routines
can give very specific responses to the input.
If the PRSO also fails to handle the input, the task falls to the
routine associated with the verb. Because such a routine is the \textquotedbl last
resort,\textquotedbl{} and since it usually gives a very general response,
it is called the default response. Here's an example of how the response
to an input might look depending on who handled it:
\begin{lstlisting}[basicstyle={\ttfamily},xleftmargin=25pt]
>HIT THE OAK CHEST WITH THE CROWBAR
The crowbar bends! It appears to be made of rubber, not
iron!
\end{lstlisting}
\selectlanguage{ngerman}%
$\rightarrow$\foreignlanguage{english}{ (handled by PRSI's action
routine)}
\selectlanguage{english}%
\begin{lstlisting}[basicstyle={\ttfamily},xleftmargin=25pt]
The sound of the impact reverberates inside the chest.
\end{lstlisting}
\selectlanguage{ngerman}%
$\rightarrow$\foreignlanguage{english}{(handled by the PRSO's action
routine)}
\selectlanguage{english}%
\begin{lstlisting}[basicstyle={\ttfamily},xleftmargin=25pt]
Hitting the oak chest accomplishes nothing.
\end{lstlisting}
\selectlanguage{ngerman}%
$\rightarrow$\foreignlanguage{english}{(handled by the verb default)}
\selectlanguage{english}%
\medskip{}
As you can see, the verb default is the least interesting and \textquotedbl colorful\textquotedbl{}
of the responses. Of course, there's not enough space on the disk
or time in the schedule to give every possible input its own special
response; a good implementor must find the proper balance, deciding
when to write a special colorful response, and when to let the relatively
drab verb default do the handling.
There are other places where the game gets a chance to handle the
input, but we'll get to that later on.
\chapter{Creating Rooms}
\section{What a Typical Room Definition Looks Like}
Here's what the definition of the Living Room from Zork I looks like:
\begin{lstlisting}[basicstyle={\ttfamily},xleftmargin=25pt]
<ROOM LIVING-ROOM
(LOC ROOMS)
(DESC "Living Room")
(EAST TO KITCHEN)
(WEST TO STRANGE-PASSAGE IF CYCLOPS-FLED ELSE
"The wooden door is nailed shut.")
(DOWN PER TRAP-DOOR-EXIT)
(ACTION LIVING-ROOM-F)
(FLAGS RLANDBIT ONBIT SACREDBIT)
(GLOBAL STAIRS)
(THINGS <> NAILS NAILS-PSEUDO)>
\end{lstlisting}
Note that, as with everything you will ever write in ZIL, the parentheses
and angle brackets are balanced.
Let's go over this room definition line by line. The first thing in
a room definition is the word ROOM followed by the internal name of
the room. This name, like all names of objects or routines in ZIL,
must be one word (or, if more than one word, connected by hyphens)
and must be all capital letters.
The second line, LOC, gives its internal location. All rooms are located
in a special object called the ROOMS object.
The third line is the external name of the room, its DESC. This is
what will appear in the output each time a player enters that room.
Note: The internal and external names of a room (or object) do not
need to be identical. For example, there's no reason the internal
name couldn't be LIV-ROOM. It's up to the author. Usually, it's a
trade-off: using the same name makes it easier to remember the internal
name, but it means more typing.
\section{Exits}
The next several lines are all the exits from the Living Room. In
general, the bulk of a room definition is its exits. The fourth line,
(EAST TO KITCHEN), is an example of the simplest kind of exit, called
a UEXIT (for unconditional exit). This means that when the player
is in the Living Room and types EAST, the player will go to the Kitchen
\textemdash{} in all cases.
The fifth line is a CEXIT (for conditional exit). If involves a global
called CYCLOPS-FLED. A global is the simplest way that you store a
piece of information in ZIL. (See section 5.2 and section 7.2.) In
this case, CYCLOPSFLED is either true or false depending on whether
the cyclops has made a hole in the oak door. What this CEXIT means
is that when the player types WEST, the player will be sent to Strange
Passage if the global CYCLOPS-FLED is true. If CYCLOPS-FLED is false,
the player will be told \textquotedbl The door is nailed shut.\textquotedbl{}
This piece of text inside quotes is called a string. The string is
not required for a CEXIT; if it is omitted, the game will supply a
default string like \textquotedbl You can't go that way.\textquotedbl{}
The sixth line is an example of an FEXIT (for function exit). (Function
is another word for routine.) The game will recognize this line as
an FEXIT because of the \textquotedbl PER.\textquotedbl{} In this
case, if the player types DOWN, the routine called TRAP-DOOREXIT decides
if the player can move, and if so, to where, and if not, what the
response should be. In this case, it will say \textquotedbl You can't
go that way.\textquotedbl{} if you haven't moved the rug, or \textquotedbl The
trap door is closed.\textquotedbl{} if you have moved the rug but
haven't opened the trap door.
There are two other types of exits, which don't happen to be used
by the Living Room in Zork I. The NEXIT (for non-exit) is simply a
direction in which you can never go, but for which you want something
more interesting than the default \textquotedbl You can't go that
way.\textquotedbl{} response. The game will recognize it as an NEXIT
because of the use of \textquotedbl SORRY.\textquotedbl{} It might
look something like this:
\begin{lstlisting}[basicstyle={\ttfamily},xleftmargin=25pt]
(NW SORRY "The soldier at Uncle Otto's front door
informs you that only Emperor Bonaparte is allowed
through.")
\end{lstlisting}
The other is the DEXIT (for door exit). This is similar to the CEXIT,
substituting the condition of a door object for the global. It might
look something like this. Note the \textquotedbl IS OPEN\textquotedbl{}
which isn't found in a CEXIT:
\begin{lstlisting}[basicstyle={\ttfamily},xleftmargin=25pt]
(SOUTH TO GARAGE IF GARAGE-DOOR IS OPEN ELSE
"You ought to use the garage door opener.")
\end{lstlisting}
If the GARAGE-DOOR object is open, and the player types SOUTH, you'll
end up in the GARAGE. Else, the player will be told the string. Once
again, the string is optional. If no string is supplied, the response
will be something like \textquotedbl You'll have to open the garage
door, first.\textquotedbl{}
\section{Other Parts of a Room Definition}
Getting back to the Living Room example, the next line defines the
room's action routine, LIVING-ROOM-F. (The F at the end is short for
\textquotedbl function.\textquotedbl ) You'll hear (a lot) more
about a room's action routine in a while.
The next line contains those FLAGS which are applicable to this room.
RLANDBIT (the R is for \textquotedbl room\textquotedbl ) means that
the room is on dry land, rather than water (such as the Reservoir)
or in the air (such as the volcano rooms in Zork II). ONBIT means
that the room is always lit. Some flag names appear in every game;
but you can make up special ones to fit the requirements of your own
game. For example, SACREDBIT is special to Zork I, and means that
the thief never visits this room. By convention, all flag names end
with \textquotedbl BIT.\textquotedbl{} For a complete list of commonly
used flags, see Appendix B.
Forget about the GLOBAL and THINGS lines for now. You'll learn about
the GLOBAL property in section 7.4, and can read about THINGS in Appendix
A. All these things \textemdash{} EAST, UP, FLAGS, ACTION, etc. \textemdash{}
are called properties. As you'll see in a moment, objects have properties
as well; some are the same as the properties that rooms have, but
some are different. Although most properties are the same from game
to game, you may occasionally want to create your own. For a complete
list of commonly used properties, see the Appendix A.
\chapter{Creating Objects}
\section{What an Object Definition Looks Like}
Here's what the definition of Zork I's brass lantern looks like:
\begin{lstlisting}[basicstyle={\ttfamily},xleftmargin=25pt]
<OBJECT LANTERN
(LOC LIVING-ROOM)
(SYNONYM LAMP LANTERN LIGHT)
(ADJECTIVE BRASS)
(DESC "brass lantern")
(FLAGS TAKEBIT LIGHTBIT)
(ACTION LANTERN-F)
(FDESC "A battery-powered lantern is on the trophy
case.")
(LDESC "There is a brass lantern (battery-powered)
here.")
(SIZE 15)>
\end{lstlisting}
As you can see, there are some properties which appeared in the room
example, but some new ones as well.
\section{Object properties}
LOC refers to the location of the object at the start of the game.
In this case, the location of the lamp is in the Living Room room.
Over the course of the game, the location of objects may change as
the player does stuff. For example, if the player picked up the lamp,
the LOC of the lamp would then be the PLAYER (sometimes called PROTAGONIST)
object. If the player then dropped the lamp in the Kitchen, the Kitchen
room would be the lamp's LOC.
The SYNONYM property is a list of all those nouns which can be used
to refer to the lamp. The ADJECTIVE property is a list of those adjectives
which can be used to refer to the lamp. An object, to be referred
to, must have at least one synonym; the ADJECTIVE property is optional.
In the case of the lamp, the player could refer to it using any of
six combinations: lamp, lantern, light, brass lamp, brass lantern,
brass light.
The DESC property, as with rooms, is the name of the object for external
consumption. It will appear whenever a routine needs to \textquotedbl plug
in\textquotedbl{} the name of the object. For example, the EAT verb
default would use it to form the output: \textquotedbl I doubt the
brass lantern would agree with you.\textquotedbl{}
The lamp has two flags: the TAKEBIT means that the lamp can be picked
up by the player; the LIGHTBIT means that the lamp can be lit. The
lamp is not currently on; once it gets turned on, it will have the
ONBIT, meaning that it is giving off light. The flags in the object
definition are only those attributes which the object has at the start
of the game.
The ACTION property identifies LANTERN-F as the action routine which
tries to handle inputs relating to the lantern. For example, if the
player typed THROW THE NERF BALL AT THE BRASS LANTERN, the LAMP object
would be the PRSI, and the routine LANTERN-F would get the first crack
at handling the input. If the player typed THROW THE BRASS LANTERN
AT THE NERF BALL, then the LAMP object would be the PRSO, and LANTERN-F
would get a crack at handling the input provided that the nerf ball's
action routine failed to do so. The FDESC property is a string which
is used to describe the brass lantern until the player picks it up
for the first time; in other words, it describes its original state.
The LDESC property is a string which subsequently describes the lantern
when it's on the ground. These strings are used when a room description
is given, which occurs when you enter a room or when you do a LOOK.
If there are no FDESC or LDESC properties, an object will be described
by plugging its DESC into a default: \textquotedbl There is a brass
lantern here.\textquotedbl{}
The SIZE property defines the size/weight of the object. This helps
the game decide things like whether you can pick something up, or
whether you're holding too much already. If no SIZE is given to a
takeable object, the default is usually 5. A very light object, like
a key or a credit card, might have a SIZE of 1 or 2. A very heavy
object, like a trunk or anvil, might have a SIZE of 25 or 50. Don't
worry too much when you're creating the object; you can always go
back and tweak the sizes during the testing phase.
\chapter{Routines in ZIL}
\section{The Basic Parts}
A routine is the most common item that makes up ZIL code. If you think
of rooms and objects as the skeletal structure of a game, then routines
are the blood and muscle that make the skeleton dance.
Like all things in ZIL, a routine must have balanced sets of parentheses
and angle brackets. The basic parts of a routine look like this. Note
how the angle brackets balance out:
\begin{lstlisting}[basicstyle={\ttfamily},xleftmargin=25pt]
<ROUTINE ROUTINE-NAME (argument-list)
<guts of the routine>>
\end{lstlisting}
There are various conventions for naming routines; object and room
action routines are usually the name of the object or room with \textquotedbl -F\textquotedbl{}
appended. As usual, there's a trade-off between shorter, easier to
type names and longer, easier to remember and understand names.
The argument list appears within parentheses after the routine name.
Arguments are variables used only within the specific routine \textemdash{}
unlike global variables, which are used by any routine in the game.
In many cases, a routine will have no arguments; in that case, the
argument list must still appear, but as an empty set of parentheses:
().
Here's an example of a couple of simple routines, just to show you
what they look like. You don't have to understand them fully, just
yet:
\begin{lstlisting}[basicstyle={\ttfamily},xleftmargin=25pt]
<ROUTINE TURN-OFF-HOUSE-LIGHTS ()
<FCLEAR ,LIVING-ROOM ,ONBIT>
<FCLEAR ,DINING-ROOM ,ONBIT>
<FCLEAR ,KITCHEN ,ONBIT>>
<ROUTINE INCREMENT-SCORE (NUM)
<SETG SCORE <+ ,SCORE .NUM>>
<COND (,SCORE-NOTIFICATION-ON
<TELL "[Your score has just gone up by "
N .NUM ".]" CR>)>>
\end{lstlisting}
The first routine, called TURN-OFF-HOUSE-LIGHTS, makes the three rooms
in the house dark. Note the empty argument list.
The second routine, INCREMENT-SCORE, has one local argument, NUM.
This routine adds the value of NUM to the player's score; if the player
has the notification feature turned on, this routine will inform the
player about the increase.
\section{Calling a Routine}
Every routine in a game is activated by being called by some other
routine. The PRSO and PRSI action routines, and the verb default routine,
are called by a routine called PERFORM, which runs through the potential
handlers and stops when someone has handled the input. In turn, an
action routine can call other routines, as you will see.
A routine calls another routine by putting the name of the called
routine at the appropriate place, inside brackets:
\begin{lstlisting}[basicstyle={\ttfamily},xleftmargin=25pt]
<ROUTINE ROUTINE-A ()
<TELL "Routine-B is about to be called by
Routine-A." CR>
<ROUTINE-B>
<TELL "Routine-B just called by Routine-A." CR>>
\end{lstlisting}
Sometimes, the caller may want to call the callee with an argument,
in order to pass information to the callee. In that case, the argument
list of the called routine must be set up to receive the passed arguments:
\begin{lstlisting}[basicstyle={\ttfamily},xleftmargin=25pt]
<ROUTINE RHYME ("AUX" ARG1 ARG2)
<SET ARG1 30>
<SET ARG2 "September">
<LINE-IN-RHYME .ARG1 .ARG2>
<SET ARG1 28>
<SET ARG2 "February">
<LINE-IN-RHYME .ARG1 .ARG2>
etc.>
<ROUTINE LINE-IN-RHYME (ARG-A ARG-B)
<TELL N .ARG-A " days hath " .ARG-B "." CR>>
\end{lstlisting}
Note that in the example above, routine RHYME has the notation \textquotedbl AUX\textquotedbl{}
in its argument list before the two arguments. This means that the
two arguments are auxiliary arguments, used within the routine RHYME,
but are not passed to RHYME by whatever routine calls RHYME. No such
notation appears in the LINE-IN-RHYME argument list, because ARG1
and ARG2 are being passed to LINE-IN-RHYME. Note that LINE-IN-RHYME
calls the variables ARG-A and ARG-B instead of ARG1 and ARG2; this
is completely arbitrary. The writer of LINE-IN-RHYME could have called
them ARG1 and ARG2 if he/she wished. Remember, even though the routine
LINE-IN-RHYME only exists in one place in your game code, it can be
called any number of times by other routines throughout your game
code. In the case of the routine LINE-IN-RHYME above, it must be passed
two arguments every time it is called.
There is a third type of argument, the optional argument. When an
argument list contains such an argument, denoted by \textquotedbl OPT\textquotedbl{}
in the argument list, it means that the routine accepts that passed
argument, but it doesn't require it.
The three types of arguments must appear in the argument list in the
following order: passed arguments, optional arguments, and auxiliary
arguments (which are also known as local variables). A routine which
uses all three kinds might look something like this:
\begin{lstlisting}[basicstyle={\ttfamily},xleftmargin=25pt]
<ROUTINE CALLEE (X "OPT" Y "AUX" Z)
<some-stuff>>
\end{lstlisting}
It could be called in either of two ways:
\begin{lstlisting}[basicstyle={\ttfamily},xleftmargin=25pt]
<CALLEE .FOO>
\end{lstlisting}
or
\begin{lstlisting}[basicstyle={\ttfamily},xleftmargin=25pt]
<CALLEE .FOO .BAR>
\end{lstlisting}
Here's an example of a routine that takes an optional argument:
\begin{lstlisting}[basicstyle={\ttfamily},xleftmargin=25pt]
<ROUTINE OPEN-DOOR (DOOR "OPT" KEY)
<TELL "You open the " D .DOOR>
<COND (.KEY
<TELL " with the " D .KEY>)>
<TELL "." CR>>
\end{lstlisting}
If this routine is called with <OPEN-DOOR ,OAK-DOOR> it will print
\textquotedbl You open the oak door.\textquotedbl{} If it is called
with <OPEN-DOOR ,OAK-DOOR ,LARGE-RUSTYKEY> it will instead print \textquotedbl You
open the oak door with the large rusty key.\textquotedbl{}
\section{Conditionals}
The guts of a routine are composed of things called CONDs, short for
conditionals. A COND is sort of an if-then statement. In its simplest
form, it looks something like this:
\begin{lstlisting}[basicstyle={\ttfamily},xleftmargin=25pt]
<COND (<if-this-is-true>
<then-do-this>)>
\end{lstlisting}
The \textquotedbl if-this-is-true\textquotedbl{} section of the COND
is called the predicate. A predicate is basically anything in ZIL
whose value can be true or false. A bit later, we will look at the
most common types of predicates.
A COND may have more than one predicate clause; if so, the COND will
continue until one of the predicates proves to be true, and then skip
any remaining predicate clauses:
\begin{lstlisting}[basicstyle={\ttfamily},xleftmargin=25pt]
<COND (<predicate-1>
<do-stuff-1>)
(<predicate-2>
<do-stuff-2>)
(<predicate-3>
<do-stuff-3>)>
\end{lstlisting}
If <predicate-1> is true, then do-stuff-1 will occur, and the second
and third clauses will be skipped. If <predicate-1> is false, the
COND will then look at <predicate-2>, etc.
Often, a routine will have more than one COND:
\begin{lstlisting}[basicstyle={\ttfamily},xleftmargin=25pt]
<COND (<predicate-1>
<do-stuff-1>)>
<COND (<predicate-2>
<do-stuff-2>)>
\end{lstlisting}
In this construction, the second predicate clause will happen even
if the first predicate clause turned out to be true.
\section{Exiting a Routine}
All routines return a value to the routine that called them. That
value is the value of the last thing that the routine did. If that
value is false, the routine is said to have returned false; if it
returns any other value, the routine is said to have returned true:
\begin{lstlisting}[basicstyle={\ttfamily},xleftmargin=25pt]
<ROUTINE FIND-FOOD ("AUX" FOOD)
<COND (<IN? ,HAM-SANDWICH ,HERE>
<SET FOOD ,HAM-SANDWICH>)
(<IN? ,CANDY-BAR ,HERE>
<SET FOOD ,CANDY-BAR>)
(<IN? ,BELGIAN-ENDIVE ,HERE>
<SET FOOD ,BELGIAN-ENDIVE>)
(T
<SET FOOD <>)>
.FOOD>
\end{lstlisting}
Remember, FOOD is an auxiliary local variable; its value is not passed
to FINDFOOD by the calling routine. However, FIND-FOOD does return
the value of FOOD back to the calling routine. If any of the three
predicates are true, FINDFOOD will return the appropriate object,
which means it has returned true. If the call to FIND-FOOD were a
predicate, it would return true, as in:
\begin{lstlisting}[basicstyle={\ttfamily},xleftmargin=25pt]
<COND (<SET FOOD <FIND-FOOD>>
<REMOVE .FOOD>
<TELL "You eat the " D .FOOD
", and your hunger abates." CR>)>
\end{lstlisting}
If none of the three predicates in FIND-FOOD were true, then the value
of .FOOD would be false, and the routine FIND-FOOD would return false.
You can force a routine to return before reaching its end, by inserting
<RTRUE> for \textquotedbl return true\textquotedbl{} or <RFALSE>
for \textquotedbl return false\textquotedbl{} at any point in the
routine. Note, however, that once the routine gets to this point,
it will immediately stop executing, even if you haven't reached the
bottom of the routine:
\begin{lstlisting}[basicstyle={\ttfamily},xleftmargin=25pt]
<ROUTINE STUPID-ROUTINE ()
<TELL "This is a stupidly-designed routine...">
<RTRUE>
<TELL "...because the RTRUE prevents it from
getting to this second string!" CR>>
\end{lstlisting}
You can also force a routine to return a specific value, be it a string,
an object, the value of a global variable, or the value of a local
variable. For example, looking at two variations of FIND-FOOD:
\begin{lstlisting}[basicstyle={\ttfamily},xleftmargin=25pt]
<COND (<IN? ,CANDY-BAR ,HERE>
<RETURN ,CANDY-BAR>)>
<COND (<IN? ,CANDY-BAR ,HERE>
<RETURN "candy bar">)>
\end{lstlisting}
The first case returns the object named CANDY-BAR, the second returns
the text string \textquotedbl candy bar.\textquotedbl{} If you're
confused about the significance of a routine returning a value, re-read
this section after reading Chapter 5.
\section{ZIL Instructions}
There are a number of things in ZIL code which, at first glance, look
like calls to a routine. However, if you look for the associated routine
in your game code, you won't find it anywhere. These are ZIL instructions,
the method by which the game communicates with the interpreter that
runs the game on each individual micro. ZIL instructions are sometimes
referred to as op-codes.
You've already seen a few of the most common instructions, such as
FCLEAR and SET. Some instructions, such as those, take one or more
arguments:
\begin{lstlisting}[basicstyle={\ttfamily},xleftmargin=25pt]
<FCLEAR ,SEARCHLIGHT ,ONBIT>
<SET .LAP-COUNTER 12>
<RANDOM 100>
\end{lstlisting}
Others take no argument:
\begin{lstlisting}[basicstyle={\ttfamily},xleftmargin=25pt]
<SAVE>
<QUIT>
\end{lstlisting}
And, like routines, some instructions accept an optional argument.
A complete list of the current ZIL instructions can be found in Appendix
D.
\chapter{Simple Action Routines}
\section{Simple Object Action Routines}
Let's say you have an object AVOCADO with the property:
\begin{lstlisting}[basicstyle={\ttfamily},xleftmargin=25pt]
(ACTION AVOCADO-F)
\end{lstlisting}
The routine called AVOCADO-F is the action routine for the object.
It might look something like this:
\begin{lstlisting}[basicstyle={\ttfamily},xleftmargin=25pt]
<ROUTINE AVOCADO-F ()
<COND (<VERB? EAT>
<REMOVE ,AVOCADO>
<TELL "The avocado is so delicious that you
eat it all." CR>)
(<VERB? CUT OPEN>
<FSET ,AVOCADO ,OPENBIT>
<MOVE ,AVOCADO-PIT ,AVOCADO>
<TELL "You halve the avocado, revealing a
gnarly pit." CR>)>>
\end{lstlisting}
AVOCADO-F, like most action routines, is not passed any arguments,
and it uses none itself, so it has an empty argument list.
This routine demonstrates one of the simplest and commonest types
of predicates. <VERB? EAT> is true if EAT is the PRSA identified by
the parser. If the input was something like EAT THE AVOCADO or DEVOUR
AVOCADO, the parser would set PRSA to the verb EAT, and <VERB? EAT>
would be true. If so, the next two things would happen. The first
is to REMOVE the avocado; that is, to set its LOC to false, since
once it is eaten, it is now nowhere as far as the game is concerned.
The second thing is the TELL. TELL is a kind of routine called a macro
which is in charge of printing everything the user sees as output
to his input. In its simplest use, as in this example, TELL simply
takes the given string and prints it. The CR after the string means
\textquotedbl carriage return,\textquotedbl{} and causes one to occur
after the string. CR will sometimes appear as the instruction <CRLF>,
meaning \textquotedbl carriage return line feed.\textquotedbl{} CR
and CRLF have the same effect.
If EAT was the verb, this string is printed, the input has been handled,
and the turn is essentially over. However, if EAT wasn't the verb,
then the COND continues to the next predicate. This second predicate
is true if the verb is either CUT or OPEN. In fact, the VERB? predicate
can take any number of verbs to check.
If the second predicate is true, the first thing that happens is the
FSET, which means \textquotedbl flag set.\textquotedbl{} In this
case, it gives the AVOCADO the OPENBIT flag. Note that an object either
has the OPENBIT or it doesn't; there is no such thing as a CLOSEDBIT;
the absence of the OPENBIT is enough to tell that the object is closed.
If you wanted to get rid of the OPENBIT, or any other flag, you would
use the FCLEAR operation. For example, if the player closed the iron
gate, you'd probably have something like:
\begin{lstlisting}[basicstyle={\ttfamily},xleftmargin=25pt]
<FCLEAR ,IRON-GATE ,OPENBIT>
\end{lstlisting}
Getting back to AVOCADO-F, the next thing that happens is to move
the AVOCADO-PIT object to the AVOCADO. This will set the AVOCADO pit's
LOC to AVOCADO. Until this point, the pit probably had no LOC; that
is, its LOC was false, meaning that as far as the game was concerned,
it wasn't anywhere. Finally, the appropriate TELL is done. The input
has now been handled. If neither of these predicates proves to be
true, because the verb is something other than EAT, CUT, or OPEN,
then AVOCADO-F has failed to handle the input. If AVOCADO was the
PRSI, the PRSO routine will then be given the chance. If AVOCADO was
the PRSO, the appropriate verb default will handle the input.
\section{Other Common Predicates}
In addition to the VERB? predicate, let's look at some other common
predicates. The most common one is EQUAL? as in:
\begin{lstlisting}[basicstyle={\ttfamily},xleftmargin=25pt]
<EQUAL? ,HERE ,DRAGONS-LAIR>
\end{lstlisting}
HERE is a global variable which is always kept set to the current
room. So, if the player was in the Dragon's Lair room, this predicate
would be true; otherwise it would be false.
Many global variables (such as the CYCLOPS-FLED example in section
2.1) are just true-false variables. Such a global can be a predicate
all by itself, without angle brackets:
\begin{lstlisting}[basicstyle={\ttfamily},xleftmargin=25pt]
,CYCLOPS-FLED
\end{lstlisting}
If CYCLOPS-FLED were currently true, the predicate would be true.
Note the comma before the global. When writing ZIL code, all global
variables, room names, and object names must be preceded by a comma.
However, local variables, those defined in the argument list and appearing
only in the current routine, must be preceded by a period. Such a
local variable could similarly be used as a predicate:
\begin{lstlisting}[basicstyle={\ttfamily},xleftmargin=25pt]
<ROUTINE OTTO-F ("AUX" OTTO-TO-SANITORIUM)
<stuff-affecting-the-value-of-the-local-variable>
<COND (.OTTO-TO-SANITORIUM
<TELL "The van drives away, turning left
toward Happy Dale." CR>)>>
\end{lstlisting}
Another common predicate is the FSET? predicate:
\begin{lstlisting}[basicstyle={\ttfamily},xleftmargin=25pt]
<FSET? ,AVOCADO ,OPENBIT>
\end{lstlisting}
will be true if the AVOCADO object has the OPENBIT flag set. Note
the vastly important difference between FSET? and FSET \textemdash{}
the first is a predicate, used to check whether a flag is set; the
second is used to actually set the flag.
Another common predicate is IN? which checks the LOC of an object:
\begin{lstlisting}[basicstyle={\ttfamily},xleftmargin=25pt]
<IN? ,EGGS ,BASKET>
\end{lstlisting}
would be true if the LOC of the EGGS object was the BASKET object.
A routine can also be used as a predicate:
\begin{lstlisting}[basicstyle={\ttfamily},xleftmargin=25pt]
<COND (<IS-OTTO-ON-ELBA?>
<TELL "A telegram arrives from Uncle Otto,
complaining about his exile." CR>)>
\end{lstlisting}
If the routine IS-OTTO-ON-ELBA returned true, the predicate would
be true, and vice versa. Here's what the routine might look like:
\begin{lstlisting}[basicstyle={\ttfamily},xleftmargin=25pt]
<ROUTINE IS-OTTO-ON-ELBA? ()
<COND (<EQUAL? <LOC ,UNCLE-OTTO> ,PARIS ,WATERLOO>
<RFALSE>)
(T
<RTRUE>)>>
\end{lstlisting}
Notice that EQUAL? can take any number of arguments, which will be
compared to the first thing after the EQUAL? The predicate will be
true if any of the subsequent arguments have the same value as the
second argument. Thus, the predicate in IS-OTTO-ON-ELBA? would be
true if the LOC of the UNCLE-OTTO object was either PARIS or WATERLOO.
\emph{{[}Put in something here about PDL's new P? predicate.{]}}
\section{More Complicated Predicates}
The predicates you've already learned can be combined with several
fundamental ZIL operations to be more useful. One of these is NOT.
NOT simply changes the sense of the predicate. If
\begin{lstlisting}[basicstyle={\ttfamily},xleftmargin=25pt]
<FSET? ,TROPHY-CASE ,OPENBIT>
\end{lstlisting}
is false, because the trophy case is closed, then
\begin{lstlisting}[basicstyle={\ttfamily},xleftmargin=25pt]
<NOT <FSET? ,TROPHY-CASE ,OPENBIT>>
\end{lstlisting}
will be true. Once again, note the absence of a CLOSEDBIT. You check
to see if the trophy case is closed by checking to make sure it doesn't
have the OPENBIT.
Two or more simple predicates can be combined together using AND.
In such a case, all of them must be true for the entire predicate
to be true:
\begin{lstlisting}[basicstyle={\ttfamily},xleftmargin=25pt]
<AND <EQUAL? ,HERE ,LAUNDRY-ROOM>
<FSET? ,DRYER ,ONBIT>>
\end{lstlisting}
This predicate will only be true if the player is in the laundry room
and the dryer is on. If either part is false, the entire predicate
will be false. Similarly, two or more simple predicates can be combined
using OR. In that case, the entire predicate is true if any of the
parts are true:
\begin{lstlisting}[basicstyle={\ttfamily},xleftmargin=25pt]
<OR <IN? ,SABOTEUR ,ZEPELLIN>
,BOMB-DEFUSED
<EQUAL? ,BLIMP-DESTINATION ,NEW-JERSEY>>
\end{lstlisting}
This predicate will be true if the SABOTEUR object is in the ZEPELLIN
object, or if the global variable BOMB-DEFUSED is set to true, or
if the global variable called BLIMP-DESTINATION is set to NEW-JERSEY.
Of course, if two or more of the parts are true, the entire predicate
remains true. Only if all three parts are false will this predicate
be false.
As you can surmise, all sorts of hair-raisingly complicated predicates
can be strung together using AND, OR and NOT. Here's what a more complicated
version of AVOCADO-F might look like:
\begin{lstlisting}[basicstyle={\ttfamily},xleftmargin=25pt]
<ROUTINE AVOCADO-F ()
<COND (<VERB? EAT>
<COND (,AVOCADO-POISONED
<SETG PLAYER-POISONED T>
<REMOVE ,AVOCADO>
<TELL "You begin to feel sick." CR>)
(<AND <EQUAL? ,HERE ,GARDEN-OF-EDEN>
<IN? ,SNAKE ,TREE-OF-KNOWLEDGE>>
<MOVE ,APPLE ,HERE>
<TELL "The avocado is so
unappetizing. Suddenly, a seductive voice beckons from
the tree. A moment later, a succulent apple lands at
your feet." CR>)
(T
<REMOVE ,AVOCADO>
<MOVE ,AVOCADO-PIT ,PLAYER>
<TELL "You eat the entire avocado.
It was filling, if not tasty." CR>)>)
(<AND <VERB? THROW>
<EQUAL? ,HERE ,MIDWAY>
<NOT ,BALLOON-POPPED>
<HAWKER-AT-CIRCUS>>
<MOVE ,AVOCADO ,MIDWAY-BOOTH>
<TELL "The avocado bounces off the balloon.
The hawker sneers. \"You'd have more luck with a dart,
kiddo! Only two bits!\"" CR>)
(<AND <VERB? COOK>
<OR <NOT <EQUAL? ,HERE ,KITCHEN>>
<NOT <IN? ,COOKPOT ,OVEN>>>>
<TELL "Even a master chef couldn't cook an
avocado with what you've got!" CR>)>>
\end{lstlisting}
Note some things about the above routine that are new to you. The
first is the inner COND, which appears within the <VERB? EAT> clause
of the main COND. Such nesting can continue more and more deeply without
limit (other than the ability for people looking at the code to understand
the resulting routine).
The second thing to note is the last predicate in that inner COND:
it is simply a T. This is simply a predicate that is always true.
The result in this case is that AVOCADO-F should always handle the
input EAT AVOCADO. If the verb is EAT, the inner COND will check the
first and second predicates. If neither is true, then the third clause,
the one with the T predicate, will occur in all cases. Sometimes you'll
see ELSE instead of T; these mean the same thing.
The third thing is the string in the second TELL, where the hawker
speaks. Note the backslash before the hawker's quotes. These are necessary
anytime you have quotes within a string; without the backslash, the
compiler will think the quote means the end of the string rather than
a character within the string, and get very confused. A confused compiler
is not a pretty sight.
\section{A Room's Action Routine}
A room's action routine is (generally) not used for the purpose of
handling the player's input directly, as with an object's action routine.
These routines perform a wide range of tasks. All room action routines
are passed an argument, which tell the routine for what purpose it
is being called. By convention, this argument is called RARG (for
room argument).
The most common use of a room's action routine is for the purpose
of describing the room (due to a LOOK or due to entering the room
for the first time, or due to entering the room in verbose mode).
If a room's description never changes, it can have an LDESC property,
a string which is the room's unchanging description. More often than
not, however, the room's description changes (a door closes, a roof
collapses, a window gets broken, a tree gets chopped down...) and
in these cases the room's action routine must handle the description.
In this case, the action routine is called with an argument called
M-LOOK:
\begin{lstlisting}[basicstyle={\ttfamily},xleftmargin=25pt]
<ROUTINE CAFETERIA-F (RARG)
<COND (<EQUAL? .RARG ,M-LOOK>
<TELL "This is a lunch room, with windows overlooking a
loading dock. ">
<COND (<IN? LUNCH-CROWD ,CAFETERIA>
<TELL "Every table is jammed with patrons. ">)>
<TELL "The only exit is north." CR>)>>
\end{lstlisting}
Notice how the room description changes, depending on whether or not
the LUNCH-CROWD object is in the cafeteria. Also, notice the argument
list with RARG. Finally, notice that the RARG in the predicate has
a period in front of it; this is because it is a local variable in
CAFETERIA-F. (It's okay for any number of routines to have a local
variable with the same name; but every global variable, object, etc.
must have a unique name.)
\pagebreak{}
Another reason for calling a room's action routine is to print a message
or perform some operation upon entering it. For example: