Added Chapter 11.
authorDavid Griffith <dave@661.org>
Fri, 15 Apr 2016 05:00:24 +0000 (22:00 -0700)
committerDavid Griffith <dave@661.org>
Fri, 15 Apr 2016 05:00:24 +0000 (22:00 -0700)
chapters/11.rst [new file with mode: 0644]
images/picV.png [new file with mode: 0644]

diff --git a/chapters/11.rst b/chapters/11.rst
new file mode 100644 (file)
index 0000000..ec95f79
--- /dev/null
@@ -0,0 +1,843 @@
+====================
+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.
diff --git a/images/picV.png b/images/picV.png
new file mode 100644 (file)
index 0000000..0472d98
Binary files /dev/null and b/images/picV.png differ