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