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