7 | *U was a usurer, a miserable elf;*
8 | *V was a vintner, who drank all himself.*
12 .. image:: /images/picV.png
19 iewed from the inside, Benny's café is warm and welcoming, and packed
20 with lunchtime customers. We'll try to conjure up some appropriate
21 images, but the main focus of the room isn't the decor: it's the door
22 leading to the toilet -- and, perhaps, privacy?
27 Benny's café is populated with customers enjoying their lunch, so it
28 won't be a good place to change identities. However, the toilet to the
29 north looks promising, though Benny has strict rules about its use and
30 the door seems to be locked.
32 .. admonition:: Cultural Note
33 :class: admonition note
35 not for the first time, this guide betrays its origins. In
36 European countries the word "toilet" often refers not only to the
37 white porcelain artefact, but also to the room in which it can be
38 found (also, a "bathroom" is for taking a bath, a "restroom" for
39 taking a rest). Bear with us on this; the dual usage becomes
40 important a little later on.
42 We define the café room in simple form:
44 .. code-block:: inform
46 Room cafe "Inside Benny's cafe"
48 "Benny's offers the FINEST selection of pastries and
49 sandwiches. Customers clog the counter, where Benny himself
50 manages to serve, cook and charge without missing a step. At
51 the north side of the cafe you can see a red door connecting
56 We'll elaborate on the last line (``n_to toilet_door``) later, when we
57 define the door object which lies between the café and the toilet.
59 We've mentioned a counter:
61 .. code-block:: inform
63 Appliance counter "counter" cafe
64 with name 'counter' 'bar',
67 "The counter is made of an astonishing ALLOY of metals,
68 STAIN-PROOF, SPILL-RESISTANT and VERY EASY to clean. Customers
69 enjoy their snacks with UTTER tranquillity, safe in the notion
70 that the counter can take it all.",
77 That ``before property``, superficially normal, actually conceals a
78 little surprise. By now you should be entirely comfortable with using an
79 object's ``before`` property to intercept an action directed at that
80 object; for example, if the player types HIT COUNTER then the counter's
81 ``before`` property is potentially able to intercept the resulting
82 Attack action. However, the command PUT KEY ON COUNTER generates *two*
83 actions. First, a PutOn action is offered to the key (effectively
84 saying, do you want to be placed on top of the counter?); that’s the
85 normal bit. And then the surprise: a Receive action is offered to the
86 counter (effectively saying, are you happy to have the key placed on
87 you?) Both actions have the same opportunity of returning ``false`` to
88 let the action continue, ``true`` to prevent it.
92 There are a lot of actions here that are rendered in a typewriter font
93 and others that are not. Should these ones that are not be promoted
94 to having a typewriter font?
96 The Receive action is generated by the library in the PutOnSub action
97 handler, and also in InsertSub (so a command like PUT BIRD IN NEST sends a
98 Receive to the nest object). There’s a matching LetGo, generated by the
99 library from commands like TAKE KEY OFF COUNTER and REMOVE BIRD FROM
100 NEST. Receive and LetGo are examples of what’s called a :term:`fake
105 in "William Tell" we defined the ``quiver``, way back in "The
106 player's possessions" on page 83, as an ``open container``. As things
107 stand, the player can put *any* held object, however inappropriate,
108 into it. We could have trapped the Receive action to ensure that
109 arrows are the only acceptable contents (recollect that ``~~``, to be
110 read as "not", turns true into false and vice versa):
112 .. code-block:: inform
116 print_ret "But it was a present from Hedwig, your wife.";
118 if (~~(noun ofclass Arrow))
119 print_ret "Only arrows -- clean arrows -- go in your quiver.";
122 Here, we intercept any attempt to place an item on the counter, and
123 translate it into an attempt to give that item to Benny. Part of the
124 game's plot depends on the player returning the toilet key to Benny, and
125 also paying him for his delicious cup of world-famous Cappuccino.
126 Putting the key and the money on the counter is a reasonable alternative
127 way for the player to accomplish this.
129 We've also mentioned some customers. These are treated as NPCs, reacting
130 to our hero’s performance.
132 .. code-block:: inform
134 Object customers "customers" cafe
135 with name 'customers' 'people' 'customer' 'men' 'women',
137 if (costume has worn)
138 "Most seem to be concentrating on their food, but some do
139 look at you quite blatantly. Must be the MIND-BEFUDDLING
140 colours of your costume.";
142 "A group of HELPLESS and UNSUSPECTING mortals, the kind
143 Captain FATE swore to DEFEND the day his parents choked on a
144 DEVIOUS slice of RASPBERRY PIE.";
148 if (costume has worn)
149 "People seem to MISTRUST the look of your FABULOUS costume.";
151 "As John Covarth, you attract LESS interest than Benny's
154 "There's no telling what sorts of MUTANT bacteria these
155 STRANGERS may be carrying around.";
157 "Mindless massacre of civilians is the qualification for
158 VILLAINS. You are SUPPOSED to protect the likes of these
162 "These people don't appear to be of the cooperative sort.";
164 number_of_comments 0, ! for counting the customer comments
166 if (location ~= cafe) return;
167 if (self.number_of_comments == 0) {
168 self.number_of_comments = 1;
169 print "^Nearby customers glance at your costume with open
172 if (random(2) == 1) { ! do this 50% of the time
173 self.number_of_comments = self.number_of_comments + 1;
174 switch (self.number_of_comments) {
175 2: "^~Didn't know there was a circus in town,~ comments one
176 customer to another. ~Seems like the clowns have the
178 3: "^~These fashion designers don't know what to do to show
179 off,~ snorts a fat gentleman, looking your way. Those
180 within earshot try to conceal their smiles.";
181 4: "^~Must be carnival again,~ says a man to his wife, who
182 giggles, stealing a peek at you. ~Time sure flies.~";
183 5: "^~Bad thing about big towns~, comments someone to his
184 table companion, ~is you get the damnedest bugs coming
186 6: "^~I sure WISH I could go to work in my pyjamas,~ says a
187 girl in an office suit to some colleagues. ~It looks SO
189 default: StopDaemon(self);
193 has scenery animate pluralname;
195 Let's go step by step. Our hero enters the café dressed as John Covarth,
196 but will eventually manage to change clothes in the toilet, and he'll
197 have to cross back through the café to reach the street and win the
198 game. The customers' ``description`` takes into consideration which
199 outfit the player character is wearing.
201 In "William Tell" we’ve seen a brief manifestation of the ``life``
202 property, but here we'll extend it a little. As we explained, ``life``
203 lets you intercept those actions particular to animate objects. Here we
204 trap ``Attack`` and ``Kiss`` to offer some customised messages for these
205 actions when applied to the customers. Also, we avoid conversation by
206 intercepting ``Ask``, ``Tell`` and ``Answer`` in order just to produce a
207 message which depends on the player character's attire.
209 One other feature of ``animate`` objects is the possibility of giving
210 them orders: BILL, SHAKE THE SPEAR or ANNIE, GET YOUR GUN . These
211 actions are dealt with in the ``orders`` property and, as with the
212 ``life`` property, the embedded routine can become quite complex if you
213 want your NPCs to behave in an interesting way. In this case, we don't
214 need the customers to perform tasks for us, so instead we provide a
215 simple rejection message, just in case the player tries to order people
218 Which leaves us with the ``daemon`` bit. A daemon is a property normally
219 used to perform some timed or repetitive action without the need of the
220 player’s direct interaction; for example, machines which work by
221 themselves, animals that move on their own, or people going about their
222 business. More powerfully, a daemon may take notice of the player’s
223 decisions at a particular moment, allowing for some interactive
224 behaviour; this is, however, an advanced feature that we won't use in
225 this example. A daemon gets a chance of doing something at the end of
226 every turn, typically to (or with) the object to which it’s associated.
227 In our example, the daemon triggers some sneers and nasty comments from
228 the customers once our hero comes out of the toilet dressed in Captain
231 To code a daemon, you need to do three things:
233 #. First, define a daemon property in the object’s body; the value of
234 the property is always an embedded routine.
236 #. However, daemons do nothing until you activate them. This is easily
237 achieved with the call ``StartDaemon(obj_id)``, which may happen
238 anywhere (if you want some object's daemon to be active from the
239 beginning of the game,you can make the call in your Initialise
242 #. Once the daemon has finished its mission (if ever) you may stop it
243 with the call ``StopDaemon(obj_id)``.
245 How does our particular daemon work? The appearance of our hero in full
246 crime-fighting wear will make the customers stare at him and make snarky
247 remarks. This must happen in the café room – the place where the
248 customers are -- so we need to make certain that the daemon does
249 something interesting only while the player stays in the right place
250 (and hasn’t wandered, say, back into the toilet):
252 .. code-block:: inform
254 if (location ~= cafe) return;
256 So if the location is not the café room (remember ~= means "not equal
257 to"), return without doing anything else; on this turn, there’s nothing
258 for the daemon to do. We use a plain ``return`` statement because the
259 value returned from a daemon doesn’t matter.
261 We have defined a customised local property, ``number_of_comments``, to
262 control the sequence of customers' remarks. When the Captain enters the
263 café room from the toilet for the first time, the value of the property
264 should be zero, so the statement block under the test:
266 .. code-block:: inform
268 if (self.number_of_comments == 0) {
269 self.number_of_comments = 1;
270 print "^Nearby customers glance at your costume with open
274 will happen only this once. What we intend is to output the text "Nearby
275 customers..." right after the startling entrance of our hero, setting up
276 the scene for the comments which are about to happen. Since we assign a
277 value of 1 to the property, the message will not be printed again.
278 Notice how we use an explicit ``print`` statement; the execution of the
279 daemon will continue normally to the next line.
281 We want the customers to indulge in witticisms once they see the
282 costumed Captain, but not on a completely predictable basis.
284 .. code-block:: inform
286 if (random(2) == 1) ...
288 ``random`` is an Inform routine used to generate random numbers or to
289 choose randomly between given choices; in the form
290 :samp:`random({expression})` it returns a random number between 1 and
291 ``expression`` inclusive. So our condition is actually stating: if a
292 random choice between 1 and 2 happens to be 1 then perform some action.
293 Remember that a daemon is run once at the end of every turn, so the
294 condition is trying to squeeze a comment from a customer roughly once
297 Next, we proceed as we have already seen in "William Tell", with a
298 switch statement to order the comments in a controlled sequence by
299 cunning use of our tailored local property, ``number_of_comments``. We
300 have written just five messages (could have been one or a hundred) and
301 then we reach the default case, which is a good place to stop the
302 daemon, since we have no more customers’ remarks to display.
304 Ah, but when does the daemon *start* functioning? Well, as soon as our
305 protagonist comes out of the toilet dressed in his multicoloured
306 super-hero pyjamas. Since we want to minimise the possible game states,
307 we’ll make some general rules to avoid trouble: (a) players will be able
308 to change only in the toilet; (b) we won’t let players change back into
309 street clothes; and (c) once players manage to step into the street thus
310 dressed, the game is won. So, we can safely assume that if players enter
311 the café in their Captain’s outfit, they’ll be coming from the toilet.
312 As a consequence of all this, we add an ``after`` property to the café
315 .. code-block:: inform
317 Room cafe "Inside Benny's cafe"
319 first_time_out false, ! Captain Fate's first appearance?
321 Go: ! The player has just arrived. Did he come from the toilet?
322 if (noun ~= s_obj) return false;
323 if (costume has worn && self.first_time_out == false) {
324 self.first_time_out = true;
325 StartDaemon(customers);
331 There are two useful techniques to detect when the player is entering or
332 leaving a room. We'll later see in detail how to deal with a player
333 trying to go away and how to avoid it if need be. For now, let’s just
334 mention that, in both cases, you have to intercept the ``Go`` action in
335 a room object; if you trap it in a ``before`` property, you’re checking
336 for departure from the room; if you trap it in an ``after`` property,
337 you’re checking for arrivals into the room. Right now we wish to know if
338 the player just came from the toilet, so we use an ``after`` property.
342 .. code-block:: inform
344 if (noun ~= s_obj) return false;
346 is telling the interpreter that we want to do something if the player
347 entered the room by typing a GO SOUTH command (this would normally mean
348 "coming from the north", but remember that nothing stops you from
349 connecting rooms without cardinal logic); the interpreter will apply
350 normal rules for the other available directions.
352 Then we check whether the player character is wearing the costume, in
353 which case it starts the ``daemon`` of the ``customers`` object. The use
354 of the local first_time_out property ensures that the condition is
355 ``true`` only once, so the statement block attached to it runs also
358 We've finished with the customers in the café. Now, we have the toilet
359 to the north which, for reasons of gameplay *and* decency, is protected
365 Door objects require some specific properties and attributes. Let's
366 first code a simple door:
368 .. code-block:: inform
370 Object toilet_door "toilet door" cafe
371 name name 'red' 'toilet' 'door',
373 "A red door with the unequivocal black man-woman
374 silhouettes marking the entrance to hygienic facilities.
375 There is a scribbled note stuck on its surface.",
379 has scenery door openable lockable locked;
381 We find this door in the café. We must specify the direction in which
382 the door leads and, as we have mentioned in the café's description, that
383 would be to the north. That’s what the ``door_dir`` property is for, and
384 in this case it takes the value of the north direction property
385 ``n_to``. Then we must tell Inform the identity of the room to be found
386 behind the door, hence the ``door_to`` property, which takes the value
387 of the toilet room -- to be defined later. Remember the café's
388 connection to the north, ``n_to toilet_door``? Thanks to it, Inform will
389 know that the door is in the way, and thanks to the ``door_to``
390 property, what lies beyond.
392 Doors *must* have the attribute ``door``, but beyond that we have a
393 stock of options to help us define exactly what kind of door we are
394 dealing with. As for containers, doors can be ``openable`` (which
395 activates the verbs OPEN and CLOSE so that they can be applied to this
396 object) and, since by default they are closed, you can give them the
397 attribute ``open`` if you wish otherwise. Additionally, doors can be
398 ``lockable`` (which sets up the LOCK/UNLOCK verbs) and you can make them
399 ``locked`` to override their default unlocked status. The verbs LOCK
400 and UNLOCK are expecting some kind of key object to operate the door.
401 This must be defined using the ``with_key`` property, whose value should
402 be the internal ID of the key; in our example, the soon-to-be-defined
403 ``toilet_key`` . If you don't supply this property, players won't be
404 able to lock or unlock the door.
406 This simple door definition has one problem, namely, that it exists only
407 in the café room. If you wish the door to be present also from the
408 toilet side, you can either (a) define another door to be found in the
409 ``toilet room``, or (b) make this one a two-sided door.
411 Solution (a) seems superficially straightforward, but then you have the
412 problem of keeping the states of the two doors – open/closed,
413 locked/unlocked -- in synch. In this scenario, where you can access the
414 toilet only through this door, that wouldn't be too complicated, since
415 you could leave the door object in the café room opened all the time,
416 regardless of what players do with the door object in the toilet room
417 and vice versa -- they are never going to see them at the same time. In
418 general terms, though, such inconsistencies lead to problems; solution
419 (a) is best ignored for most purposes.
421 Solution (b) is better, since you have only one door object to deal with
422 and its possible states affect both sides. However, the coding gets a
423 little bit complicated and you''ll have to define routines for most
426 .. code-block:: inform
428 Object toilet_door "toilet door"
429 with name 'red' 'toilet' 'door',
431 if (location == cafe)
432 "A red door with the unequivocal black man-woman silhouettes
433 marking the entrance to hygienic facilities. There is a
434 scribbled note stuck on its surface.";
436 "A red door with no OUTSTANDING features.";
438 found_in cafe toilet,
440 if (location == cafe) return n_to;
444 if (location == cafe) return toilet;
448 has scenery door openable lockable locked;
450 First of all, the door now needs a ``found_in`` property, since it's
451 going to be located both in the café and the toilet. The ``description``
452 checks which side of the door we are looking at – testing the current
453 value of the variable ``location``, which holds the room the player is
454 in -- because we have a scribbled note stuck on one side, but not on the
455 other. And the ``door_dir`` and ``door_to`` properties must use the same
456 trick, because we travel north from the café into the toilet, but south
457 from the toilet into the café.
459 Right now, the game will display "the toilet door" every time it needs
460 to refer to this object. It would be nice if we could somehow get the
461 game to distinguish between "the door to the toilet" and "the door to
462 the cafe", depending on the side we are facing. For this, a ``short_name
463 property`` is the thing. We have already talked about the external name
464 defined as part of an object's header information:
466 .. code-block:: inform
468 Object toilet_door "toilet door"
470 That ``toilet door`` will be the name displayed by the game at run-time
471 to refer to the door. With identical effect, this could also have been
474 .. code-block:: inform
477 with short_name "toilet door",
479 ``short_name`` is a property that supplies the external name of an
480 object, either as a string or an embedded routine. Normally, objects
481 retain the same external name throughout the game -- and the header
482 information method is perfect in that case -- but if it needs to change,
483 it's easy to write a routine as the value of ``short_name``:
485 .. code-block:: inform
488 with name 'red' 'toilet' 'door'
490 if (location == cafe) print "door to the toilet";
491 else print "door to the cafe";
496 Notice the ``return true`` at the end of the routine. You''ll recall
497 that the standard rule says "return false to carry on, true to take over
498 and stop normal execution”. In the case of ``short_name``, "carry on"
499 means "and now display the external name from the header information",
500 which is sometimes handy; for instance, you could write a ``short_name``
501 routine to prefix an object's external name with one of a range of
502 adjectives -- perhaps a shining/flickering/fading/useless lantern.
506 what's displayed if there isn't an external name in an object's
507 header? If you've read the section "Compile-as-you-go" on page 233,
508 you'll recall that the interpreter simply uses the internal
509 identifier within parentheses; that is, with no external name and no
510 ``short_name`` property, we might see:
512 .. code-block:: inform
514 You open the (toilet_door).
516 And the same principle applies if we were mistakenly to ``return
517 false`` from this short_name routine: we would get, first, the result
518 of our ``print`` statement, and then the standard rules would display
521 .. code-block:: inform
523 You open the door to the toilet(toilet_door).
525 Doors can get more complicated than this (no, please, don't throw our
526 guide out of the window). Here comes some optional deluxe coding to make
527 the door object a bit friendlier in game play, so you can skip it if you
530 Our door now behaves nicely at run-time. It can be locked and unlocked
531 if the player character has the right key; it can be opened and closed.
532 A sequence of commands to go into the toilet and lock the door behind
533 you would be: UNLOCK DOOR WITH KEY, OPEN DOOR, GO NORTH, CLOSE DOOR,
534 LOCK DOOR WITH KEY. After we are finished, let's go back to the café:
535 UNLOCK DOOR WITH KEY, OPEN DOOR, SOUTH. If the player is of the
536 fastidious kind: CLOSE DOOR, LOCK DOOR WITH KEY. This game features only
537 one door, but if it had three or four of them, players would grow
538 restless (at the very least) if they needed to type so many commands
539 just to go through a door. This is the kind of thing reportedly
540 considered as poor design, because the game is suddenly slowed down to
541 get over a simple action which involves no secrets or surprises. How
542 exciting can the crossing of an ordinary door be, after all?
544 If a few lines of code can make the life of the player easier, it's
545 worth a shot. Let's provide a few improvements to our toilet door in
546 ``before`` and ``after`` properties:
548 .. code-block:: inform
552 if (self hasnt locked || toilet_key notin player)
554 ks = keep_silent; keep_silent = true;
555 <Unlock self toilet_key>; keep_silent = ks;
558 if (self hasnt open) return false;
559 print "(first closing ", (the) self, ")^";
560 ks = keep_silent; keep_silent = true;
561 <Close self>; keep_silent = ks;
566 if (self has locked) return false;
567 print "You unlock ", (the) self, " and open it.^";
568 ks = keep_silent; keep_silent = true;
569 <Open self>; keep_silent = ks;
573 The basic idea here is to let the player who holds the key perform just
574 one action to both unlock *and* open the door (and, conversely, to close
575 *and* lock it). The relevant actions are ``Unlock`` and ``Open``, and
576 ``Lock`` ( ``Close`` is not necessary; if players just close the door we
577 shouldn’t assume that they want to lock it as well).
579 * **Open**: if the door isn't locked or the player doesn't hold the key,
580 keep going with the default ``Open`` action defined by the library.
581 That leaves a locked door and a player holding the key, so we
582 redirect processing to the ``Unlock`` action, giving as arguments the
583 door (self) and the toilet key. Since we are using single
584 angle-brackets ``<...>``, the action resumes after the unlocking is
585 done (note that the ``Unlock`` action also takes care of opening the
586 door). Finally, we ``return true`` to stop the library from trying to
587 open the door by itself.
589 * **Lock**: if the door is already closed, keep going with the standard
590 library ``Lock`` action. If not, tell players that we are closing the
591 door for them, redirect the action briefly to actually close it, and
592 then ``return false`` to let the ``Lock`` action proceed as before.
594 * **Unlock**: we place this action in the after property, so (let's
595 hope) the ``Unlock`` action has already happened. If the door is still
596 locked, something went wrong, so we ``return false`` to display the
597 standard message for an unsuccessful unlocking. Otherwise, the door is
598 now unlocked, so we inform the player that we are opening the door and
599 redirect the action to actually open it, returning ``true`` to
600 suppress the standard message.
602 In all processes there is a library variable called ``keep_silent``,
603 which can be either ``false`` (the normal state) or ``true``; when
604 ``true``, the interpreter does not display the associated message of an
605 action in progress, so we can avoid things like::
608 You open the door to the toilet.
609 You unlock the door to the toilet and open it.
611 Although we want to set ``keep_silent`` to ``true`` for the duration of
612 our extra processing, we need to reset it afterwards. In a case like
613 this, good design practice is to preserve its initial value (which was
614 probably ``false``, but you should avoid risky assumptions); we use a
615 local variable ``ks`` to remember that initial setting so that we can
616 safely restore it afterwards. You’ll remember that a local variable in a
617 standalone routine is declared between the routine’s name and the
620 .. code-block:: inform
622 [ BeenToBefore this_room;
624 In exactly the same way, a local variable in an embedded routine is
625 declared between the ``[`` starting marker of the routine and the
628 .. code-block:: inform
632 You can declare up to fifteen variables this way -- just separated by
633 spaces -- which are usable only within the embedded routine. When we
636 .. code-block:: inform
640 we are actually making ``ks`` equal to whatever value ``keep_silent``
641 has (either ``true`` or ``false``; we actually don't care). We then set
642 ``keep_silent`` to ``true``, make the desired silent actions, and we
645 .. code-block:: inform
649 which restores the value originally stored in ``ks`` to ``keep_silent``.
650 The effect is that we manage to leave it as it was before we tampered
653 Well, that's about everything about doors. Everything? Well, no, not
654 really; any object can grow as complex as your imagination allows, but
655 we’ll drop the subject here. If you care to see more sophisticated
656 doors, check Exercises 3 and 4 in the *Inform Designer's Manual*, where
657 an obliging door opens and unlocks by itself if the player simply walks
660 So far, we have the player in front of a locked door leading to the
661 toilet. A dead end? No, the description mentions a scribbled note on its
662 surface. This one should offer no problem:
664 .. code-block:: inform
666 Object "scribbled note" cafe
667 with name 'scribbled' 'note',
669 if (self.read_once == false) {
670 self.read_once = true;
671 "You apply your ENHANCED ULTRAFREQUENCY vision to the note
672 and squint in concentration, giving up only when you see the
673 borders of the note begin to blacken under the incredible
674 intensity of your burning stare. You reflect once more how
675 helpful it would've been if you'd ever learnt to read.
676 ^^A kind old lady passes by and explains:
677 ~You have to ask Benny for the key, at the counter.~^^
678 You turn quickly and begin, ~Oh, I KNOW that, but...~^^
679 ~My pleasure, son,~ says the lady, as she exits the cafe.";
682 "The scorched undecipherable note holds no SECRETS from
685 read_once false, ! has the player read the note once?
688 "No reason to start collecting UNDECIPHERABLE notes.";
692 Just notice how we change the description after the first time the
693 player examines the note, using the local property ``read_once`` created
694 just for this purpose. We don’t want the player to walk off with the
695 note, so we intercept the ``Take`` action and display something more in
696 character than the default message for scenery objects: "That's hardly
699 We've talked a lot about the toilet key; it seems about time to code it.
700 Originally, the key is in Benny's possession, and the player will have
701 to ask for it, just as the note explains. Although we'll define Benny in
702 detail throughout the next chapter, here we present a basic definition,
703 largely so that the key has a parent object.
705 .. code-block:: inform
707 Object benny "Benny" cafe
710 "A deceptively FAT man of uncanny agility, Benny entertains his
711 customers crushing coconuts against his forehead when the mood
713 has scenery animate male proper transparent;
715 Object toilet_key "toilet key" benny
716 with name 'toilet' 'key',
719 if (clothes has worn) print "the CRUCIAL key";
720 else print "the used and IRRELEVANT key";
724 "Your SUPRA PERCEPTIVE senses detect nothing of consequence
725 about the toilet key.",
728 "You SCAN your surroundings with ENHANCED AWARENESS,
729 but fail to detect any key.";
731 "Benny is trusting you to look after that key.";
734 While Benny has the key, there's logically no way to examine it (or
735 perform any other action involving it), but we want to prevent the
736 interpreter from objecting that ``You can't see any such thing``. We've
737 made the ``toilet_key`` a child of the ``benny`` object, and you can see
738 that Benny's got a ``transparent`` attribute; this means that the key is
739 in scope, and enables the player to refer to it without the interpreter
740 complaining. Because Benny also has an ``animate`` attribute, the
741 interpreter would normally intercept a TAKE KEY action with "That seems
742 to belong to Benny"; however, the same wouldn't apply to other commands
743 like TOUCH KEY and TASTE KEY . So, to prevent any interaction with the
744 key while it’s in Benny’s pockets, we define a ``before`` property.
746 .. code-block:: inform
750 "You SCAN your surroundings with ENHANCED AWARENESS,
751 but fail to detect any key.";
753 "Benny is trusting you to look after that key.";
756 All of the ``before`` properties that we've so far created have
757 contained one or more labels specifying the actions which they are to
758 intercept; you'll remember that in "William Tell" we introduced the
759 ``default`` action (see "A class for props" on page 74) to mean "any
760 value not already catered for". There's one of those labels here, for
761 the Drop action, but that's preceded by a piece of code that will be
762 executed at the start of *every* action directed at the key. If it’s
763 still in Benny’s possession, we display a polite refusal; if the player
764 has it then we prevent careless disposal; otherwise, the action
765 continues unhindered.
767 (In fact, the hat-on-a-pole ``Prop`` introduced on page 91 had this
768 all-exclusive ``before`` property:
770 .. code-block:: inform
774 print_ret "You're too far away at the moment.";
777 It would have behaved exactly the same if we'd omitted the ``default``
778 label, as we do here for Benny's key.)
780 Another small innovation here: the ``invent`` library property (we
781 didn’t make it up) which enables you to control how objects appear in
782 inventory listings, overriding the default. Left to itself, the
783 interpreter simply displays the object’s external name, preceded either
784 by a standard article like "a" or "some", or one specifically defined in
785 the object's ``article`` property. Here we replace "the toilet key" with
786 one of two more helpful descriptions, making it a most valuable object
787 in the eyes of John Covarth, and something to be despised haughtily by
788 Captain Fate once it's of no further use to him.
790 When we had players in the street, we faced the problem that they might
791 choose to examine the café from the outside. While it's unlikely that
792 they'll try to examine the toilet room from the outside, it takes very
793 little effort to offer a sensible output just in case:
795 .. code-block:: inform
797 Object outside_of_toilet "toilet" cafe
798 with name 'toilet' 'bath' 'rest' 'room' 'bathroom' 'restroom',
801 if (toilet_door has open) {
806 "Your SUPERB deductive mind detects that the DOOR is
809 if (toilet_door has open)
810 "A brilliant thought flashes through your SUPERLATIVE
811 brain: detailed examination of the toilet would be
812 EXTREMELY facilitated if you entered it.";
814 "With a TREMENDOUS effort of will, you summon your
815 unfathomable ASTRAL VISION and project it FORWARD
816 towards the closed door... until you remember that it's
817 Dr Mystere who's the one with mystic powers.";
819 <<Open toilet_door>>;
821 <<Close toilet_door>>;
823 "That would be PART of the building.";
825 has scenery openable enterable;
827 As with the ``outside_of_cafe`` object, we intercept an ``Enter``
828 action, to teleport players into the toilet room if they type ENTER
829 TOILET (or to display a refusal if the toilet door is closed). Players
830 may try to EXAMINE TOILET; they'll get a different message if the door
831 is open -- we invite them to enter it -- or if it's closed. OPEN TOILET
832 and CLOSE TOILET inputs are redirected to ``Open`` and ``Close`` actions
833 for the toilet door; remember that the double angle-brackets imply a
834 ``return true``, so that the action stops there and the interpreter does
835 not attempt to ``Open`` or ``Close`` the ``outside_of_toilet`` object
836 itself after it has dealt with the door.
838 You're right: the toilet looms large in this game (we blame it on early
839 maternal influences). We’ve introduced an ambiguity problem with the
840 ``outside_of_toilet`` object, and we'll need some help in fixing it.