--- /dev/null
+====================
+Captain Fate: take 2
+====================
+
+.. epigraph::
+
+ | *U was a usurer, a miserable elf;*
+ | *V was a vintner, who drank all himself.*
+
+.. only:: html
+
+ .. image:: /images/picV.png
+ :align: left
+
+.. raw:: latex
+
+ \dropcap{v}
+
+iewed from the inside, Benny's café is warm and welcoming, and packed
+with lunchtime customers. We'll try to conjure up some appropriate
+images, but the main focus of the room isn't the decor: it's the door
+leading to the toilet -- and, perhaps, privacy?
+
+A homely atmosphere
+===================
+
+Benny's café is populated with customers enjoying their lunch, so it
+won't be a good place to change identities. However, the toilet to the
+north looks promising, though Benny has strict rules about its use and
+the door seems to be locked.
+
+.. admonition:: Cultural Note
+ :class: admonition note
+
+ not for the first time, this guide betrays its origins. In
+ European countries the word "toilet" often refers not only to the
+ white porcelain artefact, but also to the room in which it can be
+ found (also, a "bathroom" is for taking a bath, a "restroom" for
+ taking a rest). Bear with us on this; the dual usage becomes
+ important a little later on.
+
+We define the café room in simple form:
+
+.. code-block:: inform6
+
+ Room cafe "Inside Benny's cafe"
+ with description
+ "Benny's offers the FINEST selection of pastries and
+ sandwiches. Customers clog the counter, where Benny himself
+ manages to serve, cook and charge without missing a step. At
+ the north side of the cafe you can see a red door connecting
+ with the toilet.",
+ s_to street,
+ n_to toilet_door;
+
+We'll elaborate on the last line (``n_to toilet_door``) later, when we
+define the door object which lies between the café and the toilet.
+
+We've mentioned a counter:
+
+.. code-block:: inform6
+
+ Appliance counter "counter" cafe
+ with name 'counter' 'bar',
+ article "the",
+ description
+ "The counter is made of an astonishing ALLOY of metals,
+ STAIN-PROOF, SPILL-RESISTANT and VERY EASY to clean. Customers
+ enjoy their snacks with UTTER tranquillity, safe in the notion
+ that the counter can take it all.",
+ before [;
+ Receive:
+ <<Give noun benny>>;
+ ],
+ has supporter;
+
+That ``before property``, superficially normal, actually conceals a
+little surprise. By now you should be entirely comfortable with using an
+object's ``before`` property to intercept an action directed at that
+object; for example, if the player types HIT COUNTER then the counter's
+``before`` property is potentially able to intercept the resulting
+Attack action. However, the command PUT KEY ON COUNTER generates *two*
+actions. First, a PutOn action is offered to the key (effectively
+saying, do you want to be placed on top of the counter?); that’s the
+normal bit. And then the surprise: a Receive action is offered to the
+counter (effectively saying, are you happy to have the key placed on
+you?) Both actions have the same opportunity of returning ``false`` to
+let the action continue, ``true`` to prevent it.
+
+.. todo::
+
+ There are a lot of actions here that are rendered in a typewriter font
+ and others that are not. Should these ones that are not be promoted
+ to having a typewriter font?
+
+The Receive action is generated by the library in the PutOnSub action
+handler, and also in InsertSub (so a command like PUT BIRD IN NEST sends
+a Receive to the nest object). There’s a matching LetGo, generated by
+the library from commands like TAKE KEY OFF COUNTER and REMOVE BIRD FROM
+NEST. Receive and LetGo are examples of what’s called a **fake action**.
+
+.. note::
+
+ in "William Tell" we defined the ``quiver``, way back in "The
+ player's possessions" on page 83, as an ``open container``. As things
+ stand, the player can put *any* held object, however inappropriate,
+ into it. We could have trapped the Receive action to ensure that
+ arrows are the only acceptable contents (recollect that ``~~``, to be
+ read as "not", turns true into false and vice versa):
+
+ .. code-block:: inform6
+
+ before [;
+ Drop,Give:
+ print_ret "But it was a present from Hedwig, your wife.";
+ Receive:
+ if (~~(noun ofclass Arrow))
+ print_ret "Only arrows -- clean arrows -- go in your quiver.";
+ ],
+
+Here, we intercept any attempt to place an item on the counter, and
+translate it into an attempt to give that item to Benny. Part of the
+game's plot depends on the player returning the toilet key to Benny, and
+also paying him for his delicious cup of world-famous Cappuccino.
+Putting the key and the money on the counter is a reasonable alternative
+way for the player to accomplish this.
+
+We've also mentioned some customers. These are treated as NPCs, reacting
+to our hero’s performance.
+
+.. code-block:: inform6
+
+ Object customers "customers" cafe
+ with name 'customers' 'people' 'customer' 'men' 'women',
+ description [;
+ if (costume has worn)
+ "Most seem to be concentrating on their food, but some do
+ look at you quite blatantly. Must be the MIND-BEFUDDLING
+ colours of your costume.";
+ else
+ "A group of HELPLESS and UNSUSPECTING mortals, the kind
+ Captain FATE swore to DEFEND the day his parents choked on a
+ DEVIOUS slice of RASPBERRY PIE.";
+ ],
+ life [;
+ Ask,Tell,Answer:
+ if (costume has worn)
+ "People seem to MISTRUST the look of your FABULOUS costume.";
+ else
+ "As John Covarth, you attract LESS interest than Benny's
+ food.";
+ Kiss:
+ "There's no telling what sorts of MUTANT bacteria these
+ STRANGERS may be carrying around.";
+ Attack:
+ "Mindless massacre of civilians is the qualification for
+ VILLAINS. You are SUPPOSED to protect the likes of these
+ people.";
+ ],
+ orders [;
+ "These people don't appear to be of the cooperative sort.";
+ ],
+ number_of_comments 0, ! for counting the customer comments
+ daemon [;
+ if (location ~= cafe) return;
+ if (self.number_of_comments == 0) {
+ self.number_of_comments = 1;
+ print "^Nearby customers glance at your costume with open
+ curiosity.^";
+ }
+ if (random(2) == 1) { ! do this 50% of the time
+ self.number_of_comments = self.number_of_comments + 1;
+ switch (self.number_of_comments) {
+ 2: "^~Didn't know there was a circus in town,~ comments one
+ customer to another. ~Seems like the clowns have the
+ day off.~";
+ 3: "^~These fashion designers don't know what to do to show
+ off,~ snorts a fat gentleman, looking your way. Those
+ within earshot try to conceal their smiles.";
+ 4: "^~Must be carnival again,~ says a man to his wife, who
+ giggles, stealing a peek at you. ~Time sure flies.~";
+ 5: "^~Bad thing about big towns~, comments someone to his
+ table companion, ~is you get the damnedest bugs coming
+ out from toilets.~";
+ 6: "^~I sure WISH I could go to work in my pyjamas,~ says a
+ girl in an office suit to some colleagues. ~It looks SO
+ comfortable.~";
+ default: StopDaemon(self);
+ }
+ }
+ ],
+ has scenery animate pluralname;
+
+Let's go step by step. Our hero enters the café dressed as John Covarth,
+but will eventually manage to change clothes in the toilet, and he'll
+have to cross back through the café to reach the street and win the
+game. The customers' ``description`` takes into consideration which
+outfit the player character is wearing.
+
+In "William Tell" we’ve seen a brief manifestation of the ``life``
+property, but here we'll extend it a little. As we explained, ``life``
+lets you intercept those actions particular to animate objects. Here we
+trap ``Attack`` and ``Kiss`` to offer some customised messages for these
+actions when applied to the customers. Also, we avoid conversation by
+intercepting ``Ask``, ``Tell`` and ``Answer`` in order just to produce a
+message which depends on the player character's attire.
+
+One other feature of ``animate`` objects is the possibility of giving
+them orders: BILL, SHAKE THE SPEAR or ANNIE, GET YOUR GUN . These
+actions are dealt with in the ``orders`` property and, as with the
+``life`` property, the embedded routine can become quite complex if you
+want your NPCs to behave in an interesting way. In this case, we don't
+need the customers to perform tasks for us, so instead we provide a
+simple rejection message, just in case the player tries to order people
+around.
+
+Which leaves us with the ``daemon`` bit. A daemon is a property normally
+used to perform some timed or repetitive action without the need of the
+player’s direct interaction; for example, machines which work by
+themselves, animals that move on their own, or people going about their
+business. More powerfully, a daemon may take notice of the player’s
+decisions at a particular moment, allowing for some interactive
+behaviour; this is, however, an advanced feature that we won't use in
+this example. A daemon gets a chance of doing something at the end of
+every turn, typically to (or with) the object to which it’s associated.
+In our example, the daemon triggers some sneers and nasty comments from
+the customers once our hero comes out of the toilet dressed in Captain
+Fate’s costume.
+
+To code a daemon, you need to do three things:
+
+#. First, define a daemon property in the object’s body; the value of
+ the property is always an embedded routine.
+
+#. However, daemons do nothing until you activate them. This is easily
+ achieved with the call ``StartDaemon(obj_id)``, which may happen
+ anywhere (if you want some object's daemon to be active from the
+ beginning of the game,you can make the call in your Initialise
+ routine).
+
+#. Once the daemon has finished its mission (if ever) you may stop it
+ with the call ``StopDaemon(obj_id)``.
+
+How does our particular daemon work? The appearance of our hero in full
+crime-fighting wear will make the customers stare at him and make snarky
+remarks. This must happen in the café room – the place where the
+customers are -- so we need to make certain that the daemon does
+something interesting only while the player stays in the right place
+(and hasn’t wandered, say, back into the toilet):
+
+.. code-block:: inform6
+
+ if (location ~= cafe) return;
+
+So if the location is not the café room (remember ~= means "not equal
+to"), return without doing anything else; on this turn, there’s nothing
+for the daemon to do. We use a plain ``return`` statement because the
+value returned from a daemon doesn’t matter.
+
+We have defined a customised local property, ``number_of_comments``, to
+control the sequence of customers' remarks. When the Captain enters the
+café room from the toilet for the first time, the value of the property
+should be zero, so the statement block under the test:
+
+.. code-block:: inform6
+
+ if (self.number_of_comments == 0) {
+ self.number_of_comments = 1;
+ print "^Nearby customers glance at your costume with open
+ curiosity.^";
+ }
+
+will happen only this once. What we intend is to output the text "Nearby
+customers..." right after the startling entrance of our hero, setting up
+the scene for the comments which are about to happen. Since we assign a
+value of 1 to the property, the message will not be printed again.
+Notice how we use an explicit ``print`` statement; the execution of the
+daemon will continue normally to the next line.
+
+We want the customers to indulge in witticisms once they see the
+costumed Captain, but not on a completely predictable basis.
+
+.. code-block:: inform6
+
+ if (random(2) == 1) ...
+
+.. todo::
+
+ "expression" in "random(expression)" should be typewriter and italic
+
+``random`` is an Inform routine used to generate random numbers or to
+choose randomly between given choices; in the form
+``random(expression)`` it returns a random number between 1 and
+``expression`` inclusive. So our condition is actually stating: if a
+random choice between 1 and 2 happens to be 1 then perform some action.
+Remember that a daemon is run once at the end of every turn, so the
+condition is trying to squeeze a comment from a customer roughly once
+every other turn.
+
+Next, we proceed as we have already seen in "William Tell", with a
+switch statement to order the comments in a controlled sequence by
+cunning use of our tailored local property, ``number_of_comments``. We
+have written just five messages (could have been one or a hundred) and
+then we reach the default case, which is a good place to stop the
+daemon, since we have no more customers’ remarks to display.
+
+Ah, but when does the daemon *start* functioning? Well, as soon as our
+protagonist comes out of the toilet dressed in his multicoloured
+super-hero pyjamas. Since we want to minimise the possible game states,
+we’ll make some general rules to avoid trouble: (a) players will be able
+to change only in the toilet; (b) we won’t let players change back into
+street clothes; and (c) once players manage to step into the street thus
+dressed, the game is won. So, we can safely assume that if players enter
+the café in their Captain’s outfit, they’ll be coming from the toilet.
+As a consequence of all this, we add an ``after`` property to the café
+room object:
+
+.. code-block:: inform6
+
+ Room cafe "Inside Benny's cafe"
+ ...
+ first_time_out false, ! Captain Fate's first appearance?
+ after [;
+ Go: ! The player has just arrived. Did he come from the toilet?
+ if (noun ~= s_obj) return false;
+ if (costume has worn && self.first_time_out == false) {
+ self.first_time_out = true;
+ StartDaemon(customers);
+ }
+ ],
+ s_to street,
+ n_to toilet_door
+
+There are two useful techniques to detect when the player is entering or
+leaving a room. We'll later see in detail how to deal with a player
+trying to go away and how to avoid it if need be. For now, let’s just
+mention that, in both cases, you have to intercept the ``Go`` action in
+a room object; if you trap it in a ``before`` property, you’re checking
+for departure from the room; if you trap it in an ``after`` property,
+you’re checking for arrivals into the room. Right now we wish to know if
+the player just came from the toilet, so we use an ``after`` property.
+
+The first line:
+
+.. code-block:: inform6
+
+ if (noun ~= s_obj) return false;
+
+is telling the interpreter that we want to do something if the player
+entered the room by typing a GO SOUTH command (this would normally mean
+"coming from the north", but remember that nothing stops you from
+connecting rooms without cardinal logic); the interpreter will apply
+normal rules for the other available directions.
+
+Then we check whether the player character is wearing the costume, in
+which case it starts the ``daemon`` of the ``customers`` object. The use
+of the local first_time_out property ensures that the condition is
+``true`` only once, so the statement block attached to it runs also
+once.
+
+We've finished with the customers in the café. Now, we have the toilet
+to the north which, for reasons of gameplay *and* decency, is protected
+by a door.
+
+A door to adore
+===============
+
+Door objects require some specific properties and attributes. Let's
+first code a simple door:
+
+.. code-block:: inform6
+
+ Object toilet_door "toilet door" cafe
+ name name 'red' 'toilet' 'door',
+ description
+ "A red door with the unequivocal black man-woman
+ silhouettes marking the entrance to hygienic facilities.
+ There is a scribbled note stuck on its surface.",
+ door_dir n_to,
+ door_to toilet,
+ with_key toilet_key,
+ has scenery door openable lockable locked;
+
+We find this door in the café. We must specify the direction in which
+the door leads and, as we have mentioned in the café's description, that
+would be to the north. That’s what the ``door_dir`` property is for, and
+in this case it takes the value of the north direction property
+``n_to``. Then we must tell Inform the identity of the room to be found
+behind the door, hence the ``door_to`` property, which takes the value
+of the toilet room -- to be defined later. Remember the café's
+connection to the north, ``n_to toilet_door``? Thanks to it, Inform will
+know that the door is in the way, and thanks to the ``door_to``
+property, what lies beyond.
+
+Doors *must* have the attribute ``door``, but beyond that we have a
+stock of options to help us define exactly what kind of door we are
+dealing with. As for containers, doors can be ``openable`` (which
+activates the verbs OPEN and CLOSE so that they can be applied to this
+object) and, since by default they are closed, you can give them the
+attribute ``open`` if you wish otherwise. Additionally, doors can be
+``lockable`` (which sets up the LOCK/UNLOCK verbs) and you can make them
+``locked`` to override their default unlocked status. The verbs LOCK
+and UNLOCK are expecting some kind of key object to operate the door.
+This must be defined using the ``with_key`` property, whose value should
+be the internal ID of the key; in our example, the soon-to-be-defined
+``toilet_key`` . If you don't supply this property, players won't be
+able to lock or unlock the door.
+
+This simple door definition has one problem, namely, that it exists only
+in the café room. If you wish the door to be present also from the
+toilet side, you can either (a) define another door to be found in the
+``toilet room``, or (b) make this one a two-sided door.
+
+Solution (a) seems superficially straightforward, but then you have the
+problem of keeping the states of the two doors – open/closed,
+locked/unlocked -- in synch. In this scenario, where you can access the
+toilet only through this door, that wouldn't be too complicated, since
+you could leave the door object in the café room opened all the time,
+regardless of what players do with the door object in the toilet room
+and vice versa -- they are never going to see them at the same time. In
+general terms, though, such inconsistencies lead to problems; solution
+(a) is best ignored for most purposes.
+
+Solution (b) is better, since you have only one door object to deal with
+and its possible states affect both sides. However, the coding gets a
+little bit complicated and you''ll have to define routines for most
+properties:
+
+.. code-block:: inform6
+
+ Object toilet_door "toilet door"
+ with name 'red' 'toilet' 'door',
+ description [;
+ if (location == cafe)
+ "A red door with the unequivocal black man-woman silhouettes
+ marking the entrance to hygienic facilities. There is a
+ scribbled note stuck on its surface.";
+ else
+ "A red door with no OUTSTANDING features.";
+ ],
+ found_in cafe toilet,
+ door_dir [;
+ if (location == cafe) return n_to;
+ else return s_to;
+ ],
+ door_to [;
+ if (location == cafe) return toilet;
+ else return cafe;
+ ],
+ with_key toilet_key,
+ has scenery door openable lockable locked;
+
+First of all, the door now needs a ``found_in`` property, since it's
+going to be located both in the café and the toilet. The ``description``
+checks which side of the door we are looking at – testing the current
+value of the variable ``location``, which holds the room the player is
+in -- because we have a scribbled note stuck on one side, but not on the
+other. And the ``door_dir`` and ``door_to`` properties must use the same
+trick, because we travel north from the café into the toilet, but south
+from the toilet into the café.
+
+Right now, the game will display "the toilet door" every time it needs
+to refer to this object. It would be nice if we could somehow get the
+game to distinguish between "the door to the toilet" and "the door to
+the cafe", depending on the side we are facing. For this, a ``short_name
+property`` is the thing. We have already talked about the external name
+defined as part of an object's header information:
+
+.. code-block:: inform6
+
+ Object toilet_door "toilet door"
+
+That ``toilet door`` will be the name displayed by the game at run-time
+to refer to the door. With identical effect, this could also have been
+coded thus:
+
+.. code-block:: inform6
+
+ Object toilet_door
+ with short_name "toilet door",
+
+``short_name`` is a property that supplies the external name of an
+object, either as a string or an embedded routine. Normally, objects
+retain the same external name throughout the game -- and the header
+information method is perfect in that case -- but if it needs to change,
+it's easy to write a routine as the value of ``short_name``:
+
+.. code-block:: inform6
+
+ Object toilet_door
+ with name 'red' 'toilet' 'door'
+ short_name [;
+ if (location == cafe) print "door to the toilet";
+ else print "door to the cafe";
+ ],
+ description
+ ...
+
+Notice the ``return true`` at the end of the routine. You''ll recall
+that the standard rule says "return false to carry on, true to take over
+and stop normal execution”. In the case of ``short_name``, "carry on"
+means "and now display the external name from the header information",
+which is sometimes handy; for instance, you could write a ``short_name``
+routine to prefix an object's external name with one of a range of
+adjectives -- perhaps a shining/flickering/fading/useless lantern.
+
+.. note::
+
+ what's displayed if there isn't an external name in an object's
+ header? If you've read the section "Compile-as-you-go" on page 233,
+ you'll recall that the interpreter simply uses the internal
+ identifier within parentheses; that is, with no external name and no
+ ``short_name`` property, we might see:
+
+ .. code-block:: inform6
+
+ You open the (toilet_door).
+
+ And the same principle applies if we were mistakenly to ``return
+ false`` from this short_name routine: we would get, first, the result
+ of our ``print`` statement, and then the standard rules would display
+ the internal ID:
+
+ .. code-block:: inform6
+
+ You open the door to the toilet(toilet_door).
+
+Doors can get more complicated than this (no, please, don't throw our
+guide out of the window). Here comes some optional deluxe coding to make
+the door object a bit friendlier in game play, so you can skip it if you
+foresee headaches.
+
+Our door now behaves nicely at run-time. It can be locked and unlocked
+if the player character has the right key; it can be opened and closed.
+A sequence of commands to go into the toilet and lock the door behind
+you would be: UNLOCK DOOR WITH KEY, OPEN DOOR, GO NORTH, CLOSE DOOR,
+LOCK DOOR WITH KEY. After we are finished, let's go back to the café:
+UNLOCK DOOR WITH KEY, OPEN DOOR, SOUTH. If the player is of the
+fastidious kind: CLOSE DOOR, LOCK DOOR WITH KEY. This game features only
+one door, but if it had three or four of them, players would grow
+restless (at the very least) if they needed to type so many commands
+just to go through a door. This is the kind of thing reportedly
+considered as poor design, because the game is suddenly slowed down to
+get over a simple action which involves no secrets or surprises. How
+exciting can the crossing of an ordinary door be, after all?
+
+If a few lines of code can make the life of the player easier, it's
+worth a shot. Let's provide a few improvements to our toilet door in
+``before`` and ``after`` properties:
+
+.. code-block:: inform6
+
+ before [ ks;
+ Open:
+ if (self hasnt locked || toilet_key notin player)
+ return false;
+ ks = keep_silent; keep_silent = true;
+ <Unlock self toilet_key>; keep_silent = ks;
+ return true;
+ Lock:
+ if (self hasnt open) return false;
+ print "(first closing ", (the) self, ")^";
+ ks = keep_silent; keep_silent = true;
+ <Close self>; keep_silent = ks;
+ return false;
+ ],
+ after [ ks;
+ Unlock:
+ if (self has locked) return false;
+ print "You unlock ", (the) self, " and open it.^";
+ ks = keep_silent; keep_silent = true;
+ <Open self>; keep_silent = ks;
+ return true;
+ ],
+
+The basic idea here is to let the player who holds the key perform just
+one action to both unlock *and* open the door (and, conversely, to close
+*and* lock it). The relevant actions are ``Unlock`` and ``Open``, and
+``Lock`` ( ``Close`` is not necessary; if players just close the door we
+shouldn’t assume that they want to lock it as well).
+
+* **Open**: if the door isn't locked or the player doesn't hold the key,
+ keep going with the default ``Open`` action defined by the library.
+ That leaves a locked door and a player holding the key, so we
+ redirect processing to the ``Unlock`` action, giving as arguments the
+ door (self) and the toilet key. Since we are using single
+ angle-brackets ``<...>``, the action resumes after the unlocking is
+ done (note that the ``Unlock`` action also takes care of opening the
+ door). Finally, we ``return true`` to stop the library from trying to
+ open the door by itself.
+
+* **Lock**: if the door is already closed, keep going with the standard
+ library ``Lock`` action. If not, tell players that we are closing the
+ door for them, redirect the action briefly to actually close it, and
+ then ``return false`` to let the ``Lock`` action proceed as before.
+
+* **Unlock**: we place this action in the after property, so (let's
+ hope) the ``Unlock`` action has already happened. If the door is still
+ locked, something went wrong, so we ``return false`` to display the
+ standard message for an unsuccessful unlocking. Otherwise, the door is
+ now unlocked, so we inform the player that we are opening the door and
+ redirect the action to actually open it, returning ``true`` to
+ suppress the standard message.
+
+In all processes there is a library variable called ``keep_silent``,
+which can be either ``false`` (the normal state) or ``true``; when
+``true``, the interpreter does not display the associated message of an
+action in progress, so we can avoid things like::
+
+ >OPEN DOOR
+ You open the door to the toilet.
+ You unlock the door to the toilet and open it.
+
+Although we want to set ``keep_silent`` to ``true`` for the duration of
+our extra processing, we need to reset it afterwards. In a case like
+this, good design practice is to preserve its initial value (which was
+probably ``false``, but you should avoid risky assumptions); we use a
+local variable ``ks`` to remember that initial setting so that we can
+safely restore it afterwards. You’ll remember that a local variable in a
+standalone routine is declared between the routine’s name and the
+semicolon:
+
+.. code-block:: inform6
+
+ [ BeenToBefore this_room;
+
+In exactly the same way, a local variable in an embedded routine is
+declared between the ``[`` starting marker of the routine and the
+semicolon:
+
+.. code-block:: inform6
+
+ before [ ks;
+
+You can declare up to fifteen variables this way -- just separated by
+spaces -- which are usable only within the embedded routine. When we
+assign it thus:
+
+.. code-block:: inform6
+
+ ks = keep_silent;
+
+we are actually making ``ks`` equal to whatever value ``keep_silent``
+has (either ``true`` or ``false``; we actually don't care). We then set
+``keep_silent`` to ``true``, make the desired silent actions, and we
+assign:
+
+.. code-block:: inform6
+
+ keep_silent = ks;
+
+which restores the value originally stored in ``ks`` to ``keep_silent``.
+The effect is that we manage to leave it as it was before we tampered
+with it.
+
+Well, that's about everything about doors. Everything? Well, no, not
+really; any object can grow as complex as your imagination allows, but
+we’ll drop the subject here. If you care to see more sophisticated
+doors, check Exercises 3 and 4 in the *Inform Designer's Manual*, where
+an obliging door opens and unlocks by itself if the player simply walks
+in its direction.
+
+So far, we have the player in front of a locked door leading to the
+toilet. A dead end? No, the description mentions a scribbled note on its
+surface. This one should offer no problem:
+
+.. code-block:: inform6
+
+ Object "scribbled note" cafe
+ with name 'scribbled' 'note',
+ description [;
+ if (self.read_once == false) {
+ self.read_once = true;
+ "You apply your ENHANCED ULTRAFREQUENCY vision to the note
+ and squint in concentration, giving up only when you see the
+ borders of the note begin to blacken under the incredible
+ intensity of your burning stare. You reflect once more how
+ helpful it would've been if you'd ever learnt to read.
+ ^^A kind old lady passes by and explains:
+ ~You have to ask Benny for the key, at the counter.~^^
+ You turn quickly and begin, ~Oh, I KNOW that, but...~^^
+ ~My pleasure, son,~ says the lady, as she exits the cafe.";
+ }
+ else
+ "The scorched undecipherable note holds no SECRETS from
+ you NOW! Ha!";
+ ],
+ read_once false, ! has the player read the note once?
+ before [;
+ Take:
+ "No reason to start collecting UNDECIPHERABLE notes.";
+ ],
+ has scenery;
+
+Just notice how we change the description after the first time the
+player examines the note, using the local property ``read_once`` created
+just for this purpose. We don’t want the player to walk off with the
+note, so we intercept the ``Take`` action and display something more in
+character than the default message for scenery objects: "That's hardly
+portable".
+
+We've talked a lot about the toilet key; it seems about time to code it.
+Originally, the key is in Benny's possession, and the player will have
+to ask for it, just as the note explains. Although we'll define Benny in
+detail throughout the next chapter, here we present a basic definition,
+largely so that the key has a parent object.
+
+.. code-block:: inform6
+
+ Object benny "Benny" cafe
+ with name 'benny',
+ description
+ "A deceptively FAT man of uncanny agility, Benny entertains his
+ customers crushing coconuts against his forehead when the mood
+ strikes him.",
+ has scenery animate male proper transparent;
+
+ Object toilet_key "toilet key" benny
+ with name 'toilet' 'key',
+ article "the",
+ invent [;
+ if (clothes has worn) print "the CRUCIAL key";
+ else print "the used and IRRELEVANT key";
+ return true;
+ ],
+ description
+ "Your SUPRA PERCEPTIVE senses detect nothing of consequence
+ about the toilet key.",
+ before [;
+ if (self in benny)
+ "You SCAN your surroundings with ENHANCED AWARENESS,
+ but fail to detect any key.";
+ Drop:
+ "Benny is trusting you to look after that key.";
+ ];
+
+While Benny has the key, there's logically no way to examine it (or
+perform any other action involving it), but we want to prevent the
+interpreter from objecting that ``You can't see any such thing``. We've
+made the ``toilet_key`` a child of the ``benny`` object, and you can see
+that Benny's got a ``transparent`` attribute; this means that the key is
+in scope, and enables the player to refer to it without the interpreter
+complaining. Because Benny also has an ``animate`` attribute, the
+interpreter would normally intercept a TAKE KEY action with "That seems
+to belong to Benny"; however, the same wouldn't apply to other commands
+like TOUCH KEY and TASTE KEY . So, to prevent any interaction with the
+key while it’s in Benny’s pockets, we define a ``before`` property.
+
+.. code-block:: inform6
+
+ before [;
+ if (self in benny)
+ "You SCAN your surroundings with ENHANCED AWARENESS,
+ but fail to detect any key.";
+ Drop:
+ "Benny is trusting you to look after that key.";
+ ];
+
+All of the ``before`` properties that we've so far created have
+contained one or more labels specifying the actions which they are to
+intercept; you'll remember that in "William Tell" we introduced the
+``default`` action (see "A class for props" on page 74) to mean "any
+value not already catered for". There's one of those labels here, for
+the Drop action, but that's preceded by a piece of code that will be
+executed at the start of *every* action directed at the key. If it’s
+still in Benny’s possession, we display a polite refusal; if the player
+has it then we prevent careless disposal; otherwise, the action
+continues unhindered.
+
+(In fact, the hat-on-a-pole ``Prop`` introduced on page 91 had this
+all-exclusive ``before`` property:
+
+.. code-block:: inform6
+
+ before [;
+ default:
+ print_ret "You're too far away at the moment.";
+ ],
+
+It would have behaved exactly the same if we'd omitted the ``default``
+label, as we do here for Benny's key.)
+
+Another small innovation here: the ``invent`` library property (we
+didn’t make it up) which enables you to control how objects appear in
+inventory listings, overriding the default. Left to itself, the
+interpreter simply displays the object’s external name, preceded either
+by a standard article like "a" or "some", or one specifically defined in
+the object's ``article`` property. Here we replace "the toilet key" with
+one of two more helpful descriptions, making it a most valuable object
+in the eyes of John Covarth, and something to be despised haughtily by
+Captain Fate once it's of no further use to him.
+
+When we had players in the street, we faced the problem that they might
+choose to examine the café from the outside. While it's unlikely that
+they'll try to examine the toilet room from the outside, it takes very
+little effort to offer a sensible output just in case:
+
+.. code-block:: inform6
+
+ Object outside_of_toilet "toilet" cafe
+ with name 'toilet' 'bath' 'rest' 'room' 'bathroom' 'restroom',
+ before [;
+ Enter:
+ if (toilet_door has open) {
+ PlayerTo(toilet);
+ return true;
+ }
+ else
+ "Your SUPERB deductive mind detects that the DOOR is
+ CLOSED.";
+ Examine:
+ if (toilet_door has open)
+ "A brilliant thought flashes through your SUPERLATIVE
+ brain: detailed examination of the toilet would be
+ EXTREMELY facilitated if you entered it.";
+ else
+ "With a TREMENDOUS effort of will, you summon your
+ unfathomable ASTRAL VISION and project it FORWARD
+ towards the closed door... until you remember that it's
+ Dr Mystere who's the one with mystic powers.";
+ Open:
+ <<Open toilet_door>>;
+ Close:
+ <<Close toilet_door>>;
+ Take,Push,Pull:
+ "That would be PART of the building.";
+ ],
+ has scenery openable enterable;
+
+As with the ``outside_of_cafe`` object, we intercept an ``Enter``
+action, to teleport players into the toilet room if they type ENTER
+TOILET (or to display a refusal if the toilet door is closed). Players
+may try to EXAMINE TOILET; they'll get a different message if the door
+is open -- we invite them to enter it -- or if it's closed. OPEN TOILET
+and CLOSE TOILET inputs are redirected to ``Open`` and ``Close`` actions
+for the toilet door; remember that the double angle-brackets imply a
+``return true``, so that the action stops there and the interpreter does
+not attempt to ``Open`` or ``Close`` the ``outside_of_toilet`` object
+itself after it has dealt with the door.
+
+You're right: the toilet looms large in this game (we blame it on early
+maternal influences). We’ve introduced an ambiguity problem with the
+``outside_of_toilet`` object, and we'll need some help in fixing it.