1 ===============================
2 William Tell: the early years
3 ===============================
9 | *M was a miser, and hoarded up gold;*
10 | *N was a nobleman, gallant and bold.*
14 .. image:: /images/picM.png
21 oving along swiftly, we'll define the first two rooms and populate them
22 with assorted townspeople and street furniture, we'll equip Wilhelm with
23 his trusty bow and quiver of arrows, and we'll introduce Helga the friendly
29 This is the street room, the location where the game starts::
31 Room street "A street in Altdorf"
33 print "The narrow street runs north towards the town square.
34 Local folk are pouring into the town through the gate to the
35 south, shouting greetings, offering produce for sale,
36 exchanging news, enquiring with exaggerated disbelief about
37 the prices of the goods displayed by merchants whose stalls
38 make progress even more difficult.^";
39 if (self hasnt visited)
40 print "^~Stay close to me, son,~ you say,
41 ~or you'll get lost among all these people.~^";
45 "The crowd, pressing north towards the square,
46 makes that impossible.";
48 We're using our new ``Room`` class, so there's no need for a ``light``
49 attribute. The ``n_to`` and ``s_to`` properties, whose values are an
50 internal ID and a string respectively, are techniques we've used before.
51 The only innovation is that the ``description`` property has an embedded
54 The first thing in that routine is a ``print`` statement, displaying
55 details of the street surroundings. If that was all that we wanted to do,
56 we could have supplied those details by making the ``description`` value a
57 string; that is, these two examples behave identically::
60 print "The narrow street runs north towards the town square.
61 Local folk are pouring into the town through the gate to the
62 south, shouting greetings, offering produce for sale,
63 exchanging news, enquiring with exaggerated disbelief about
64 the prices of the goods displayed by merchants whose stalls
65 make progress even more difficult.^";
69 "The narrow street runs north towards the town square.
70 Local folk are pouring into the town through the gate to the
71 south, shouting greetings, offering produce for sale,
72 exchanging news, enquiring with exaggerated disbelief about
73 the prices of the goods displayed by merchants whose stalls
74 make progress even more difficult.",
76 However, that *isn't* all that we want to do. Having presented the basic
77 description, we're going to display that little line of dialogue, where
78 Wilhelm tells his son to be careful. And we want to do that only once, the
79 very first time that the street's description is displayed. If the player
80 types LOOK a few times, or moves north and then returns south to the
81 street, we're happy to see the surroundings described -- but we don't want
82 that dialogue again. This is the pair of statements that makes it happen::
84 if (self hasnt visited)
85 print "^~Stay close to me, son,~ you say,
86 ~or you'll get lost among all these people.~^";
88 The line of dialogue is produced by the ``print`` statement, the ``print``
89 statement is controlled by the ``if`` statement, and the ``if`` statement
90 is performing the test ``self hasnt visited``. In detail:
92 * ``visited`` is an attribute, but not one that you'd normally give to an
93 object yourself. It's automatically applied to a room object by the
94 interpreter, but only after that room has been visited for the first
97 * ``hasnt`` (and ``has``) are available for testing whether a given
98 attribute is currently set for a given object. :samp:`{X} has {Y}` is
99 true if object :samp:`{X}` currently has attribute :samp:`{Y}`, false if
100 it doesn't. To make the test in reverse, :samp:`{X} hasnt {Y}` is true
101 if object :samp:`{X}` currently does not have attribute :samp:`{Y}`,
104 * ``self``, which we met in the previous chapter, is that useful variable
105 which, within an object, always refers to that object. Since we're using
106 it in the middle of the ``street`` object, that's what it refers to.
108 So, putting it all together, ``self hasnt visited`` is true (and therefore
109 the ``print`` statement is executed) only while the ``street`` object has
110 *not* got a ``visited`` attribute. Because the interpreter automatically
111 gives rooms a ``visited`` attribute as soon as the player has been there
112 once, this test will be true only for one turn. Therefore, the line of
113 dialogue will be displayed only once: the first time the player visits the
114 street, at the very start of the game.
116 Although the primary importance of ``self`` is within class definitions, it
117 can also be convenient to use it simply within an object. Why didn't we
120 if (street hasnt visited)
121 print "^~Stay close to me, son,~ you say,
122 ~or you'll get lost among all these people.~^";
124 It's true that the effect is identical, but there are a couple of good
125 reasons for using ``self``. One: it's an aid to understanding your code
126 days or weeks after writing it.
128 If you read the line ``if (street hasnt visited)``, you need to think for a
129 moment about which object is being tested; oh, it's this one. When you
130 read ``if (self hasnt visited)``, you immediately *know* which object we're
133 Another reason is auto-plagiarism. Many times you'll find that a chunk of
134 code is useful in different situations (say, you want to repeat the
135 mechanics of the street description in another room). Rather than writing
136 everything from scratch, you'll typically use copy-and-paste to repeat the
137 routine, and then all you have to do is compose the appropriate descriptive
138 strings for the new room. If you've used ``self``, the line ``if (self
139 hasnt visited)`` is still good; if you've written instead ``if (street
140 hasnt visited)``, you'll have to change that as well. Worse, if you
141 *forget* to change it, the game will still work -- but not in the way you'd
142 intended, and the resulting bug will be quite difficult to track down.
149 The street's description mentions various items -- the gate, the people,
150 etc. -- which ought to exist within the game (albeit only in minimal form)
151 to sustain the illusion of hustle and bustle. Our ``Prop`` class is ideal
154 Prop "south gate" street
155 with name 'south' 'southern' 'wooden' 'gate',
156 description "The large wooden gate in the town walls is wide open.";
158 Prop "assorted stalls"
159 with name 'assorted' 'stalls',
160 description "Food, clothing, mountain gear; the usual stuff.",
161 found_in street below_square,
165 with name 'goods' 'produce' 'food' 'clothing' 'mountain' 'gear' 'stuff',
166 description "Nothing special catches your eye.",
167 found_in street below_square,
171 with name 'merchant' 'merchants' 'trader' 'traders',
173 "A few crooks, but mostly decent traders touting their wares
174 with raucous overstatement.",
175 found_in street below_square,
176 has animate pluralname;
179 with name 'people' 'folk' 'local' 'crowd',
180 description "Mountain folk, just like yourself.",
181 found_in [; return true; ],
182 has animate pluralname;
186 Because these objects are not referenced by other objects, we haven't
187 bothered to given them internal :samp:`{obj_ids}` (though we could have;
188 it wouldn't make any difference). However, we *have* provided
189 :samp:`{external_names}`, because these are used by the ``Prop`` class's
190 ``print_ret ... (the) self`` statement.
192 You'll see a couple of new attributes: ``animate`` marks an object as being
193 "alive", while ``pluralname`` specifies that its external name is plural
194 rather than singular. The interpreter uses these attributes to ensure that
195 messages about such objects are grammatical and appropriate (for example,
196 it will now refer to "some merchants" rather than "a merchants"). Because
197 the library handles so many situations automatically, it's hard to be sure
198 exactly what messages players may trigger; the best approach is to play
199 safe and always give an object the relevant set of attributes, even when,
200 as here, they probably won't be needed.
202 You'll also see a new ``found_in`` property, which specifies the rooms --
203 and only the rooms; ``found_in`` shouldn't be used to place objects inside
204 containers or supporters -- where this object is to appear. The stalls,
205 for example, can be EXAMINEd both in the street and below the square, so we
206 *could* have created a ``Prop`` object in each room::
208 Prop "assorted stalls" street
209 with name 'assorted' 'stalls',
210 description "Food, clothing, mountain gear; the usual stuff.",
213 Prop "assorted stalls" below_square
214 with name 'assorted' 'stalls',
215 description "Food, clothing, mountain gear; the usual stuff.",
218 but ``found_in`` does the same job more neatly -- there's only one object,
219 but it appears in both the ``street`` and ``below_square`` rooms while the
220 player's there. The local people are even more ubiquitous. In this case
221 the ``found_in`` value is an embedded routine rather than a list of rooms;
222 such a routine would generally test the value of the current location and
223 ``return true`` if it wants to be present here, or ``false`` if not. Since
224 we'd like the local people *always* to be present, in every room, we
225 ``return true`` without bothering to examine ``location``. It's as though
226 we'd written any of these, but simpler and less error prone::
229 with name 'people' 'folk' 'local' 'crowd',
230 description "Mountain folk, just like yourself.",
231 found_in street below_square south_square mid_square north_square
233 has animate pluralname;
236 with name 'people' 'folk' 'local' 'crowd',
237 description "Mountain folk, just like yourself.",
239 if (location == street || location == below_square ||
240 location == south_square || location == mid_square ||
241 location == north_square || location == marketplace)
245 has animate pluralname;
248 with name 'people' 'folk' 'local' 'crowd',
249 description "Mountain folk, just like yourself.",
251 if (location == street or below_square or south_square or
252 mid_square or north_square or marketplace) return true;
255 has animate pluralname;
257 In the second example, you'll see the ``||`` operator, to be read as "or",
258 which we mentioned near the end of "Heidi"; it combines the various
259 :samp:`location == {some_room}` comparisons so that the ``if`` statement is
260 true if *any* of those individual tests is true. And in the third example
261 we introduce the ``or`` keyword, which is a more succinct way of achieving
262 exactly the same result.
266 The player's possessions
267 ========================
269 Since our ``Initialise`` routine has already mentioned them, we might as
270 well define Wilhelm's bow and arrows::
274 description "Your trusty yew bow, strung with flax.",
277 print_ret "You're never without your trusty bow.";
281 Object quiver "quiver"
284 "Made of goatskin, it usually hangs over your left shoulder.",
287 print_ret "But it was a present from Hedwig, your wife.";
289 has container open clothing;
291 Both of these are straightforward objects, with the ``Drop``, ``Give`` and
292 ``ThrowAt`` actions being intercepted to ensure that Wilhelm is never
293 without them. The ``clothing`` attribute makes its first appearance,
294 marking both the quiver and the bow as capable of being worn (as the result
295 of a WEAR BOW command, for instance); you'll remember that our
296 ``Initialise`` routine goes on to add a ``worn`` attribute to the quiver.
298 An empty quiver is pretty useless, so here's the class used to define
299 Wilhelm's stock of arrows. This class has some unusual features::
302 with name 'arrow' 'arrows//p',
305 description "Just like all your other arrows -- sharp and true.",
308 print_ret "Your arrows are sharp, and you guard them carefully.";
311 The classes we've created so far -- ``Room``, ``Prop`` and ``Furniture`` --
312 are intended for objects which behave the same but are otherwise clearly
313 separate. For example, a table, a bed and a wardrobe would generally have
314 their own individual characteristics -- a name, a description, maybe some
315 specialised properties -- while still inheriting the general behaviour of
316 ``Furniture`` objects. The arrows aren't like this: not only do they
317 behave the same, but also they are indistinguishable one from another.
318 We're trying for this effect:
320 .. code-block:: transcript
324 a quiver (being worn)
328 where the interpreter lumps together our stock of three arrows, rather than
329 listing them individually in this clumsy fashion:
331 .. code-block:: transcript
335 a quiver (being worn)
341 The interpreter will do this for us if our objects are "indistinguishable",
342 best achieved by making them members of a class which includes both
343 ``name`` and ``plural`` properties. We define the actual arrows very
346 Arrow "arrow" quiver;
347 Arrow "arrow" quiver;
348 Arrow "arrow" quiver;
350 and you can see that we provide only two pieces of information for each
351 ``Arrow`` object: an external name in double quotes ("arrow" in each case)
352 which the interpreter uses when referring to the object, and an initial
353 location (in the quiver). That's all: no block of properties, no set of
354 attributes, and no internal identifier, because we never need to refer to
355 the individual ``Arrow`` objects within the game.
357 The name property of the class definition has an odd-looking dictionary
360 name 'arrow' 'arrows//p',
362 The word ``'arrow'`` refers to a single arrow. So also would the word
363 ``'arrows'``, unless we specifically tell the interpreter that it's a
364 plural reference. That ``//p`` marks ``'arrows'`` as being a potential
365 reference to more than one object at once, thus enabling players to type
366 TAKE ARROWS and thereby pick up as many arrows as happened to be available
367 (without it, TAKE ARROWS would have picked up one at random).
369 There are two other properties not seen previously::
374 The ``article`` property lets you define the object's indefinite article --
375 usually something like "a", "an" or "some" -- instead of letting the
376 library assign one automatically. It's a belt-and-braces (OK,
377 belt-and-suspenders) precaution: because "arrow" starts with a vowel, we
378 need to display "an arrow" not "a arrow". Most interpreters automatically
379 get this right, but just to be on the safe side, we explicitly define the
380 appropriate word. And the ``plural`` property defines the word to be used
381 when lumping several of these objects together, as in the "three arrows"
382 inventory listing. The interpreter can't just automatically slap an "s" on
383 the end; the plural of "slice of cake", for example, isn't "slice of
386 Moving further along the street
387 ===============================
389 As Wilhelm moves north towards the square, he comes to this room::
391 Room below_square "Further along the street"
393 "People are still pushing and shoving their way from the southern
394 gate towards the town square, just a little further north.
395 You recognise the owner of a fruit and vegetable stall.",
399 No surprises there, nor in most of the supporting scenery objects. ::
401 Furniture stall "fruit and vegetable stall" below_square
402 with name 'fruit' 'veg' 'vegetable' 'stall' 'table',
404 "It's really only a small table, with a big heap of potatoes,
405 some carrots and turnips, and a few apples.",
406 before [; Search: <<Examine self>>; ],
409 Prop "potatoes" below_square
410 with name 'potato' 'potatoes' 'spuds',
412 "Must be a particularly early variety... by some 300 years!",
415 Prop "fruit and vegetables" below_square
416 with name 'carrot' 'carrots' 'turnip' 'turnips' 'apples' 'vegetables',
417 description "Fine locally grown produce.",
420 The only new thing here is the ``before`` property of the fruit'n'veg
421 stall. The stall's description -- lots of items on a table -- may suggest
422 to players that they can SEARCH through the produce, maybe finding a lucky
423 beetroot or something else interesting. No such luck -- and we might as
424 well trap the attempt.
426 Having intercepted a ``Search`` action, our plan is to respond with the
427 stall's description, as though the player has typed EXAMINE THE STALL.
428 There isn't an easy way for us to stealthily slide those literal words into
429 the interpreter, but we *can* simulate the effect which they'd cause: an
430 action of ``Examine`` applied to the object stall. This rather cryptic
431 statement does the job::
435 Having diverted the ``Search`` action into an ``Examine`` action, we must
436 tell the interpreter that it doesn't need to do anything else, because
437 we've handled the action ourselves. We've done that before -- using
438 ``return true`` -- and so a first stab at the ``before`` action looks like
441 before [; Search: <Examine stall>; return true; ],
443 The two-statement sequence ``<...>; return true`` is so common that there's
444 a single statement shortcut: ``<<...>>``. Also, for exactly the same
445 reason as before, our code is clearer if we use ``self`` instead of
446 ``stall``. So this is how the property finally stands::
448 before [; Search: <<Examine self>>; ],
450 A couple of final observations before we leave this topic. The example
451 here is of an action (``Examine``) applied to an object (``self``, though
452 ``stall`` or ``noun`` would also work at this point). You can also use the
453 ``<...>`` and ``<<...>>`` statements for actions which affect no objects::
457 (representing the command LOOK), or which affect two. For example, the
458 command PUT THE BIRD IN THE NEST can be simulated with this statement::
460 <<Insert bird nest>>;
465 One of the trickiest aspects of designing a good game is to provide
466 satisfying interaction with other characters. It's hard enough to code
467 inanimate objects which provoke appropriate responses to whatever actions
468 the player character (PC) might attempt. That all gets much worse once
469 those "other objects" are living creatures -- non-player characters (NPCs)
470 -- with, supposedly, minds of their own. A good NPC might move around
471 independently, perform actions with a purpose, initiate conversations,
472 respond to what you say and do (and even to what you *don't* say or do); it
473 can be a real nightmare.
475 But not here: we've kept our three NPCs -- Helga, Walter and the vogt -- as
476 simple as possible. Nevertheless, we can establish some fundamental
477 principles; here's the class upon which we base our NPCs::
481 Answer,Ask,Order,Tell:
482 print_ret "Just use T[ALK] [TO ", (the) self, "].";
486 The most important thing here is the ``animate`` attribute -- that's what
487 defines an object as an NPC, and causes the interpreter to treat it a
488 little differently -- for example, TAKE HELGA results in "I don't suppose
489 Helga would care for that".
491 The ``animate`` attribute also brings into play nine extra actions which
492 can be applied only to animate objects: ``Answer``, ``Ask``, ``Order`` and
493 ``Tell`` are all associated with speech, and ``Attack``, ``Kiss``,
494 ``Show``, ``ThrowAt`` and ``WakeOther`` are associated with non-verbal
495 interaction. Additionally, a new ``life`` property -- very similar to
496 ``before`` -- can be defined to intercept them. Here we use it to trap
497 speech-related commands such as ASK HELGA ABOUT APPLE and TELL WALTER ABOUT
498 BABIES, telling players that in this game we've implemented only a simpler
499 TALK verb (which we describe in :ref:`verbs`).
501 Based on the NPC class we've created, here's Helga::
503 NPC stallholder "Helga" below_square
504 with name 'stallholder' 'greengrocer' 'monger' 'shopkeeper' 'merchant'
505 'owner' 'Helga' 'dress' 'scarf' 'headscarf',
507 "Helga is a plump, cheerful woman,
508 concealed beneath a shapeless dress and a spotted headscarf.",
510 print "Helga pauses from sorting potatoes
511 to give you a cheery wave.^";
512 if (location hasnt visited) {
513 move apple to player;
514 print "^~Hello, Wilhelm, it's a fine day for trade! Is this
515 young Walter? My, how he's grown. Here's an apple for him
516 -- tell him to mind that scabby part, but the rest's good
517 enough. How's Frau Tell? Give her my best wishes.~^";
520 times_spoken_to 0, ! for counting the conversation topics
523 self.times_spoken_to = self.times_spoken_to + 1;
524 switch (self.times_spoken_to) {
525 1: score = score + 1;
526 print_ret "You warmly thank Helga for the apple.";
527 2: print_ret "~See you again soon.~";
534 The new attributes are ``female`` -- because we want the interpreter to
535 refer to Helga with the appropriate pronouns -- and ``proper``. The latter
536 signifies that this object's external name is a proper noun, and so
537 references to it should not be preceded by "a" or "the": you wouldn't want
538 to display "You can see a Helga here" or "I don't suppose the Helga would
539 care for that". You may notice the library variable ``score`` being
540 incremented. This variable holds the number of points that the player has
541 scored; when it changes like this, the interpreter tells the player that
542 "Your score has just gone up by one point".
544 There are also ``life`` and ``times_spoken_to`` properties (which we'll
545 talk about in :doc:`09`) and an ``initial`` property.
547 ``initial`` is used when the interpreter is describing a room and listing
548 the objects initial you can see there. If we *didn't* define it, you'd get
551 .. code-block:: transcript
553 Further along the street
554 People are still pushing and shoving their way from the southern gate towards
555 the town square, just a little further north. You recognise the owner of a fruit
558 You can see Helga here.
562 but we want to introduce Helga in a more interactive manner, and that's
563 what the ``initial`` property is for: it replaces the standard "You can see
564 *object* here" with a tailored message of your own design. The value of an
565 ``initial`` property can be either a string which is to be displayed or, as
566 here, an embedded routine. This one is pretty similar to the
567 ``description`` property that we defined for the street: something that's
568 *always* printed (Helga pauses...) and something that's printed only on the
569 first occasion ("Hello, Wilhelm, it's a fine day... "):
571 .. code-block:: transcript
573 Further along the street
574 People are still pushing and shoving their way from the southern gate towards
575 the town square, just a little further north. You recognise the owner of a fruit
578 Helga pauses from sorting potatoes to give you a cheery wave.
580 "Hello, Wilhelm, it's a fine day for trade! Is this young Walter? My, how he's
581 grown. Here's an apple for him -- tell him to mind that scabby part, but the
582 rest's good enough. How's Frau Tell? Give her my best wishes."
586 But it's not quite the same as the street's description routine. First, we
587 need a slightly different ``if`` test: ``self hasnt visited`` works fine
588 for a room object, but this routine is part of an object *in* a room;
589 instead we could use either ``below_square hasnt visited`` or (better)
590 ``location hasnt visited`` -- since ``location`` is the library variable
591 that refers to the room where the player currently is. And second, some
592 curly braces ``{...}`` have appeared: why?
594 On Wilhelm's first visit to this room, we need to do two things:
596 * ensure that Wilhelm is in possession of an apple, because that's
599 * display Helga's cheery greeting.
601 The ``move`` statement does the first of those, and the ``print`` statement
602 does the second. And both statements need to be controlled by the ``if``
603 statement. So far, we've used an ``if`` statement twice, in both cases to
604 control a single following statement. ::
606 if (nest in branch) deadflag = 2;
608 if (self hasnt visited)
609 print "^~Stay close to me, son,~ you say,
610 ~or you'll get lost among all these people.~^";
612 That's what an ``if`` does -- it controls whether the following statement
613 is executed or not. So how can we control two statements at once? Well,
614 we *could* write two ``if`` statements::
616 if (location hasnt visited)
617 move apple to player;
618 if (location hasnt visited)
619 print "^~Hello, Wilhelm, it's a fine day for trade! Is this
620 young Walter? My, how he's grown. Here's an apple for him
621 -- tell him to mind that scabby part, but the rest's good
622 enough. How's Frau Tell? Give her my best wishes.~^";
624 but that's unbearably clumsy; instead, we use the braces to group the
625 ``move`` and ``print`` statement into a :term:`statement block` (sometimes
626 known as a code block) which counts as a single statement for the purposes
627 of control by the ``if`` statement. ::
629 if (location hasnt visited) {
630 move apple to player;
631 print "^~Hello, Wilhelm, it's a fine day for trade! Is this
632 young Walter? My, how he's grown. Here's an apple for him
633 -- tell him to mind that scabby part, but the rest's good
634 enough. How's Frau Tell? Give her my best wishes.~^";
637 A statement block can contain one, two, ten, a hundred statements; it
638 doesn't matter -- they're all treated as one unit by ``if`` (and by
639 ``objectloop``, which we meet later, and by ``do``, ``for`` and ``while``,
640 all of them loop statements that we don't encounter in this guide).
644 The exact positioning of the braces is a matter of personal choice. We
653 but other designers have their own preferences, including::
674 Although we've not yet needed to use it, now would probably be a good time
675 to mention the ``else`` extension to the ``if`` statement. Sometimes we
676 want to execute one statement block if a certain condition is true, and a
677 different statement block if it's not true. Again, we *could* write two
680 if (location has visited) {
685 if (location hasnt visited) {
691 but that's hardly an elegant approach; an ``else`` clause does the job more
694 if (location has visited) {
705 We've done a lot of scene-setting, but the real action is still to come.
706 Next, it's time to define the town square, and create a confrontation
707 between Wilhelm and the vogt's soldiers. (But first, see again
708 :ref:`compile-as-you-go` if you're typing in the game as you read through