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