.. epigraph::
- | *W was a watchman, and guarded the door;*
- | *X was expensive, and so became poor.*
+ | |CENTER| *W was a watchman, and guarded the door;*
+ | |CENTER| *X was expensive, and so became poor.*
.. only:: html
.. image:: /images/picW.png
:align: left
-.. raw:: latex
-
- \dropcap{w}
-
-e've given ourselves an interesting challenge by overusing that
-convenient word "toilet", and here we show you how we resolve the
-ambiguities that have been introduced. Also, it's time for the eponymous
+|W|\e've given ourselves an interesting challenge by overusing that
+convenient word "toilet", and here we show you how we resolve the
+ambiguities that have been introduced. Also, it's time for the eponymous
owner of Benny's café to be developed in full.
Too many toilets
================
-If you check the ``name`` properties of the toilet door, the toilet key
+.. index::
+ single: ambiguous objects
+
+If you check the :prop:`name` properties of the toilet door, the toilet key
and the toilet room, you’ll see that the dictionary word ``'toilet'``
occurs in all of them. There won't be any problems if players mention
the words DOOR or KEY, but we reach a strange impasse should they try to
form of a library extension: the solution neatly packaged as a file that
other designers can incorporate into their source code. These files can
be found in the IF Archive: go to
-``http://mirror.ifarchive.org/indexes/if-archive.html`` and then select
+http://mirror.ifarchive.org/indexes/if-archive.html and then select
"``.../infocom``", "``.../compilers``", "``.../inform6``",
"``.../library``", and "``.../contributions``". All of these files
contain Inform code. To use a library extension (also known as a library
your source code. It is not unusual to find other suggestions and
warnings.
-To help us out of the disambiguation problem with the word TOILET, we
-are going to use Neil Cerutti's extension ``pname.h``, which is designed
-for situations precisely like this. First, we follow the link to the IF
-archive and download the compressed file ``pname.zip``, which contains
-two more files: ``pname.h`` and ``pname.txt``. We place these files in
-the folder where we are currently developing our game or, if using the
-environment we proposed in "Tools of the trade" on page 17, in the
-``Inform\Lib\Contrib`` folder. The text file offers instructions about
-installation and usage. Here we find a warning:
+To help us out of the disambiguation problem with the word TOILET, we are
+going to use Neil Cerutti's extension ``pname.h``, which is designed for
+situations precisely like this. First, we follow the link to the IF archive
+and download the compressed file ``pname.zip``, which contains two more
+files: ``pname.h`` and ``pname.txt``. We place these files in the folder
+where we are currently developing our game or, if using the environment we
+proposed in :doc:`02`, in the ``Inform\Lib\Contrib`` folder. The text file
+offers instructions about installation and usage. Here we find a warning:
This version of pname.h is recommended for use only with version 6/10
of the Inform Library.
identical in other Inform versions.
The introduction explains what ``pname.h`` does for you; namely, it lets
-you avoid using complicated ``parse_name`` routines to disambiguate the
+you avoid using complicated :prop:`parse_name` routines to disambiguate the
player's input when the same dictionary word refers to more than one
-item. A ``parse_name`` routine would have been the solution to our
+item. A :prop:`parse_name` routine would have been the solution to our
problem before the existence of this file, and it qualifies as an
advanced programming topic, difficult to master on a first approach.
Fortunately, we don't need to worry. Neil Cerutti explains:
The ``pname.h`` package defines a new object property, ``pname``
(short for phrase name), with a similar look and feel to the standard
- ``name`` property: both contain a list of dictionary words. However,
+ :prop:`name` property: both contain a list of dictionary words. However,
in a ``pname`` property the order of the words is significant, and
special operators ``'.p'`` ``'.or'`` and ``'.x'`` enable you to embed
some intelligence into the list. In most cases where the standard
- ``name`` property isn't enough, you can now just replace it with a
- ``pname`` property, rather than write a ``parse_name`` property
+ :prop:`name` property isn't enough, you can now just replace it with a
+ ``pname`` property, rather than write a :prop:`parse_name` property
routine.
We'll soon see how it works. Let's take a look at the installation
#. Add four lines near the head of the program (before you include
``Parser.h``).
- ``Replace MakeMatch;``
- ``Replace Identical;``
- ``Replace NounDomain;``
- ``Replace TryGivenObject;``
+ .. code-block:: inform
+
+ Replace MakeMatch;
+ Replace Identical;
+ Replace NounDomain;
+ Replace TryGivenObject;
#. Include the ``pname.h`` header just after you include ``Parser.h``.
- ``Include "Parser";``
- ``Include "pname";``
+
+ .. code-block:: inform
+
+ Include "Parser";
+ Include "pname";
#. Add ``pname`` properties to those objects which require phrase
recognition.
``pname.h`` right after it. ``Replace`` tells the compiler that we're
providing replacements for some standard routines.
-.. code-block:: inform6
+.. code-block:: inform
Constant Story "Captain Fate";
Constant Headline
Include "Parser";
Include "pname";
- !...
+ ...
Now our source code is ready to benefit from the library package. How
does it work? We have acquired a new property -- ``pname`` -- which can
be added to some of our objects, and which works pretty much like a
-``name`` property. In fact, it should be used *instead* of a ``name``
+:prop:`name` property. In fact, it should be used *instead* of a :prop:`name`
property where we have a disambiguation problem. Let’s change the
relevant lines for the toilet door and the toilet key:
-.. todo::
-
- Maybe specially highlight the lines using pname?
-
-.. code-block:: inform6
+.. code-block:: inform
Object toilet_door
with pname '.x' 'red' '.x' 'toilet' 'door',
short_name [;
- !...
+ ...
Object toilet_key "toilet key" benny
with pname '.x' 'toilet' 'key',
article "the",
- !...
+ ...
while leaving the ``outside_of_toilet`` unchanged:
-.. code-block:: inform6
+.. code-block:: inform
Object outside_of_toilet "toilet" cafe
with name 'toilet' 'bath' 'rest' 'room' 'bathroom' 'restroom',
before [;
- !...
+ ...
We are now using a new operator -- ``'.x'`` -- in our ``pname`` word
lists. explains
these objects, so that at run-time players could refer to the DOOR or
TOILET DOOR or the KEY or TOILET KEY -- but not simply to the TOILET --
when referring to either the door or the key. And, by leaving unchanged
-the name property of the outside_of_toilet object – where there is also
+the name property of the ``outside_of_toilet`` object – where there is also
another ``'toilet'`` entry -- the ``pname`` properties will tell the
interpreter to discard the key and the door as possible objects to be
considered when players refer just to TOILET. Looking at it in terms of
about sums it all up; pretty simple to describe -- not so simple to
code. Remember Benny's basic definition from the previous chapter:
-.. code-block:: inform6
+.. code-block:: inform
Object benny "Benny" cafe
with name 'benny',
strikes him.",
has scenery animate male proper transparent;
-We can now add some complexity, beginning with a ``life`` property. In
+We can now add some complexity, beginning with a :prop:`life` property. In
generic form:
-.. code-block:: inform6
+.. code-block:: inform
life [;
Give: !... code for giving objects to Benny
We have seen some of these actions before. We'll take care of the easier
ones:
-.. code-block:: inform6
+.. code-block:: inform
Attack:
if (costume has worn) {
returned. The solution, yet again (this really is a most useful
capability), is more local property variables:
-.. code-block:: inform6
+.. code-block:: inform
Object benny "Benny" cafe
with name 'benny',
coffee_not_paid false, ! is Benny waiting to be paid?
key_not_returned false, ! is Benny waiting for the key?
live [;
- !...
+ ...
-Now we are ready to tackle the ``Give`` action of the ``life`` property,
+Now we are ready to tackle the ``Give`` action of the :prop:`life` property,
which deals with commands like GIVE THE KEY TO BENNY (in a moment, we'll
-come to the ``Give`` action of the ``orders`` property, which deals with
+come to the ``Give`` action of the :prop:`orders` property, which deals with
commands like BENNY, GIVE ME THE KEY):
-.. code-block:: inform6
+.. code-block:: inform
Give:
switch (noun) {
back anytime,~ he says.";
}
-The Give action in the ``life`` property holds the variable ``noun`` as
+The Give action in the :prop:`life` property holds the variable :var:`noun` as
the object offered to the NPC. Remember that we can use the ``switch``
statement as shorthand for:
-.. code-block:: inform6
+.. code-block:: inform
if (noun == costume) { whatever };
if (noun == clothes) { whatever };
- !...
-
-We won't let players give away their clothes or their costume (yes, an
-improbable action, but you never know). The toilet key and the coin are
-successfully transferred. The property ``key_not_returned`` will be set
-to true when we receive the toilet key from Benny (we have not coded
-that bit yet), and now, when we give it back, it's reset to ``false``.
-The ``move`` statement is in charge of the actual transfer of the object
-from the player's inventory to Benny, and we finally display a
-confirmation message. With the coin, we find a new statement:
-``remove``. This extracts the object from the object tree, so that it
-now has no parent. The effect is to make it disappear from the game
-(though you are not destroying the object permanently -- and indeed you
-could return it to the object tree using the ``move`` statement); as far
-as the player is concerned, there isn’t a COIN to be found anywhere. The
-``coffee_not_paid`` property will be set to true when Benny serves us
-the cup of coffee (again, we’ll see that in a moment); now we reset it
-to ``false``, which liberates the player from debt. This culminates with
-the ``"..."`` print-and-return statement, telling the player that the
-action was successful. In passing, remember that in "A homely
-atmosphere" on page 131 we defined the counter such that PUT KEY ON
+ ...
+
+We won't let players give away their clothes or their costume (yes, an
+improbable action, but you never know). The toilet key and the coin are
+successfully transferred. The property ``key_not_returned`` will be set to
+true when we receive the toilet key from Benny (we have not coded that bit
+yet), and now, when we give it back, it's reset to :const:`false`. The ``move``
+statement is in charge of the actual transfer of the object from the
+player's inventory to Benny, and we finally display a confirmation
+message. With the coin, we find a new statement: ``remove``. This extracts
+the object from the object tree, so that it now has no parent. The effect
+is to make it disappear from the game (though you are not destroying the
+object permanently -- and indeed you could return it to the object tree
+using the ``move`` statement); as far as the player is concerned, there
+isn’t a COIN to be found anywhere. The ``coffee_not_paid`` property will be
+set to true when Benny serves us the cup of coffee (again, we’ll see that
+in a moment); now we reset it to :const:`false`, which liberates the player from
+debt. This culminates with the ``"..."`` print-and-return statement,
+telling the player that the action was successful. In passing, remember
+that in :ref:`homely-atmos` we defined the counter such that PUT KEY ON
COUNTER is automatically translated into GIVE KEY TO BENNY .
Why move the key to Benny but remove the coin instead? Once players
supposedly into Benny's greedy pockets. No need to worry about it any
more.
-The benny object needs also an ``orders`` property, just to take care of
+The benny object needs also an :prop:`orders` property, just to take care of
the player's requests for coffee and the key, and to fend off any other
-demands. The ``Give`` action in an ``orders`` property deals with inputs
+demands. The ``Give`` action in an :prop:`orders` property deals with inputs
like ASK BENNY FOR THE KEY or BENNY, GIVE ME THE KEY. The syntax is
-similar to that of the ``life`` property:
+similar to that of the :prop:`life` property:
-.. code-block:: inform6
+.. code-block:: inform
orders [; ! handles ASK BENNY FOR X and BENNY, GIVE ME XXX
Give:
}
],
-* We test the value of ``second`` in order to trap over-generous
+* We test the value of :var:`second` in order to trap over-generous
gestures such as BENNY, GIVE COFFEE TO CUSTOMERS . Then we consider
potential requests.
possessions -- a perverse player could get the key, then drop it
somewhere and ask for it again; if this should happen, we indicate
that Benny is nobody's fool with the message ``"~Last place I saw
- that key..."``. Once all these fitting conditions are ``true``,
+ that key..."``. Once all these fitting conditions are :const:`true`,
players will get the key, which means that they have to return it --
- the ``key_not_returned`` property becomes ``true`` -- and we display
+ the ``key_not_returned`` property becomes :const:`true` -- and we display
a suitable message. However, if the player didn't ask for a coffee,
Benny refuses to oblige, mentioning for the first time the menu board
where players will be able to see a picture of a cup of coffee when
* **Coffee:** we check whether players have already asked for a coffee,
by testing the ``coffee_asked_for`` property, and refuse to serve
- another one if ``true``. If ``false``, we place the coffee on the
+ another one if :const:`true`. If :const:`false`, we place the coffee on the
counter, and set the properties ``coffee_asked_for`` and
- ``coffee_not_paid`` to ``true``. The message bit you know about.
+ ``coffee_not_paid`` to :const:`true`. The message bit you know about.
* **Food:** we'll provide an object to deal with all of the delicious
comestibles to be found in the café, specifically those (such as
We must revisit the café room object:
-.. code-block:: inform6
+.. code-block:: inform
Room cafe "Inside Benny's cafe"
with description
``player.description`` variable, but opted to use the
``LibraryMessages`` object instead. This is a similar case. The code
causing Benny to intercept the forgetful player could have been added,
-perhaps, to a ``daemon`` property in Benny’s definition. However, since
+perhaps, to a :prop:`daemon` property in Benny’s definition. However, since
the action to be intercepted is always the same one and happens to be a
movement action when the player tries to leave the café room, it is also
possible to code it by trapping the ``Go`` action of the room object.
Both would have been right, but this is somewhat simpler.
-We have added a ``before`` property to the room object (albeit a longish
+We have added a :prop:`before` property to the room object (albeit a longish
one), just dealing with the ``Go`` action. As we mentioned in an earlier
chapter, this technique lets you trap the player who is about to exit a
room before the movement actually takes place, a good moment to
interfere if we want to prevent escape. The first line:
-.. code-block:: inform6
+.. code-block:: inform
if (noun ~= s_obj) return false;
The first three are covered by the test:
-.. code-block:: inform6
+.. code-block:: inform
if (benny.coffee_not_paid == true || benny.key_not_returned == true) ...
that is, if either the coffee is not paid for *or* if the key is not
-returned. When this condition is ``false``, it means that both
+returned. When this condition is :const:`false`, it means that both
misdemeanours have been avoided and that the player is free to go.
-However, when this condition is ``true``, the hand of Benny falls on the
+However, when this condition is :const:`true`, the hand of Benny falls on the
player's shoulder and then the game displays a different message
according to which fault or faults the player has committed.