11. Captain Fate: take 2¶
U was a usurer, a miserable elf;V was a vintner, who drank all himself.

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.
Cultural 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:
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:
--- T Y P E ---
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.
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, 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):
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.
--- T Y P E ---
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):
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:
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.
if (random(2) == 1) ...
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:
--- T Y P E ---
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:
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:
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:
--- T Y P E ---
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:
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:
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
:
--- T Y P E ---
Object toilet_door
with name 'red' 'toilet' 'door'
short_name [;
if (location == cafe) print "door to the toilet";
else print "door to the cafe";
return true;
],
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, 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:
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:
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:
--- T Y P E ---
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 theUnlock
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 theUnlock
action also takes care of opening the door). Finally, wereturn 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 thenreturn false
to let theLock
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 wereturn 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, returningtrue
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:
[ 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:
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:
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:
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:
--- T Y P E ---
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.
--- T Y P E ---
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.
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) 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 in The south side of the square had
this all-exclusive before
property:
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:
--- T Y P E ---
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.