§20.7. Making new text with text substitutions

Substitutions are most often used just for printing, like so:

say "The clock reads [time of day].";

But they can also produce text which can be stored up or used in other ways. For example, defining

To decide what text is (T - text) doubled:
    decide on "[T][T]".

makes

let the Gerard Kenny reference be "NewYork" doubled;

set this temporary variable to "NewYorkNewYork".

There is, however, a subtlety here. A text with a substitution in it, like:

"The clock reads [time of day]."

is always waiting to be substituted, that is, to become something like:

"The clock reads 11:12 AM."

If all we do with text is to print it, there's nothing to worry about. But if we're storing it up, especially for multiple turns, there are ambiguities. For example, suppose we're changing the look of the black status line bar at the top of the text window:

now the left hand status line is "[time of day]";

Just copying "[time of day]" to the "left hand status line" variable doesn't make it substitute - which is just as well, or the top of the screen would perpetually show "9:00 AM".

On the other hand, looking back at the phrase example:

To decide what text is (T - text) doubled:
    decide on "[T][T]".

"[T][T]" is substituted immediately it's formed. That's also a good thing, because "T" loses its meaning the moment the phrase finishes, which would make "[T][T]" meaningless anywhere else.

What's going on here is this: Inform substitutes text immediately if it contains references to a temporary value such as "T", and otherwise only if it needs to access the contents. This is why "[time of day]" isn't substituted until we need to print it out (or, say, access the third character): "time of day" is a value which always exists, not a temporary one.

Using the adjectives "substituted" and "unsubstituted", it's always possible to test whether a given text is in either state, should this ever be useful. For example,

now the left hand status line is "[time of day]";
if the left hand status line is unsubstituted, say "Yes!";

will say "Yes!": the LHSL is like a bomb waiting to go off. Speaking of which:

The player is holding a temporal bomb.

When play begins:
    now the left hand status line is "Clock reads: [time of day]".

After dropping the temporal bomb:
    now the left hand status line is the substituted form of the left hand status line;
    say "Time itself is now broken. Well done."

This is making use of:

substituted form of (text) ... text

This takes a text and makes substitution occur immediately. For example,

substituted form of "time of death, [time of day]"

produces something like "time of death, 9:15 AM" rather than "time of death, [time of day]". It's entirely legal to apply this to text which never had any substitutions in, so

substituted form of "balloon"

produces "balloon".

Note that there's no analogous phrase for "unsubstituted form of...", because once text has substituted, there's no way to go back.


arrow-up.pngStart of Chapter 20: Advanced Text
arrow-left.pngBack to §20.6. Regular expression matching
arrow-right.pngOnward to §20.8. Replacements

*ExampleMirror, Mirror
The sorcerer's mirror can, when held up high, form an impression of its surroundings which it then preserves.

*ExampleIdentity Theft
Allowing the player to enter a name to be used for the player character during the game.

Here we create a class of matches that can be used to burn other objects. Our objectives are as follow:

Burned objects other than matches should be removed from play instantly (just as edible objects are instantly eaten). We could give everything its own burning duration, but that complicates matters and allows for fire to spread from one object to another; for an example of how to do that, see the example "In Fire or in Flood".

Matches should be described to show whether they are burning or extinguished, and when the parser chooses one of several identical matches, it should make very clear which match it has selected.

The game must sensibly select and, if necessary, automatically light new matches to carry out a >BURN THING command.

The matches must burn for a set number of turns before going out, never to be used again.

And finally, the part for which the text will be useful: when several matches go out in the same turn, we want the game to print

Four matches go out.

rather than

A match goes out.
A match goes out.
A match goes out.
A match goes out.

This last function appears down in Section 3, if we wish to skip ahead and look at it.

paste.png "The Cow Exonerated"

Section 1 - Simple Burning

Understand the commands "light" and "burn" as something new.

Understand "burn [something] with [strikable-match]" as burning it with. Understand "burn [something] with [something preferably held]" as burning it with. Burning it with is an action applying to one thing and one carried thing.

Understand the command "light" as "burn".

A thing can be flammable or impervious. A thing is usually impervious.

Check burning something with something (this is the burn only with flaming matches rule):
    if the second noun is not a strikable-match, say "You can only light things with matches." instead;
    if the second noun is not flaming, say "[The second noun] needs to be burning first." instead.

Check burning something with something (this is the burn only flammable things rule):
    if the noun is impervious, say "[The noun] cannot be burned." instead.

Check burning something with something (this is the burn only things not held rule):
    say "[one of]It occurs to you to set down [the noun] before burning, just for safety's sake. [or]Again, you decide to put down [the noun] prior to burning. [or]You try setting down [the noun] as usual. [stopping][run paragraph on]";
    silently try the player dropping the noun;
    if the player encloses the noun, stop the action.

Carry out burning something with something (this is the simplistic burning rule):
    now the noun is nowhere.

Report burning something with something:
    say "You burn up [the noun]."

Rule for implicitly taking the second noun while burning something with something which is not a strikable-match:
    say "You can only light things with matches.";
    stop the action.

Section 2 - Matches

The word "matches" is used by Inform to compare snippets of text (see "Reading a command" in the Activities chapter). This can sometimes cause awkwardness if we also have a kind called "match", so for the occasion we will give our matches a more specialized name, never visible to the player:

A strikable-match is a kind of thing. The plural of strikable-match is s-matches.

A strikable-match has a number called duration. The duration of a strikable-match is usually 3.

Rule for printing the name of a strikable-match: say "match".
Rule for printing the plural name of a strikable-match: say "matches".

Understand "match" as a strikable-match. Understand "matches" as a strikable-match.

Flame-state is a kind of value. The flame-states are burnt, flaming, and new. Understand "burning" or "lit" as flaming. Understand "unused" as new.

A strikable-match has a flame-state. A strikable-match is usually new. Understand the flame-state property as describing a strikable-match.

Before printing the name of a strikable-match while asking which do you mean:
    say "[flame-state] ".

Before printing the name of a strikable-match while taking inventory:
    say "[flame-state] ".
Before printing the plural name of a strikable-match while taking inventory:
    say "[flame-state] ".

Before printing the name of a strikable-match while clarifying the parser's choice of something:
    if not taking inventory, say "[flame-state] ".

After printing the name of a strikable-match (called special-target) while clarifying the parser's choice of something:
    if the player carries the special-target:
        say " you're carrying";
    otherwise if the special-target is in the location:
        say " on the ground";
    otherwise:
        say " [if the holder of the special-target is a container]in[otherwise]on[end if] [the holder of the special-target]".

Understand "strike [something]" as attacking.

Understand "strike [strikable-match]" as striking. Striking is an action applying to one carried thing.

Understand "burn [strikable-match]" as striking.

Does the player mean striking a new strikable-match:
    it is very likely.

Does the player mean striking a burnt strikable-match:
    it is unlikely.

Check striking a strikable-match (this is the strike only new matches rule):
    if the noun is burnt, say "[The noun] has already burnt down and cannot be relit." instead;
    if the noun is flaming, say "[The noun] is already burning." instead.

Carry out striking a strikable-match (this is the standard striking rule):
    now the noun is flaming;
    now the noun is lit.

Report striking a strikable-match (this is the standard report striking rule):
    say "You light [the noun]."

Before burning something with a new strikable-match (this is the prior lighting rule):
    say "(first [if the player does not carry the second noun]taking and [end if]lighting [the second noun])[command clarification break]";
    silently try striking the second noun;
    if the second noun is not flaming, stop the action.

Rule for implicitly taking a strikable-match (called target) while striking:
    try silently taking the target.

Does the player mean burning something with a flaming strikable-match:
    it is very likely.

Does the player mean burning something with a new strikable-match:
    it is likely.

Does the player mean burning something with a burnt strikable-match:
    it is unlikely.

Instead of burning a burnt strikable-match with something:
    say "[The noun] is completely consumed and cannot be relit."

Section 3 - Putting the Matches Out

Every turn:
    let N be 0; [here we track how many matches are being put out during this turn, so that we don't have to mention each match individually if several go out during the same move]
    repeat with item running through flaming s-matches:
        decrement the duration of the item;
        if the duration of the item is 0:
            now the item is burnt;
            now the item is unlit;
            if the item is visible, increment N;
    if N is 1:
        say "[if the number of visible flaming s-matches is greater than 0]One of the matches [otherwise if the number of burnt visible s-matches is greater than 1]Your last burning match [otherwise]The match [end if]goes out.";
    otherwise if N is greater than 1:
        let enumeration be "[N in words]";
        if N is the number of visible s-matches:
            if N is two, say "Both";
            otherwise say "All [enumeration]";
        otherwise:
            say "[enumeration in title case]";
        say " matches go out[if a visible strikable-match is flaming], leaving [number of visible flaming s-matches in words] still lit[end if]."

Section 4 - Scenario

Old Chicago is a room.

The player carries a flammable thing called a log. Understand "wooden" and "wood" as the log.

The player carries two s-matches. The matchbox is an open openable container. It contains five s-matches. The player carries the matchbox.

When play begins:
    now every strikable-match carried by the player is flaming;
    now every strikable-match carried by the player is lit.

Test me with "i / burn match / i / i / burn log with match / burn matchbox with match / i".

**ExampleThe Cow Exonerated
Creating a class of matches that burn for a time and then go out, with elegant reporting when several matches go out at once.

Here we create a class of matches that can be used to burn other objects. Our objectives are as follow:

Burned objects other than matches should be removed from play instantly (just as edible objects are instantly eaten). We could give everything its own burning duration, but that complicates matters and allows for fire to spread from one object to another; for an example of how to do that, see the example "In Fire or in Flood".

Matches should be described to show whether they are burning or extinguished, and when the parser chooses one of several identical matches, it should make very clear which match it has selected.

The game must sensibly select and, if necessary, automatically light new matches to carry out a >BURN THING command.

The matches must burn for a set number of turns before going out, never to be used again.

And finally, the part for which the text will be useful: when several matches go out in the same turn, we want the game to print

Four matches go out.

rather than

A match goes out.
A match goes out.
A match goes out.
A match goes out.

This last function appears down in Section 3, if we wish to skip ahead and look at it.

paste.png "The Cow Exonerated"

Section 1 - Simple Burning

Understand the commands "light" and "burn" as something new.

Understand "burn [something] with [strikable-match]" as burning it with. Understand "burn [something] with [something preferably held]" as burning it with. Burning it with is an action applying to one thing and one carried thing.

Understand the command "light" as "burn".

A thing can be flammable or impervious. A thing is usually impervious.

Check burning something with something (this is the burn only with flaming matches rule):
    if the second noun is not a strikable-match, say "You can only light things with matches." instead;
    if the second noun is not flaming, say "[The second noun] needs to be burning first." instead.

Check burning something with something (this is the burn only flammable things rule):
    if the noun is impervious, say "[The noun] cannot be burned." instead.

Check burning something with something (this is the burn only things not held rule):
    say "[one of]It occurs to you to set down [the noun] before burning, just for safety's sake. [or]Again, you decide to put down [the noun] prior to burning. [or]You try setting down [the noun] as usual. [stopping][run paragraph on]";
    silently try the player dropping the noun;
    if the player encloses the noun, stop the action.

Carry out burning something with something (this is the simplistic burning rule):
    now the noun is nowhere.

Report burning something with something:
    say "You burn up [the noun]."

Rule for implicitly taking the second noun while burning something with something which is not a strikable-match:
    say "You can only light things with matches.";
    stop the action.

Section 2 - Matches

The word "matches" is used by Inform to compare snippets of text (see "Reading a command" in the Activities chapter). This can sometimes cause awkwardness if we also have a kind called "match", so for the occasion we will give our matches a more specialized name, never visible to the player:

A strikable-match is a kind of thing. The plural of strikable-match is s-matches.

A strikable-match has a number called duration. The duration of a strikable-match is usually 3.

Rule for printing the name of a strikable-match: say "match".
Rule for printing the plural name of a strikable-match: say "matches".

Understand "match" as a strikable-match. Understand "matches" as a strikable-match.

Flame-state is a kind of value. The flame-states are burnt, flaming, and new. Understand "burning" or "lit" as flaming. Understand "unused" as new.

A strikable-match has a flame-state. A strikable-match is usually new. Understand the flame-state property as describing a strikable-match.

Before printing the name of a strikable-match while asking which do you mean:
    say "[flame-state] ".

Before printing the name of a strikable-match while taking inventory:
    say "[flame-state] ".
Before printing the plural name of a strikable-match while taking inventory:
    say "[flame-state] ".

Before printing the name of a strikable-match while clarifying the parser's choice of something:
    if not taking inventory, say "[flame-state] ".

After printing the name of a strikable-match (called special-target) while clarifying the parser's choice of something:
    if the player carries the special-target:
        say " you're carrying";
    otherwise if the special-target is in the location:
        say " on the ground";
    otherwise:
        say " [if the holder of the special-target is a container]in[otherwise]on[end if] [the holder of the special-target]".

Understand "strike [something]" as attacking.

Understand "strike [strikable-match]" as striking. Striking is an action applying to one carried thing.

Understand "burn [strikable-match]" as striking.

Does the player mean striking a new strikable-match:
    it is very likely.

Does the player mean striking a burnt strikable-match:
    it is unlikely.

Check striking a strikable-match (this is the strike only new matches rule):
    if the noun is burnt, say "[The noun] has already burnt down and cannot be relit." instead;
    if the noun is flaming, say "[The noun] is already burning." instead.

Carry out striking a strikable-match (this is the standard striking rule):
    now the noun is flaming;
    now the noun is lit.

Report striking a strikable-match (this is the standard report striking rule):
    say "You light [the noun]."

Before burning something with a new strikable-match (this is the prior lighting rule):
    say "(first [if the player does not carry the second noun]taking and [end if]lighting [the second noun])[command clarification break]";
    silently try striking the second noun;
    if the second noun is not flaming, stop the action.

Rule for implicitly taking a strikable-match (called target) while striking:
    try silently taking the target.

Does the player mean burning something with a flaming strikable-match:
    it is very likely.

Does the player mean burning something with a new strikable-match:
    it is likely.

Does the player mean burning something with a burnt strikable-match:
    it is unlikely.

Instead of burning a burnt strikable-match with something:
    say "[The noun] is completely consumed and cannot be relit."

Section 3 - Putting the Matches Out

Every turn:
    let N be 0; [here we track how many matches are being put out during this turn, so that we don't have to mention each match individually if several go out during the same move]
    repeat with item running through flaming s-matches:
        decrement the duration of the item;
        if the duration of the item is 0:
            now the item is burnt;
            now the item is unlit;
            if the item is visible, increment N;
    if N is 1:
        say "[if the number of visible flaming s-matches is greater than 0]One of the matches [otherwise if the number of burnt visible s-matches is greater than 1]Your last burning match [otherwise]The match [end if]goes out.";
    otherwise if N is greater than 1:
        let enumeration be "[N in words]";
        if N is the number of visible s-matches:
            if N is two, say "Both";
            otherwise say "All [enumeration]";
        otherwise:
            say "[enumeration in title case]";
        say " matches go out[if a visible strikable-match is flaming], leaving [number of visible flaming s-matches in words] still lit[end if]."

Section 4 - Scenario

Old Chicago is a room.

The player carries a flammable thing called a log. Understand "wooden" and "wood" as the log.

The player carries two s-matches. The matchbox is an open openable container. It contains five s-matches. The player carries the matchbox.

When play begins:
    now every strikable-match carried by the player is flaming;
    now every strikable-match carried by the player is lit.

Test me with "i / burn match / i / i / burn log with match / burn matchbox with match / i".

Here we create a class of matches that can be used to burn other objects. Our objectives are as follow:

Burned objects other than matches should be removed from play instantly (just as edible objects are instantly eaten). We could give everything its own burning duration, but that complicates matters and allows for fire to spread from one object to another; for an example of how to do that, see the example "In Fire or in Flood".

Matches should be described to show whether they are burning or extinguished, and when the parser chooses one of several identical matches, it should make very clear which match it has selected.

The game must sensibly select and, if necessary, automatically light new matches to carry out a >BURN THING command.

The matches must burn for a set number of turns before going out, never to be used again.

And finally, the part for which the text will be useful: when several matches go out in the same turn, we want the game to print

Four matches go out.

rather than

A match goes out.
A match goes out.
A match goes out.
A match goes out.

This last function appears down in Section 3, if we wish to skip ahead and look at it.

paste.png "The Cow Exonerated"

Section 1 - Simple Burning

Understand the commands "light" and "burn" as something new.

Understand "burn [something] with [strikable-match]" as burning it with. Understand "burn [something] with [something preferably held]" as burning it with. Burning it with is an action applying to one thing and one carried thing.

Understand the command "light" as "burn".

A thing can be flammable or impervious. A thing is usually impervious.

Check burning something with something (this is the burn only with flaming matches rule):
    if the second noun is not a strikable-match, say "You can only light things with matches." instead;
    if the second noun is not flaming, say "[The second noun] needs to be burning first." instead.

Check burning something with something (this is the burn only flammable things rule):
    if the noun is impervious, say "[The noun] cannot be burned." instead.

Check burning something with something (this is the burn only things not held rule):
    say "[one of]It occurs to you to set down [the noun] before burning, just for safety's sake. [or]Again, you decide to put down [the noun] prior to burning. [or]You try setting down [the noun] as usual. [stopping][run paragraph on]";
    silently try the player dropping the noun;
    if the player encloses the noun, stop the action.

Carry out burning something with something (this is the simplistic burning rule):
    now the noun is nowhere.

Report burning something with something:
    say "You burn up [the noun]."

Rule for implicitly taking the second noun while burning something with something which is not a strikable-match:
    say "You can only light things with matches.";
    stop the action.

Section 2 - Matches

The word "matches" is used by Inform to compare snippets of text (see "Reading a command" in the Activities chapter). This can sometimes cause awkwardness if we also have a kind called "match", so for the occasion we will give our matches a more specialized name, never visible to the player:

A strikable-match is a kind of thing. The plural of strikable-match is s-matches.

A strikable-match has a number called duration. The duration of a strikable-match is usually 3.

Rule for printing the name of a strikable-match: say "match".
Rule for printing the plural name of a strikable-match: say "matches".

Understand "match" as a strikable-match. Understand "matches" as a strikable-match.

Flame-state is a kind of value. The flame-states are burnt, flaming, and new. Understand "burning" or "lit" as flaming. Understand "unused" as new.

A strikable-match has a flame-state. A strikable-match is usually new. Understand the flame-state property as describing a strikable-match.

Before printing the name of a strikable-match while asking which do you mean:
    say "[flame-state] ".

Before printing the name of a strikable-match while taking inventory:
    say "[flame-state] ".
Before printing the plural name of a strikable-match while taking inventory:
    say "[flame-state] ".

Before printing the name of a strikable-match while clarifying the parser's choice of something:
    if not taking inventory, say "[flame-state] ".

After printing the name of a strikable-match (called special-target) while clarifying the parser's choice of something:
    if the player carries the special-target:
        say " you're carrying";
    otherwise if the special-target is in the location:
        say " on the ground";
    otherwise:
        say " [if the holder of the special-target is a container]in[otherwise]on[end if] [the holder of the special-target]".

Understand "strike [something]" as attacking.

Understand "strike [strikable-match]" as striking. Striking is an action applying to one carried thing.

Understand "burn [strikable-match]" as striking.

Does the player mean striking a new strikable-match:
    it is very likely.

Does the player mean striking a burnt strikable-match:
    it is unlikely.

Check striking a strikable-match (this is the strike only new matches rule):
    if the noun is burnt, say "[The noun] has already burnt down and cannot be relit." instead;
    if the noun is flaming, say "[The noun] is already burning." instead.

Carry out striking a strikable-match (this is the standard striking rule):
    now the noun is flaming;
    now the noun is lit.

Report striking a strikable-match (this is the standard report striking rule):
    say "You light [the noun]."

Before burning something with a new strikable-match (this is the prior lighting rule):
    say "(first [if the player does not carry the second noun]taking and [end if]lighting [the second noun])[command clarification break]";
    silently try striking the second noun;
    if the second noun is not flaming, stop the action.

Rule for implicitly taking a strikable-match (called target) while striking:
    try silently taking the target.

Does the player mean burning something with a flaming strikable-match:
    it is very likely.

Does the player mean burning something with a new strikable-match:
    it is likely.

Does the player mean burning something with a burnt strikable-match:
    it is unlikely.

Instead of burning a burnt strikable-match with something:
    say "[The noun] is completely consumed and cannot be relit."

Section 3 - Putting the Matches Out

Every turn:
    let N be 0; [here we track how many matches are being put out during this turn, so that we don't have to mention each match individually if several go out during the same move]
    repeat with item running through flaming s-matches:
        decrement the duration of the item;
        if the duration of the item is 0:
            now the item is burnt;
            now the item is unlit;
            if the item is visible, increment N;
    if N is 1:
        say "[if the number of visible flaming s-matches is greater than 0]One of the matches [otherwise if the number of burnt visible s-matches is greater than 1]Your last burning match [otherwise]The match [end if]goes out.";
    otherwise if N is greater than 1:
        let enumeration be "[N in words]";
        if N is the number of visible s-matches:
            if N is two, say "Both";
            otherwise say "All [enumeration]";
        otherwise:
            say "[enumeration in title case]";
        say " matches go out[if a visible strikable-match is flaming], leaving [number of visible flaming s-matches in words] still lit[end if]."

Section 4 - Scenario

Old Chicago is a room.

The player carries a flammable thing called a log. Understand "wooden" and "wood" as the log.

The player carries two s-matches. The matchbox is an open openable container. It contains five s-matches. The player carries the matchbox.

When play begins:
    now every strikable-match carried by the player is flaming;
    now every strikable-match carried by the player is lit.

Test me with "i / burn match / i / i / burn log with match / burn matchbox with match / i".