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