Menus by Emily Short

I’m having some issues using Emily Short’s “Menus” extension. Let me explain.

In my game there is a car, and there are four possible destinations the car can drive to. When the player enters the car, I have a menu appear asking which of the four destinations they would like to drive to.
When they select the entry, I have a rule fire which moves the car and player to the desired location. That part works just fine. The part I can’t figure out is: how do I then close the menu and return to gameplay?
I know it’s going to be a simple “quit the menu;” answer, I just can’t find it anywhere in the documentation/source code.
Right now the player has to manually quit the menu to see that anything has happened.

On a side note, how do I change the title from “Instructions” to “Destination?” on the menu screen?
I’m also using the Basic Help Menu extension.

I don’t know anything about programming, but I can give you some hints on commands.

Get out of car
You must first park your car.
Park car
Which car do yo want to park, the red car or the yellow car?
Park yellow car
The yellow car is now parked.

The menu should turn off at this point.

The best way to get the hang of the "Menus" extension is to open the extension itself and skim through the code; the first few times I tried to make frequent use of "Menus" this exercise helped me quickly understand how it all works.

I don't have either Inform 7 or the "Menus" extension to look at right now (since the extension comes with Inform, apparently one can't also view/download its text at the I7 website).  Normally I'd be more reluctant to answer your question without being able to check the particulars of syntax and so forth, but I was idly browsing the forum for a bit and noticed your question had received no response during the time of my visit; in other words, you'll have to carefully double-check my advice.

In response to your trouble with exiting the “menu screen,” the directive you’ll want to include in your rules is something quite like:

decrease the depth of the current-menu by 1

For the particular phrasing, you may want to open the extension (and its companion, “Basic Screen Effects”) to have a look.

One further thing to keep in mind about using the “Menus” extension is that by default (in other words, unless you write some rules to the contrary), a player can exit any menu screen by pressing the “Q” key. This could be a problem if the proper functioning of your game depends on you (as author) controlling the Menu screen (to see that such-and-such is carried out, etc). The best thing to do might be to intercede by unlisting the rule in the extension that governs navigating the menu depth and replacing this with your own version; unfortunately I can’t recall the name of the particular rule from memory, but as I mentioned if you look through the extension’s code you should see it without much searching.

Changing the name of the menu, or other text that appears above the options while the menu is displayed, is actually just a matter of changing the status line. Somewhere in “Menus” there are two rules that refer to something quite like “Deep Menu Status” and “Shallow Menu Status.” You ought instead write your own rules for displaying the status bar (easiest if you use the “Basic Screen Effects” extension in conjunction with “Menus”), which will supercede these “Deep/Shallow Status” thingies. In the same way, you could also override the status line info while making use of the default menus from the “Basic Help Menu” extension.

I would suggest overall you consider a very simple “driving” scene as a way to automate the machinery of constructing, displaying, effecting, and clearing your menus. Notionally, this might look like:

Using-carstuff is a truth state that varies.  Using-carstuff is usually false.

Carstuff is a recurring scene.  Carstuff begins when using-carstuff is true.  Carstuff ends when using-carstuff is false.

When carstuff begins:
	[initialize and display the menu]

Every turn during carstuff:
[construct the status line per your own table rather than the Deep/Shallow tables]
[carry out the displaying activity with the current menu-- in other words, if the player pressed "Q" to quit your menu, you disregard this and bring the menu right back up again]

When carstuff ends:
	[get rid of the menu, i.e. "decrease the menu depth"]

Sorry I can’t be more forthcoming with particulars, but as I said I don’t have Inform with me at the moment to check on details. If I haven’t answered your questions, or if you have more questions, I’m sure others will be glad to fill in some of the details.

This is not really the question you’re asking, but: I would strongly advise against this use of Menus. It’s not what the extension was intended for – namely to provide some out-of-game data and allow the player to browse through it at his leisure – and therefore it’s not really designed to be easy to close the menu out without the player’s involvement. But more than that, in my opinion this will provide a bad player experience: it will remove the scrollback so that the player can’t see what has just been happening before driving the car (which people tend to dislike, especially if it happens frequently or unpredictably) and it forces an unnecessary break in the command-line rhythm of a game.

If what you want is to offer the player a set of enumerated choices without disrupting the whole screen display pattern, there are other ways to do that that don’t feel quite so jumpy.

Yeah, the menu thing is kind of jarring and would probably ruin the game’s flow. Think simpler; try simply asking the player which destination they want? I think 9:05 did something similar but it’s been ages since I’ve played that.

As I was reading through other posts on related topics, I found that many people suggested using something like one of the conversation-modifying extensions and using conversation nodes to accomplish this.
I’ll have to look into using something like that.

Emily, your comments on scrollback are a very good point.
Thanks everyone for your advice, this is what makes writing IF so rewarding - the community support is fantastic.

Joel, I wrote a very short and easy to use bit of code that creates in-game menus (of up to 9 options) which can be responded to with one keypress. I wrote it because I found most of the question/conversation extensions that are out there already are more powerful and/or more confusing to use than what I needed. So it sounds like it might interest you. I was thinking of releasing it as an extension myself.

Read my 1st post on the following topic page. It has the code and an explanation of how to use it:

[url]https://intfiction.org/t/easier-name-gender-selection/2270/1]

Isn’t this the sort of thing that the Questions extension was written for?

This is perfect - it’s exactly what I need.
Thank you severedhand!

I’ve found that “Menus” alone can provide a very versatile and robust technique for all sorts of interactivity, even if such wasn’t emshort’s purpose when she wrote the extension. “Menus” can also, under some circumstances, facilitate a fast-paced and quite entertaining offering of play.

Joel Webster sounds satisfied with the replies he’s received, which is groovy since that’s our objective here. Nonetheless, as I felt my response yesterday was far too short on particulars since I had no reference materials handy, I dug out an Inform story file I wrote some time ago that demonstrates how, using only “Menus,” to resolve each and every issue Joel initially raised in his questions. If the discussion here is already resolved to the OP’s satisfaction then consider the posting of (a surfeit of) code below as a mere appendix, germane because it directly addresses several points on how to use and modify the “Menus” extension.

Certainly, as emshort and others mentioned, one drawback of using “Menus” is that some interpreters may clear their text-record buffer each time the screen is cleared (which occurs every turn a menu is displayed using “Menus”), leading to player frustration. For example, when using Gargoyle one loses the continuous stream of text availabe by pressing “page-up” after a menu is displayed. However, not all interpreters suffer such difficulties; I (exclusively) prefer Windows Frotz and Windows Glulxe for playing any game written with Inform 6 or Inform 7, and the “scrollback” function of these two interpreters is unaffected by screen-clearings. I think the point then would be that this is something an author ought keep in mind while preparing a game for distribution to others, and might perhaps lead an author to either release a game along with an amenable interpreter or plainly recommend one program over another to potential players.

Though far more lengthy than the usual example in a forum discussion, the code below had the virtue of being already written; copy/pasting is far easier than writing something novel. Among other things, it shows how to carefully construct/display/dispense with menus as well as how to construct various status bars for use with menus, when to use subtleties like “rule succeeds” and “current menu is,” and also moves both the player and other characters about according to rules effected with menu-usage. In other words, this example seemed to me so relevant to everything that Joel mentioned in his first post that I thought it a shame to let it gather dust on my hard drive rather than record it here. The example also makes a more complex use of I7’s Scene machinery than we often see publicly posted; since questions about scene-usage come up from time to time, perhaps what follows can serve as a reference on that count as well.

(As the example is quite lengthy at ~1800 words, I’ve tucked it into a a spoiler tag:)

[spoiler][code]
[Preface:

What follows is only the barest outline of but one aspect of a simple rpg-style game featuring heavily randomized combat, which uses a menu-driven interactive system for resolving encounters. Among other things, the example below lacks any implementation at all of one of the more fundamental ideas which led me to write this code in the first place: namely, instead of having numerous actors clogging up the off-stage area (and hence our memory allocation), I wanted to use but a single placeholder or generic enemy; at the start of each encounter, this generic enemy (“Met”) would then be temporarily redefined (printed name, character statistics, etc) by reference to a grand Table of Monsters where such data would be stored for all the various types of opponents one might encounter.

I ought add that the broader notion of such a menu-driven system is hardly novel, as I’ve seen other IF games that use something similar as their basis of interaction-- though as far as I know none use Inform 7’s Scene machinery as a fundamental game mechanic.

Also note that, due to forum typography restrictions, copying/pasting the code below into an Inform story file may be rather tedious as all tab stops in both rules and tables will be converted to spaces; these spaces will have to be deleted and replaced with tabs one by one.]

Volume 0 - Preliminary Notions

Include Menus by Emily Short.

[The following modification of “Menus” is required to counter the player quitting our menu system (by pressing “Q”) during encounters, leaving the game in a very wretched state indeed]

The basic menu contents rule is not listed in any rulebook.

Rule for displaying (this is the alternate menu contents rule):
now the current menu selection is 1;
show alt-menu contents.

To show alt-menu contents:
increase the menu depth by 1;
let temporary depth be the menu depth;
let temporary menu be the current menu;
let temporary title be the current menu title;
let __x be 0;
let __index be 0;
while __index is not 1:
now the current menu is the temporary menu;
let __n be 0;
repeat through current menu:
increase __n by 1;
if title entry is current menu title, now current menu selection is __n;
now the current menu title is the temporary title;
reprint current menu;
let __x be the chosen letter;
if __x is a number listed in the Table of Menu Commands:
unless encounter is happening:
consider the effect entry;
if temporary depth > menu depth:
now __index is 1;
otherwise:
if __x is -8 or __x is 81 or __x is 113 or __x is 27:
if temporary depth > menu depth:
now __index is 1;
otherwise:
consider the effect entry;
if temporary depth > menu depth:
now __index is 1.

[Some other initialization stuff]

The return-spot is a room that varies. The return-spot is usually starthere.

The current-foe is a person that varies. The current-foe is usually Avatar.

Volume P - People

[In a more fully-developed example, these “character statistics” would likely be uniquely assigned by table entries or else derived by formula from “basic attributes” like strength, dexterity, etc]

A person has a number called hit-points. The hit-points of a person are usually 25.

A person has a number called damage. The damage of a person is usually 5.

A person has a number called hit-chance. The hit-chance of a person is usually 67.

Volume S - Scenes

Part 1 - Random Encounters

Chapter 1 - Begin the Random Encounter

Section 1 - Definition of the Encounter Scene

Start-encounter is a truth state that varies. Start-encounter is usually false.
Encounter-resolved is a truth state that varies. Encounter-resolved is usually false.

Encounter is a recurring scene. Encounter begins when start-encounter is true. Encounter ends when encounter-resolved is true.

Section 2 - Starting the Encounter Scene

[In a more fully-developed example, “When encounter begins” is the point where we would refer to an enemies table and turn generic “Met” into Hilgar the Orc, Olaf the Cyborg Terminator, etc]

When encounter begins:
now return-spot is the location of the player;
now start-encounter is false;
move met to the arena;
now the hit-points of Met is 25;
now met is alive;
move the player to the arena;
now resolve-initial-interaction is false.

[temp]
When encounter begins:
now the current-foe is Met.

Section 3 - Concluding the Encounter Scene

When encounter ends:
move the player to return-spot;
remove met from play;
now encounter-resolved is false.

[temp]
When encounter ends:
now the current-foe is Avatar.

Chapter 2 - Initial Phase of the Encounter

Section 1 - Defining the Initial Phase

Resolve-initial-interaction is a truth state that varies. Resolve-initial-interaction is usually true.

Initial-reaction is a recurring scene. Initial-reaction begins when resolve-initial-interaction is false. Initial-reaction ends when resolve-initial-interaction is true.

Section 2 - Refining the Initial Phase

Initial-reaction has a text called initial-outcome. The initial-outcome of initial-reaction is usually “”.

[I ardently wished to use a KOV here with adverbial iterations, but apparently while a KOV can be specified as applying to ALL scenes, individual scenes may not have their own discrete value assignments; hence the confusing number-system.]

Initial-reaction has a number called initial-reaction-endstate. The initial-reaction-endstate of initial-reaction is usually 0. [1=fight, 2=chat, 3=flee, 4=bribe]

Initial-reaction ends angrily when the initial-reaction-endstate of initial-reaction is 1.
Initial-reaction ends chattily when the initial-reaction-endstate of initial-reaction is 2.
Initial-reaction ends furtively when the initial-reaction-endstate of initial-reaction is 3.
Initial-reaction ends expensively when the initial-reaction-endstate of initial-reaction is 4.

Rule for constructing the status line while initial-reaction is happening:
fill status bar with Table of Initial-Phase Status;
rule succeeds.

Table of Initial-Phase Status
left central right
“” “Shall you:” “”
“” “” “”
" Up/Down arrow = Navigate" “” “ENTER = Select”

Section 3 - Commencing the Initial Phase

When initial-reaction begins:
determine outcome of initial-reaction.

To determine outcome of initial-reaction:
now the current menu is the Table of Encounter-Starting Options;
carry out the displaying activity.

Table of Encounter-Starting Options
title subtable description toggle
“Fight” – -- InitiateCombat rule
“Chat” – -- InitiateEncounterChat rule
“Flee” – -- InitiateFleeing rule
“Bribe” – -- InitiateOffering rule

Section 4 - Concluding the Initial Phase

When initial-reaction ends angrily:
say “[initial-outcome of initial-reaction]”;
say paragraph break;
now resolve-initial-interaction is true;
now the initial-outcome of initial-reaction is “”;
now the initial-reaction-endstate of initial-reaction is 0;
now in-combat is true.

[The next several rules would of course change into intermediate steps rather than conclusions if we implemented a more substantial consequence of choosing them]

When initial-reaction ends chattily:
say “[initial-outcome of initial-reaction]”;
say paragraph break;
now resolve-initial-interaction is true;
now the initial-outcome of initial-reaction is “”;
now the initial-reaction-endstate of initial-reaction is 0;
now encounter-resolved is true.

When initial-reaction ends furtively:
say “[initial-outcome of initial-reaction]”;
say paragraph break;
now resolve-initial-interaction is true;
now the initial-outcome of initial-reaction is “”;
now the initial-reaction-endstate of initial-reaction is 0;
now encounter-resolved is true.

When initial-reaction ends expensively:
say “[initial-outcome of initial-reaction]”;
say paragraph break;
now resolve-initial-interaction is true;
now the initial-outcome of initial-reaction is “”;
now the initial-reaction-endstate of initial-reaction is 0;
now encounter-resolved is true.

Section 5 - Combat may be an outcome of the Initial Phase

This is the InitiateCombat rule:
decrease the menu depth by 1;
now the initial-outcome of initial-reaction is “There shall be blood! You decide to fight [printed name of the current-foe].”;
now the initial-reaction-endstate of initial-reaction is 1;
rule succeeds.

Section 6 - Talking may be an outcome of the Initial Phase

This is the InitiateEncounterChat rule:
decrease the menu depth by 1;
now the initial-outcome of initial-reaction is “Feeling rather sociable, you decide to chat up [printed name of the current-foe].”;
now the initial-reaction-endstate of initial-reaction is 2;
rule succeeds.

Section 7 - Evasion may be an outcome of the Initial Phase

This is the InitiateFleeing rule:
decrease the menu depth by 1;
now the initial-outcome of initial-reaction is “Feeling apprehensive, you attempt to evade the attention of [printed name of the current-foe].”;
now the initial-reaction-endstate of initial-reaction is 3;
rule succeeds.

Section 8 - Bribery may be an outcome of the Initial Phase

This is the InitiateOffering rule:
decrease the menu depth by 1;
now the initial-outcome of initial-reaction is “You hope that [printed name of current-foe] may be satisfied with a bribe and allow you to be on about your business.”;
now the initial-reaction-endstate of initial-reaction is 4;
rule succeeds.

Chapter 3 - Combat Phase of the Encounter

Section 1 - Defining the Scene of Combat

In-combat is a truth state that varies. In-combat is usually false.

Combat is a recurring scene. Combat begins when in-combat is true. Combat ends when in-combat is false.

Section 2 - Effecting Combat

When combat begins:
initialize fighting.

To initialize fighting:
now the current menu is the Table of Tactical Options;
carry out the displaying activity;
clear the screen.

Every turn during combat:
initialize fighting.

[temp]
When combat ends:
now encounter-resolved is true.

Rule for constructing the status line while combat is happening:
fill status bar with Table of Combat Menu Status;
rule succeeds.

Table of Combat Menu Status
left central right
“” “Fight it out!” “”
" Your HP: [hit-points of player]" “” “[printed name of the current-foe][’]s HP: [hit-points of current-foe] "
“” “” “”
" Up/Down arrow = Navigate” “” “ENTER = Select”

Table of Tactical Options
title subtable description toggle
“Attack” – -- ResolveAttacks rule
“Use Item” – -- ItemUseInCombat rule
“Flee” – -- FleeCombat rule
“Surrender” – -- HopeForMercy rule

Section 3 - Resolving Combat

This is the ResolveAttacks rule:
say paragraph break;
say “Fisticuffs ensue!”;
let firststrike be a random number between 1 and 2;
let pcstrike be a random number between 1 and 100;
let metstrike be a random number between 1 and 100;
if firststrike is 1:
say “You obtain the initiative!”;
if the hit-chance of the player is greater than pcstrike or the hit-chance of the player is pcstrike:
say “You hit [printed name of the current-foe] for [damage of the player]!”;
decrease the hit-points of Met by damage of the player;
update salubrity for met;
if met is dead:
say “You mercilessly slay [printed name of the current-foe]!”;
now in-combat is false;
wait for any key;
decrease the menu depth by 1;
rule fails;
if the hit-chance of the player is less than pcstrike:
say “You swing at [printed name of the current-foe], but he dodges your blow.”;
if the hit-chance of met is greater than metstrike or the hit-chance of met is metstrike:
say “[Printed name of the current-foe] hits you for [damage of met]!”;
decrease the hit-points of the player by damage of met;
update salubrity for the player;
if the player is dead:
decrease the menu depth by 1;
rule fails;
if the hit-chance of met is less than metstrike:
say “[Printed name of the current-foe] swings at you, but he misses.”;
if firststrike is 2:
say “[Printed name of the current-foe] obtains the initiative!”;
if the hit-chance of met is greater than metstrike or the hit-chance of met is metstrike:
say “[Printed name of the current-foe] hits you for [damage of met]!”;
decrease the hit-points of the player by damage of met;
update salubrity for the player;
if the player is dead:
decrease the menu depth by 1;
rule fails;
if the hit-chance of met is less than metstrike:
say “[Printed name of the current-foe] swings at you, but he misses.”;
if the hit-chance of the player is greater than pcstrike or the hit-chance of the player is pcstrike:
say “You hit [printed name of the current-foe] for [damage of the player]!”;
decrease the hit-points of Met by damage of the player;
update salubrity for met;
if met is dead:
say “You mercilessly slay [printed name of the current-foe]!”;
now in-combat is false;
wait for any key;
decrease the menu depth by 1;
rule fails;
if the hit-chance of the player is less than pcstrike:
say “You swing at [printed name of the current-foe], but he dodges your blow.”;
wait for any key;
rule succeeds.

A person can be dead or alive. [In a more well-developed example, this would have non-trivial consequences]

To update salubrity for (theyem - a person):
if the hit-points of theyem is less than 1:
now theyem is dead;
if theyem is the player:
end the story saying “[printed name of current-foe] mercilessly slays you.”

Chapter 4 - Rainy Day Notions

[in a more well-developed and interesting example, the following options would of course lead to something much more substantial than a mere line of printed text:]

This is the ItemUseInCombat rule:
say paragraph break;
say “Whereby we rummage through our loot for something useful in the present circumstance.”;
wait for any key;
rule succeeds.

This is the FleeCombat rule:
say paragraph break;
say “Whereby we attempt to escape under fire from the enemy.”;
wait for any key;
rule succeeds.

This is the HopeForMercy rule:
say paragraph break;
say “Perhaps the enemy will take pity on our ineptitude.”;
wait for any key;
rule succeeds.

Volume W - World

The Starthere is a room. “Go west for encounter testing.”.

A person called Avatar is in starthere. The player is Avatar.

The Conduit is west of starthere. The description of the conduit is “We ought not reach this enigmatic place.”.

Instead of going west from starthere:
if a random chance of 1 in 2 succeeds:
now start-encounter is true;
otherwise:
say “You explore a bit, but don’t find anything interesting.”

The Arena is a room.

There is a person called Met.
[/code][/spoiler]

I hope anyone trying to use “Menus” in the future will find the above example answers far more questions than it poses.

Endosphere