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