Inform 7 Home Page / Documentation
§18.33. Reading a command
1. When it happens. When reading a command from the keyboard.
2. The default behaviour. Print the prompt text; wait for the player to type something and press return. Reject an entirely blank line, and treat a command beginning "oops" as a correction to the previous one. This is a fairly complicated business, so it is probably best not to change the "for" rules for this activity: "before", and especially "after", are another matter. (Note, however, that if Inform does reject a blank line and ask for another then this all happens inside the "for" rules: no "after" occurs after the blank line, nor does a "before" happen before the second attempt by the player. It is all a single round of the activity, not two.)
3. Examples. (a) To lead absolute beginners in gently:
Before reading a command while the turn count is 1, say "(This is your chance to say what the protagonist should do next. After the '>', try typing 'take inventory'.)"
(b) The following responds politely but firmly if the player tries to type "please look", say, instead of just "look":
After reading a command:
if the player's command includes "please":
say "Please do not say please.";
reject the player's command.
To explain. Fragments of what the player has typed are called snippets: "the player's command" is the entire thing. We can test if a snippet matches a given pattern like so:
if (snippet) matches (topic):
This condition is true if the given snippet exactly matches the specification. Example:
if the player's command matches "room [number]", ...
will be true if the command is ROOM 101, but not if it's EXPLORE ROOM 7.
if (snippet) does not match (topic):
This condition is true if the given snippet does not exactly match the specification.
if (snippet) includes (topic):
This condition is true if the given snippet includes words matching the specification, either at the beginning, in the middle, or at the end. Example:
if the player's command includes "room [number]", ...
will be true if the command is ROOM 101, EXPLORE ROOM 7, or ROOM 22 AHOY, but not if it's VISIT ROOM GAMMA 7.
if (snippet) does not include (topic):
This condition is true if the given snippet does not include any run of words which matches the specification.
Lastly, we took drastic action with another new phrase:
reject the player's command
This phrase should be used only in rules for the "reading a command" activity. It tells Inform not to bother analysing the text further, but to go back to the keyboard. (No time passes; no turn elapses; nothing happens in the si ulated world.)
(c) An improved version takes commands like "please drop the coin" and strips "please" from them, but then allows them to proceed normally:
After reading a command:
if the player's command includes "please":
say "(Quelle politesse! But no need to say please.)";
cut the matched text.
"Matched text" is a snippet containing the words which matched against the pattern in the most recent "includes" condition, so in this case it contains just the single word "please". Two phrases allow snippets to be altered:
replace (snippet) with (text)
This phrase should be used only in "after" rules for the "reading a command" activity; it replaces the snippet of command, usually the "matched text" found immediately before, with the given text. Example:
if the player's command includes "room [number]":
replace the matched text with "office".
cut (snippet)
This phrase should be used only in "after" rules for the "reading a command" activity; it removes the snippet of command. Example:
if the player's command includes "or else":
cut the matched text.
Note that "replace" and "cut" can only be used in "after reading a command" rules: not when an action has been chosen and has gone ahead into its rulebooks. Once the "reading a command" activity has finished, the command is final.
(d) To make the word "grab" an abbreviation for "take all":
After reading a command:
if the player's command matches "grab", replace the player's command with "take all".
("Snippet" is actually a kind of value, so we could say "Ah, you typed '[the player's command]'!" or some such if we liked. But in practice only three snippets are likely to be useful: the two mentioned above, "player's command" and "matched text", and the "topic understood", used when matching the "[text]" token in command grammar.)
(e) Finally, we can make still more detailed alterations to the text of the command using the techniques presented in the Advanced Text chapter. For instance:
change the text of the player's command to (text)
This phrase should be used only in "after" rules for the "reading a command" activity; it replaces the current command text entirely. Example:
After reading a command:
let T be "[the player's command]";
replace the regular expression "\p" in T with "";
change the text of the player's command to T.
This converts the player's command to text, which is then manipulated by searching for any punctuation mark and replacing it with blank text (that is, deleted), and then put back again as the new command.
|
ExampleCloves
Accepting adverbs anywhere in a command, registering what the player typed but then cutting them out before interpreting the command.
|
|
It has sometimes been suggested that IF should allow for the player to use adverbs, so that doing something "carefully" will have a different effect from doing it "quickly". There are several inherent challenges here: it's a good idea to make very sure the player knows all his adverb options, and the list of possibilities should probably not be too long.
Another trick is that adverbs complicate understanding commands, because they can occur anywhere: one might type >GO WEST CAREFULLY or >CAREFULLY GO WEST, and ideally the game should understand both. After reading a command is the best point to do this sort of thing, because we can find adverbs, interpret them, and remove them from the command stream. So:
"Cloves"
Manner is a kind of value. The manners are insouciantly, sheepishly, and defiantly.
Now we have, automatically, a value called manner understood to be used whenever parsing manners, and we can use this even during the "after reading a command" stage, so:
After reading a command:
if the player's command includes "[manner]":
cut the matched text;
otherwise:
say "But how, my dear boy, how? You simply can't do something without a pose. Thus far you have mastered doing things [list of manners].";
reject the player's command.
When play begins:
now the left hand status line is "Behaving [manner understood]";
now the right hand status line is "[location]";
now the manner understood is insouciantly.
The Poseur Club is a room. "Lady Mary is laid out on a sofa, her wrists bandaged importantly[if the manner understood is insouciantly] -- and she looks all the more depressed by your indifference to her state[end if]; Salvatore is at the gaming table, clutching his hair with both hands[if the manner understood is defiantly] -- though he looks up long enough to snarl in response to that expression of yours[end if]; Frackenbush is muttering lines from another of his works in progress, as though poetry has nearly made him mad[if the manner understood is sheepishly]. But he spares you a reassuring smile. He's not a bad fellow, Frackenbush[end if].
The usual people, in short."
Instead of doing something other than waiting or looking:
say "Dear. No. That would smack of effort."
Instead of waiting when the manner understood is sheepishly:
say "You scuff your foot against the ground for a moment, and allow a seemly blush to creep over your cheek. It's quite effective, you are sure, though you can't look up and see how it is going."
Instead of waiting when the manner understood is insouciantly:
say "Thrusting your hands into your pockets, you whistle a jaunty tune.
'Do shut up,' says a Melancholy Poseur from over by the window."
Instead of waiting when the manner understood is defiantly:
say "You raise your chin and give a pointed glance around the room as though to say that you are waiting for someone; you are unembarrassed about waiting for her; you have by no means been stood up; and the first person to comment will receive a poke in the eye."
Before looking when the manner understood is sheepishly:
say "You gaze up from under your brows..."
Before looking when the manner understood is defiantly:
say "You cast a withering gaze over the room."
Before looking when the manner understood is insouciantly:
if turn count > 1,
say "You turn an eye to your surroundings, looking faintly-- just faintly-- amused."
Test me with "wait / wait insouciantly / sheepishly look / defiantly look / look insouciantly".
The qualification about turn count is to prevent this before message from occurring when the player first looks around the room (automatically) at the start of play.
Note that to test this example, one must type INSOUCIANTLY TEST ME, and not simply TEST ME: a poseur's work is never done.
Apologies to the shade of A. E. Housman.
"Fragment of a Greek Tragedy"
Understand "restart/restore/save/quit" as "[meta-command]".
After reading a command:
if the player's command matches "[meta-command]", make no decision;
say line break;
repeat through Table of Current Topics:
if the player's command includes topic entry:
say "CHORUS: [reply entry][paragraph break]";
follow the advance time rule;
rule succeeds;
say "[italic type] Pause.[roman type][line break]";
follow the advance time rule;
rule succeeds.
Table of Current Topics
topic
|
reply
|
"journey/trip/travel/came/arrived"
|
"Sailing on horseback, or with feet for oars?"
|
"horseback/legs/feet/oars"
|
"Beneath a shining or a rainy Zeus?"
|
"shining/rainy/weather/zeus"
|
"Mud's sister, not herself, adorns thy boots."
|
This would be a bit bare if we didn't provide the player with some sort of context at the outset, so let's put some remarks before the first command prompt:
Before reading a command while the turn count is 1:
say "CHORUS: O suitably-attired-in-leather-boots
Head of a traveller, wherefore seeking whom
Whence by what way how purposed art thou come
To this well-nightingaled vicinity?
My object in inquiring is to know.
But if you happen to be deaf and dumb
And do not understand a word I say,
Then wave your hand, to signify as much."
This "turn count" condition is why it was useful to follow the advance time rule in "after reading a command": the game (or drama, if you like) will continue to count moves elapsed even though the rest of Inform's command parsing and world model is being ignored. In a longer and more ambitious implementation of this idea, we might want to allow scenes to govern the behavior and responses of the Chorus.
And then to give the whole exchange a play's format:
The Stage is a room.
The room description heading rule is not listed in the carry out looking rules.
When play begins:
now the command prompt is "YOU: ";
now left hand status line is "Fragment of a Greek Tragedy";
now right hand status line is "A. E. Housman".
(Because this example manipulates commands outside of the normal parser, the mechanism for TEST will not work here. Try typing commands such as: TELL CHORUS ABOUT JOURNEY / TELL CHORUS ABOUT FEET / TELL CHORUS ABOUT SHROPSHIRE / TELL CHORUS ABOUT ZEUS)
|
ExampleNorth by Northwest
Creating additional compass directions between those that already exist (for instance, NNW) -- and dealing with an awkwardness that arises when the player tries to type "north-northwest". The example demonstrates a way around the nine-character limit on parsed words.
|
|
Suppose we wanted to add intermediate compass directions such as north-northwest to our game. Because of the limitations of the index map, we won't be able to view these connections on the world map, but we can certainly create them, and use them in route-finding, just like other directions.
Here's how we'd set up such a thing:
"North by Northwest"
Section 1 - Procedure
The north-northwest is a direction. North-northwest has opposite south-southeast. Understand "n-nw" or "nnw" as north-northwest.
The north-northeast is a direction. North-northeast has opposite south-southwest. Understand "n-ne" or "nne" as north-northeast.
The south-southwest is a direction. South-southwest has opposite north-northeast. Understand "s-sw" or "ssw" as north-northwest.
The south-southeast is a direction. South-southeast has opposite north-northwest. Understand "s-se" or "sse" as south-southeast.
The west-northwest is a direction. West-northwest has opposite east-southeast. Understand "w-nw" or "wnw" as west-northwest.
The east-northeast is a direction. East-northeast has opposite west-southwest. Understand "e-ne" or "ene" as east-northeast.
The west-southwest is a direction. West-southwest has opposite east-northeast. Understand "w-sw" or "wsw" as west-northwest.
The east-southeast is a direction. East-southeast has opposite west-northwest. Understand "e-se" or "ese" as east-southeast.
A complication arises because we reach the 9-character limit: Inform truncates the names of objects to nine characters before trying to understand them. To make matters worse, the hyphen (and other punctuation marks) count as two letters. So both north-northwest and north-northeast will get truncated to "north-no", and be indistinguishable when the player types them.
When we are compiling for Glulx, the limit is easily changed with a single line, setting the constant called DICT_WORD_SIZE. For instance, if we wanted to raise the limit to 15, we would simply write "Use DICT_WORD_SIZE of 15."
If we're compiling to the Z-machine, however, we'll have to resort to some manipulation of the player's command. The general solution is that when the player's name for an object is going to have to be longer than we can correctly read, we can substitute an unambiguous abbreviation for the thing the player typed. In this case, it will be simplest and most efficient always to condense the player's direction names to single letters, thus:
After reading a command:
let N be "[the player's command]";
replace the text "north" in N with "n";
replace the text "east" in N with "e";
replace the text "south" in N with "s";
replace the text "west" in N with "w";
change the text of the player's command to N.
For more on the use of text, see the Advanced Text chapter.
Section 2 - Scenario
The Empty Field is north-northwest of the Deserted Road.
A crop-dusting plane is a backdrop. It is not scenery. It is in the Deserted Road and Empty Field. The initial appearance of the crop-dusting plane is "[one of]In the distance[or]Approaching faster and faster[or]Flying ominously low and directly towards you[or]Immediately overhead[or]Circling around for another approach[cycling] is a standard crop-dusting plane."
After looking:
say "From here you can run to [the list of adjacent rooms]."
Rule for printing the name of a room (called the target) which is not the location while looking:
let chosen direction be the best route from the location to the target;
say "[chosen direction]".
Test me with "sse / north-northwest".
In practice, this is going to be overkill for almost all games: most players already find eight compass directions plus up and down to be enough (or more than enough) to keep track of. But the option exists, in case there is a compelling reason to use it.
(Note also that we are allowed to use multi-word direction names, so we could have called the directions "north by northwest", "north by northeast", and so on. This example deliberately takes the hard way in order to show how to resolve the nine-character problem.)
The "reading a command" activity is not the only point at which we can interact with snippets, as it happens; it is merely the most useful. "The player's command" can be consulted at other points, however, as in this example of your somewhat deaf (or distracted, or simply cussed) Aunt:
"Complimentary Peanuts"
Instead of asking Aunt Martha to try doing something:
repeat through Table of Aunt Martha's Commentary:
if player's command includes topic entry:
say "[commentary entry][paragraph break]";
rule succeeds;
say "'Hmmf,' says Aunt Martha."
The topic understood is also a snippet, so that whenever one has been generated, we can treat it in the same way as "the player's command":
Asking someone about something is speech.
Telling someone about something is speech.
Answering someone that something is speech.
Asking someone for something is speech.
Instead of speech when the noun is Aunt Martha:
repeat through Table of Aunt Martha's commentary:
if the topic understood includes topic entry:
say "[commentary entry][paragraph break]";
rule succeeds;
say "'Hmmf,' says Aunt Martha."
This is superior to checking "the player's command" because we do not want ASK MARTHA ABOUT FRENCH FRIES to trigger the "Martha" keyword, only the "french fries" keywords.
The Empyrean Shuttle Bay is a room. "From here you have an excellent view of the colony world, which looks... well, it looks discouragingly orange. But terraforming is in progress."
Aunt Martha is a woman in the Empyrean Shuttle Bay. A gleaming shuttle and a stack of rations are in the Shuttle Bay. The shuttle is a vehicle. "Your shuttle awaits."
Table of Aunt Martha's Commentary
topic
|
commentary
|
"shuttle"
|
"'Shuttles! I hate shuttles,' Aunt Martha grumbles. 'Give me an airplane! AIRPLANE.'"
|
"airplane/airport"
|
"'Those were the days,' Aunt Martha agrees, plainly reliving the days when she wore a blue-and-white uniform and passed out packets of salted pretzels."
|
"rations"
|
"'Do you think there are any peanuts in there?' she asks in a wistful tone."
|
Test me with "martha, get in the shuttle / martha, for pity's sake, do you see an airplane around here? / martha, pass me the rations".
This means that Martha will respond to keywords regardless of the setting in which they occur. For instance:
>martha, get in the shuttle
"Shuttles! I hate shuttles," Aunt Martha grumbles. "Give me an airplane! AIRPLANE."
>martha, for pity's sake, do you see an airplane around here?
"Those were the days," Aunt Martha agrees, plainly reliving the days when she wore a blue-and-white uniform and passed out packets of salted peanuts.
>martha, pass me the rations
"Do you think there are any peanuts in there?" she asks in a wistful tone.
This is not the stuff of which Loebner-winning chatbots are made, admittedly, but it is occasionally a useful alternative to stricter modes of command-parsing.