Add chapter 8.
[ibg.git] / chapters / 08.rst
1 ============================
2  William Tell: in his prime
3 ============================
4
5 .. highlight:: inform6
6
7 .. epigraph::
8
9    | *O was an oyster girl, and went about town;*
10    | *P was a parson, and wore a black gown.*
11
12 .. only:: html
13
14    .. image:: /images/picO.png
15       :align: left
16
17 .. raw:: latex
18
19    \dropcap{o}
20
21 ur game's action nears its climax in the town's central square.  In this
22 chapter we define the square's constituent rooms and deal with Wilhelm's
23 approach to the hat on the pole -- does he salute it, or does he remain
24 proudly defiant?
25
26 The south side of the square
27 ============================
28
29 The town square, notionally one enormous open space, is represented by
30 three rooms.  Here's the south side::
31
32    Room     south_square "South side of the square"
33      with   description
34                 "The narrow street to the south has opened onto the town square,
35                  and resumes at the far side of this cobbled meeting place.
36                  To continue along the street towards your destination --
37                  Johansson's tannery -- you must walk north across the square,
38                  in the middle of which you see Gessler's hat set on that
39                  loathsome pole. If you go on, there's no way you can avoid
40                  passing it. Imperial soldiers jostle rudely through the throng,
41                  pushing, kicking and swearing loudly.",
42             n_to mid_square,
43             s_to below_square;
44
45    Prop     "hat on a pole"
46      with   name 'hat' 'pole',
47             before [;
48                default:
49                  print_ret "You're too far away at the moment.";
50             ],
51             found_in south_square north_square;
52
53    Prop     "Gessler's soldiers"
54      with   name 'soldier' 'soldiers' 'guard' 'guards',
55             description "They're uncouth, violent men, not from around here.",
56             before [;
57                FireAt:
58                  print_ret "You're outnumbered many times.";
59                Talk:
60                  print_ret "Such scum are beneath your contempt.";
61             ],
62             found_in south_square mid_square north_square marketplace,
63      has    animate pluralname proper;
64
65 It's all pretty standard stuff: just a ``Room`` and two ``Prop``\s.  The
66 "real" pole object is located in the ``mid_square`` room, which means that
67 players can't EXAMINE it from this room (technically, it's "not in scope").
68 However, since we're pretending that Wilhelm can see the whole of the
69 square from where he's standing, we need to provide a dummy hat on a pole,
70 ``found_in`` both this room and the north side of the square, even if it's
71 "too far away" for a detailed description.
72
73 In fact, it's "too far away" for anything.  We've replaced the standard
74 ``before`` action for the ``Prop`` class (which permits ``Examine``, but
75 rejects other actions with "You don't need to worry about...") with one
76 rejecting *all* actions.  Since Wilhelm's hatred of the vogt's activities
77 is central to our plot, a message saying "You don't need to worry about the
78 hat" would be unacceptably misleading.
79
80 The obnoxious soldiers are also implemented very sketchily; they need to be
81 there, but they don't do much.  Their most interesting characteristic is
82 probably that they trap two actions -- ``FireAt`` and ``Talk`` -- which are
83 *not* part of the library, but instead new actions that we've defined
84 specially for this game.  We'll talk about those actions in "Verbs, verbs,
85 verbs" on page 111, at which time the role of this ``before`` property will
86 make more sense.
87
88 The middle of the square
89 ========================
90
91 The activities here are pivotal to the game's plot.  Wilhelm has arrived
92 from the south side of the square, and now encounters the pole with the hat
93 on top.  He can do three things:
94
95 #. Return south.  That's allowed, but all it does is waste a little time --
96    there's nothing else to usefully do south of here.
97
98 #. Salute the pole, and then proceed to the north.  That's allowed, though
99    it rather subverts the folk story.
100
101 #. Attempt to proceed northwards without saluting the pole.  Twice, a
102    soldier will prevent this, and issue a verbal warning.  On the third
103    attempt, patience runs out, and Wilhelm is hauled off to perform his
104    party piece.
105
106 So, there are two actions that we need to look out for: ``Salute`` (trapped
107 by the pole), and ``Go`` (which can be trapped by the room itself).  ``Go``
108 is a standard library action.  ``Salute`` is one that we've devised; let's
109 deal with it first.  Here's a first cut of the room::
110
111    Room     mid_square "Middle of the square"
112      with   description
113                 "There is less of a crush in the middle of the square; most
114                  people prefer to keep as far away as possible from the pole
115                  which towers here, topped with that absurd ceremonial hat. A
116                  group of soldiers stands nearby, watching everyone who passes.",
117             n_to north_square,
118             s_to south_square;
119
120 and the pole::
121
122    Furniture    pole "hat on a pole" mid_square
123      with name 'wooden' 'pole' 'pine' 'hat' 'black' 'red' 'brim' 'feathers',
124            description
125                 "The pole, the trunk of a small pine some few inches in diameter,
126                  stands about nine or ten feet high. Set carefully on top is
127                  Gessler's ludicrous black and red leather hat, with a widely
128                  curving brim and a cluster of dyed goose feathers.",
129            has_been_saluted false,
130            before [;
131               FireAt:
132                 print_ret "Tempting, but you're not looking for trouble.";
133               Salute:
134                 self.has_been_saluted = true;
135                 print_ret "You salute the hat on the pole. ^^
136                     ~Why, thank you, sir,~ sneers the soldier.";
137            ],
138      has   scenery;
139
140 The room will need some more work in a minute, but the pole object is
141 complete (note that we've simplified matters slightly by making one object
142 represent both the pole and the hat which it supports).  It mentions a
143 property which we've not met before: ``has_been_saluted``.  What a
144 remarkable coincidence: the library provides a property with a name that's
145 exactly right for our game; surely not?
146
147 No, of course not.  ``has_been_saluted`` isn't a standard library property;
148 it's one that we've just invented.  Notice how easily we did it -- we
149 simply included the line::
150
151    has_been_saluted false,
152
153 in the object definition and voilĂ , we've added our own home-made property,
154 and initialised it to ``false``.  To switch the state of the property, we
155 can simply write::
156
157    pole.has_been_saluted = true;
158    pole.has_been_saluted = false;
159
160 or just (within the pole object)::
161
162    self.has_been_saluted = true;
163    self.has_been_saluted = false;
164
165 We could also test, if necessary, how the property currently fares::
166
167    if (pole.has_been_saluted == true) ...
168
169 and that is exactly what we'll be doing in a minute to check whether
170 Wilhelm has saluted the pole, and choose between different outcomes.
171
172 Notice that we use ``==`` (that's two equals signs) to test for "is equal
173 to"; don't confuse this usage with ``=`` (a single equals sign) which
174 assigns a value to a variable.  Compare these examples:
175
176 .. list-table::
177    :header-rows: 1
178    :widths: 1 1
179
180    * - Correct
181      - Incorrect
182
183    * - ``score = 10;``
184      - ``score == 10;``
185
186    * - assigns the value 10 to ``score``
187      - does nothing; ``score`` is unchanged
188
189    * - ``if (score == 10) ...``
190      - ``if (score = 10) ...``
191
192    * - executes the next statement only if the value of ``score`` is 10 
193      - assigns 10 to ``score``, then always executes the next statement --
194        because ``score = 10`` evaluates to 10, which is treated as
195        ``true``, so the test is always ``true``
196
197 Defining a new property variable which, instead of applying to every object
198 in the game (as do the standard library properties), is specific only to a
199 class of objects or even -- as here -- to a single object, is a common and
200 powerful technique.  In this game, we need a ``true/false`` variable to
201 show whether Wilhelm has saluted the pole or not: the clearest way is to
202 create one as part of the pole.  So, when the pole object traps the Salute
203 action, we do two things: use a ``self.has_been_saluted = true`` statement
204 to record the fact, and then use a ``print_ret`` statement to tell players
205 that the salute was "gratefully" received.
206
207 .. note::
208
209    Creating new property variables like this -- at the drop of a hat, as it
210    were -- is the recommended approach, but it isn't the only possibility.
211    We briefly mention some alternative approaches in "Reading other
212    people's code" on page 181.
213
214 Back to the ``mid_square`` room.  We've said that we need to detect Wilhelm
215 trying to leave this room, which we can do by trapping the ``Go`` action in
216 a ``before`` property.  Let's sketch the coding we'll need::
217
218    before [;
219       Go:
220         if (noun == s_obj)       { Wilhelm is trying to move south }
221         if (noun == n_obj)       { Wilhelm is trying to move north }
222    ];
223
224 We can easily trap the ``Go`` action, but which direction is he moving?
225 Well, it turns out that the interpreter turns a command of GO SOUTH (or
226 just SOUTH) into an action of ``Go`` applied to an object ``s_obj``.  This
227 object is defined by the library; so why isn't it called just "``south``"?
228 Well, because we already have another kind of south, the property ``s_to``
229 used to say what lies in a southerly direction when defining a room.  To
230 avoid confusing them, ``s_to`` means "south to" and ``s_obj`` means "south
231 when the player types it as the object of a verb".
232
233 The identity of the object which is the target of the current action is
234 stored in the ``noun`` variable, so we can write the statement ``if (noun
235 == s_obj)`` to test whether the contents of the ``noun`` variable are equal
236 to the ID of the ``s_obj`` object -- and, if so, Wilhelm is trying to move
237 south.  Another similar statement tests whether he's trying to move north,
238 and that's all that we're interested in; we can let other movements take
239 care of themselves.
240
241 The words :samp:`{Wilhelm is trying to move south}` aren't part of our
242 game; they're just a temporary reminder that, if we need to execute any
243 statements in this situation, here's the place to put them.  Actually,
244 that's the simpler case; it's when :samp:`{Wilhelm is trying to move
245 north}` that the fun starts.  We need to behave in one of two ways,
246 depending on whether or not he's saluted the pole.  But we *know* when he's
247 done that; the pole's ``has_been_saluted`` property tells us.  So we can
248 expand our sketch like this::
249
250   before [;
251      Go:
252        if (noun == s_obj)        { Wilhelm is trying to move south [1] }
253        if (noun == n_obj)        { Wilhelm is trying to move north...
254            if (pole.has_been_saluted == true)
255                                  { ...and he's saluted the pole [2] }
256            else                  { ...but he hasn't saluted the pole [3] }
257        }
258   ];
259
260 Here we have one ``if`` statement nested inside another.  And there's more:
261 the inner ``if`` has an ``else`` clause, meaning that we can execute one
262 statement block when the test ``if (pole.has_been_saluted == true)`` is
263 true, and an alternative block when the test isn't true.  Read that again
264 carefully, checking how the braces ``{...}`` pair up; it's quite complex,
265 and you need to understand what's going on.  One important point to
266 remember is that, unless you insert braces to change this, an ``else``
267 clause always pairs with the most recent ``if``.  Compare these two
268 examples::
269
270   if (condition1) {
271       if (condition2) { here when condition1 is true and condition2 is true }
272       else            { here when condition1 is true and condition2 is false }
273   }
274
275   if (condition1) {
276        if (condition2) { here when condition1 is true and condition2 is true }
277   }
278   else                 { here when condition1 is false }
279
280 In the first example, the ``else`` pairs with the most recent :samp:`if
281 ({condition2})`, whereas in the second example the revised positioning of
282 the braces causes the ``else`` to pair with the earlier :samp:`if
283 ({condition1})`.
284
285 .. note::
286
287    We've used indentation as a visual guide to how the ``if`` and ``else``
288    are related.  Be careful, though; the compiler matches an ``else`` to
289    its ``if`` purely on the basis of logical grouping, regardless of how
290    you've laid out the code.
291
292 Back to the before property.  You should be able to see that the cases
293 marked ``[1]``, ``[2]`` and ``[3]`` correspond to the three possible
294 courses of action we listed at the start of this section.  Let's write the
295 code for those, one at a time.
296
297 .. rubric:: Case 1: Returning south
298
299 First, :samp:`{Wilhelm is trying to move south}`; not very much to this::
300
301    warnings_count 0,         ! for counting the soldier's warnings
302    before [;
303       Go:
304         if (noun == s_obj) {
305             self.warnings_count = 0;
306             pole.has_been_saluted = false;
307         }
308         if (noun == n_obj) {
309             if (pole.has_been_saluted == true)
310                       { moving north...and he's saluted the pole }
311             else      { moving north...but he hasn't saluted the pole }
312         }
313    ];
314
315 Wilhelm might wander into the middle of the square, take one look at the
316 pole and promptly return south.  Or, he might make one or two (but not
317 three) attempts to move north first, and then head south.  *Or*, he might
318 be really perverse, salute the pole and only then head south.  In all of
319 these cases, we take him back to square one, as though he'd received no
320 soldier's warnings (irrespective of how many he'd actually had) and as
321 though the pole had not been saluted (irrespective of whether it was or
322 not).  In effect, we're pretending that the soldier has such a short
323 memory, he'll completely forget Wilhelm if our hero should move away from
324 the pole.
325
326 To do all this, we've added a new property and two statements.  The
327 property is ``warnings_count``, and its value will count how many times
328 Wilhelm has tried to go north without saluting the pole: 0 initially, 1
329 after his first warning, 2 after his second warning, 3 when the soldier's
330 patience finally runs out.  The property ``warnings_count`` isn't a
331 standard library property; like the pole's ``has_been_saluted`` property,
332 it's one that we've created to meet a specific need.
333
334 Our first statement is ``self.warnings_count = 0``, which resets the value
335 of the ``warnings_count`` property of the current object -- the
336 ``mid_square`` room -- to 0.  The second statement is
337 ``pole.has_been_saluted = false``, which signifies that the pole has not be
338 saluted.  That's it: the soldier's memory is erased, and Wilhelm's actions
339 are forgotten.
340
341 .. rubric:: Case 2: Moving north after saluting
342
343 :samp:`{Wilhelm is moving north...and he's saluted the pole}`; another easy
344 one::
345
346   warnings_count 0,         ! for counting the soldier's warnings
347   before [;
348      Go:
349        if (noun == s_obj) {
350            self.warnings_count = 0;
351            pole.has_been_saluted = false;
352        }
353        if (noun == n_obj) {
354            if (pole.has_been_saluted == true) {
355                 print "^~Be sure to have a nice day.~^";
356                 return false;
357            }
358            else                   { moving north...but he hasn't saluted the pole }
359        }
360   ];
361
362 All that we need do is print a sarcastic goodbye from the soldier, and then
363 ``return false``.  You'll remember that doing so tells the interpreter to
364 continue handling the action, which in this case is an attempt to move
365 north.  Since this is a permitted connection, Wilhelm thus ends up in the
366 ``north_square`` room, defined shortly.
367
368 .. rubric:: Case 3: Moving north before saluting
369
370 So that just leaves the final case: :samp:`{moving north...but he hasn't
371 saluted the pole}`.  This one has more to it than the others, because we
372 need the "three strikes and you're out" coding.  Let's sketch a little
373 more::
374
375   warnings_count 0,         ! for counting the soldier's warnings
376   before [;
377      Go:
378        if (noun == s_obj) {
379             self.warnings_count = 0;
380             pole.has_been_saluted = false;
381        }
382        if (noun == n_obj) {
383             if (pole.has_been_saluted == true) {
384                 print "^~Be sure to have a nice day.~^";
385                 return false;
386             }
387             else {
388                 self.warnings_count = self.warnings_count + 1;
389                 switch (self.warnings_count) {
390                     1:       First attempt at moving north
391                     2:       Second attempt at moving north
392                     default: Final attempt at moving north
393                 }
394           }
395        }
396   ];
397
398 First of all, we need to count how many times he's tried to move north.
399 ``self.warnings_count`` is the variable containing his current tally, so we
400 add 1 to whatever value it contains: ``self.warnings_count =
401 self.warnings_count + 1``.  Then, determined by the value of the variable,
402 we must decide what action to take: first attempt, second attempt, or final
403 confrontation.  We could have used three separate ``if`` statements::
404
405    if (self.warnings_count == 1)         { First attempt at moving north }
406    if (self.warnings_count == 2)         { Second attempt at moving north }
407    if (self.warnings_count == 3)         { Final attempt at moving north }
408
409 or a couple of nested ``if`` statements::
410
411    if (self.warnings_count == 1)     { First attempt at moving north }
412    else {
413        if (self.warnings_count == 2) { Second attempt at moving north }
414        else                          { Final attempt at moving north }
415    }
416
417 but for a series of tests all involving the same variable, a ``switch``
418 statement is usually a clearer way of achieving the same effect.  The
419 generic syntax for a ``switch`` statement is::
420
421    switch (expression) {
422      value1: whatever happens when the expression evaluates to value1
423      value2: whatever happens when the expression evaluates to value2
424      ...
425      valueN: whatever happens when the expression evaluates to valueN
426      default: whatever happens when the expression evaluates to something else
427    }
428
429 This means that, according to the current value of an expression, we can
430 get different outcomes.  Remember that the :samp:`{expression}` may be a
431 ``Global`` or local variable, an object's property, one of the variables
432 defined in the library, or any other expression capable of having more than
433 one value.  You could write ``switch (x)`` if ``x`` is a defined variable,
434 or even, for instance, ``switch (x+y)`` if both ``x`` and ``y`` are defined
435 variables.  Those :samp:`{whatever happens when...}` are collections of
436 statements which implement the desired effect for a particular value of the
437 switched variable.
438
439 Although a switch statement :samp:`switch ({expression}) { ... }` needs
440 that one pair of braces, it doesn't need braces around each of the
441 individual "cases", no matter how many statements each of them includes.
442 As it happens, case 1 and case 2 contain only a single ``print_ret``
443 statement each, so we'll move swiftly past them to the third, more
444 interesting, case -- when ``self.warnings_count`` is 3.  Again, we could
445 have written this::
446
447    switch     (self.warnings_count) {
448      1:       First attempt at moving north
449      2:       Second attempt at moving north
450      3:       Final attempt at moving north
451    }
452
453 but using the word ``default`` -- meaning "any value not already catered
454 for" -- is better design practice; it's less likely to produce misleading
455 results if for some unforeseen reason the value of ``self.warnings_count``
456 isn't the 1, 2 or 3 you'd anticipated.  Here's the remainder of the code
457 (with some of the printed text omitted)::
458
459   self.warnings_count = self.warnings_count + 1;
460   switch (self.warnings_count) {
461     1: print_ret "...";
462     2: print_ret "...";
463     default:
464        print "^~OK, ";
465        style underline; print "Herr"; style roman;
466        print " Tell, now you're in real trouble. I asked you
467            ...
468            old lime tree growing in the marketplace.^";
469        move apple to son;
470        PlayerTo(marketplace);
471        return true;
472   }
473
474 The first part is really just displaying a lot of text, made slightly
475 messier because we're adding emphasis to the word "Herr" by using
476 underlining (which actually comes out as *italic type* on most
477 interpreters).  Then, we make sure that Walter has the apple (just in case
478 we didn't give it to him earlier in the game), relocate to the final room
479 using ``PlayerTo(marketplace)``, and finally ``return true`` to tell the
480 interpreter that we've handled this part of the ``Go`` action ourselves.
481 And so, at long last, here's the complete code for the ``mid_square``, the
482 most complicated object in the whole game::
483
484   Room    mid_square "Middle of the square"
485     with  description
486                "There is less of a crush in the middle of the square; most
487                  people prefer to keep as far away as possible from the pole
488                  which towers here, topped with that absurd ceremonial hat.  A
489                  group of soldiers stands nearby, watching everyone who passes.",
490           n_to north_square,
491           s_to south_square,
492           warnings_count 0,          ! for counting the soldier's warnings
493           before [;
494              Go:
495                if (noun == s_obj) {
496                     self.warnings_count = 0;
497                     pole.has_been_saluted = false;
498                }
499                if (noun == n_obj) {
500                     if (pole.has_been_saluted == true) {
501                         print "^~Be sure to have a nice day.~^";
502                         return false;
503                     }   ! end of (pole has_been_saluted)
504                     else {
505                         self.warnings_count = self.warnings_count + 1;
506                         switch (self.warnings_count) {
507                           1: print_ret "A soldier bars your way. ^^
508                                  ~Oi, you, lofty; forgot yer manners, didn't you?
509                                  How's about a nice salute for the vogt's hat?~";
510                           2: print_ret "^~I know you, Tell, yer a troublemaker,
511                                  ain't you? Well, we don't want no bovver here,
512                                  so just be a good boy and salute the friggin'
513                                  hat. Do it now: I ain't gonna ask you again...~";
514                           default:
515                              print "^~OK, ";
516                              style underline; print "Herr"; style roman;
517                              print " Tell, now you're in real trouble. I asked you
518                                  nice, but you was too proud and too stupid. I
519                                  think it's time that the vogt had a little word
520                                  with you.~
521                                  ^^
522                                  And with that the soldiers seize you and Walter
523                                  and, while the sergeant hurries off to fetch
524                                  Gessler, the rest drag you roughly towards the
525                                  old lime tree growing in the marketplace.^";
526                              move apple to son;
527                              PlayerTo(marketplace);
528                              return true;
529                         }    ! end of switch
530                     }   ! end of (pole has_NOT_been_saluted)
531                }    ! end of (noun == n_obj)
532           ];
533
534 The north side of the square
535 ============================
536
537 The only way to get here is by saluting the pole and then moving north; not
538 very likely, but good game design is about predicting the unpredictable. ::
539
540   Room     north_square "North side of the square"
541     with   description
542                "A narrow street leads north from the cobbled square. In its
543                 centre, a little way south, you catch a last glimpse of the pole
544                 and hat.",
545            n_to [;
546                deadflag = 3;
547                print_ret "With Walter at your side, you leave the square by the
548                    north street, heading for Johansson's tannery.";
549            ],
550            s_to "You hardly feel like going through all that again.";
551
552 There's one new feature in this room: the value of the ``n_to`` property is
553 a routine, which the interpreter runs when Wilhelm tries to exit the square
554 northwards.  All that the routine does is set the value of the library
555 variable ``deadflag`` to 3, print a confirmation message, and ``return
556 true``, thus ending the action.
557
558 At this point, the interpreter notices that ``deadflag`` is no longer zero,
559 and terminates the game.  In fact, the interpreter checks ``deadflag`` at
560 the end of every turn; these are the values that it's expecting to find:
561
562 * 0 -- this is the normal state; the game continues.
563 * 1 -- the game is over. The interpreter displays "You have died".
564 * 2 -- the game is over. The interpreter displays "You have won".
565 * any other value -- the game is over, but there aren't any appropriate
566   messages built into the library.  Instead, the interpreter looks for an
567   **entry point** routine called ``DeathMessage`` -- which we must provide
568   -- where we can define our own tailored "end messages".
569
570 In this game, we never set ``deadflag`` to 1, but we do use values of 2
571 and 3.  So we'd better define a ``DeathMessage`` routine to tell players
572 what they've done::
573
574     [ DeathMessage; print "You have screwed up a favourite folk story"; ];
575
576 Our game has only one customised ending, so the simple ``DeathMessage``
577 routine we've written is sufficient for our purposes.  Were you to conceive
578 multiple endings for a game, you could specify suitable messages by
579 checking for the current value of the ``deadflag`` variable::
580
581     [ DeathMessage;
582         if (deadflag == 3) print "You leave Scarlett O'Hara for good";
583         if (deadflag == 4) print "You crush Scarlett with a passionate embrace";
584         if (deadflag == 5) print "You've managed to divorce Scarlett";
585         ...
586     ];
587
588 Of course, you must assign the appropriate value to ``deadflag`` at the
589 point when the game arrives at each of those possible endings.
590
591 We've nearly finished.  In the concluding chapter of this game, we'll talk
592 about the fateful shooting of the arrow.