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