Now and then in IF there is a situation where we need to ask the player for a numbered choice rather than an ordinary action command. What's more, that numbered choice might change during the game, so we don't want to just hard-wire the meanings of "1", "2", and "3" whenever the player types them.
A better trick is to keep a list or table (we'll use a table here because it involves slightly less overhead) recording what the player's numerical choices currently mean. Then every time the player selects a number, the table is consulted, and if the number corresponds to something, the player's choice is acted on.
In our example, we'll have a transporter pad that can take the player to any room in the game that he's already visited. (Just for the sake of example, we'll start him off with a few pre-visited rooms.)
"Down in Oodville"
Section 1 - Method
Understand "[number]" as selecting.
Selecting is an action applying to one number.
Check selecting: [assuming we don't want to be able to transport from just anywhere]
if the player is not on the transporter pad:
say "You can transport only from the transporter pad. From other places than the transporter room, you can HOME to your base ship, but not leap sideways to other locations.";
empty the transport options instead.
Check selecting:
if the number understood is greater than the number of filled rows in the Table of Transport Options or the number understood is less than one:
say "[The number understood] is not a valid option. ";
list the transport options instead.
Carry out selecting:
let N be the number understood; [not actually a necessary step, but it makes the next line easier to understand]
choose row N in the Table of Transport Options;
if the transport entry is a room:
move the player to the transport entry;
otherwise:
say "*** BUG: Improperly filled table of transport options ***" [It should not be possible for this to occur, but we add an error message for it so that, if it ever does, we will know what is causing the programming error in our code]
To list the transport options:
let N be 1;
say "From here you could choose to go to: [line break]";
repeat through the Table of Transport Options:
say " [N]: [transport entry][line break]";
increment N.
To empty the transport options:
repeat through the Table of Transport Options:
blank out the whole row; [first we empty the table]
To load the transport options:
repeat with interesting room running through visited rooms which are not the Transporter Room:
choose a blank row in the Table of Transport Options;
now the transport entry is the interesting room.
Table of Transport Options
transport
an object
with 3 blank rows. [In the current scenario, the number of blank rows need never be greater than the number of rooms in the game, minus the transport room itself.]
Understand "home" as homing. Homing is an action applying to nothing.
Check homing:
if the player is in the Transporter Room:
say "You're already here!" instead.
Carry out homing:
move the player to the transporter room.
Section 2 - Scenario
The Transporter Room is a room.
Oodville is a visited room.
Midnight is a visited room. The Diamond City is west of Midnight.
The transporter pad is an enterable supporter in the Transporter Room. "The transporter pad in the middle of the floor is currently dull blue: powered but unoccupied."
After entering the transporter pad:
say "The transporter beeps and glows amber as you step onto its surface. A moment later a hologram displays your options. [run paragraph on]";
empty the transport options;
load the transport options;
list the transport options.
Test me with "get on pad / 0 / -1 / 8 / 2 / look / w / home / get on pad / get off pad / 3".
If we wanted to replace the regular command structure entirely with numbered menus, or use menus to hold conversation options, we could: several Inform extensions provide these functions.
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)