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