§6.15. Actions on Multiple Objects

Inform allows a handful of actions - TAKE, DROP, PUT, INSERT - to apply to more than one item at a time, so that the player can move things around easily.

The general principle is that multiple objects are allowed if the actions are likely to be successful but not interesting most of the time, and if they're things that the player could plausibly do all at once. For most actions, the use of ALL would seem weirdly indiscriminate: EAT ALL, say, describes very implausible behavior, and EXAMINE ALL would likely generate a screenful of text at once.

But this is all under our control. To create an action that uses multiples, or to allow the use of multiple objects with an already-existing action, we need to create an understand statement that uses the "[things]" token (note the plural). For instance:

Understand "give [things] to [someone]" as giving it to.

This would let the existing give action apply to multiple objects, in just the same way that "take" does. Shawn's Bad Day demonstrates how we might allow EXAMINE ALL to print descriptions of every visible item.

Alternatively, we could generate a new action:

Understand "give [things] to [someone]" as multiply-giving it to. Multiply-giving it to is an action applying to one carried thing and one thing.

(In theory the language here should perhaps be "several carried things" -- but Inform is still going to process multiply-giving item by item, unless we redirect it. More about this in a moment.)

When handling an action that uses the "[things]" token, the parser makes a list of every item to which it is going to apply the action: this is called the multiple objects list. The multiple objects list can be the result of a vague request (GET ALL) or a specific one involving identical multiples (GET PENNIES, GET THREE APPLES) or a very specific one involving unique, named nouns (GET GERBIL, APPLE, AND POMEGRANATE).

We can manipulate what Inform includes in "ALL" in sentences like TAKE ALL with the "deciding whether all includes..." activity; for instance

Rule for deciding whether all includes scenery: it does not.

prevents TAKE ALL from applying to things that can't be moved anyway, avoiding lots of lines like

tree: That's hardly portable.
swing set: That's hardly portable.

A slightly tedious technical note: the multiple objects list is not strictly a list in the standard Inform sense, because it is used so frequently in parsing that it would be cumbersome to handle it with the more flexible but less efficient structure used for lists. However, if we want to manipulate the multiple objects list as though it were an ordinary list -- that is, sort it, rotate it, truncate it, remove entries from it, etc -- we may do so by creating a list like this:

let L be the multiple object list.

and later after making L conform to our desires:

alter the multiple object list to L.

Inform next repeatedly runs the action rulebook for the action generated, using each item from the multiple object list as "noun" in turn (or as "second noun", if that's where the [things] token appeared in the understand line). Since it is possible to alter the multiple object list before the "generate action rule" portion of the turn sequence consults the rulebooks, we can also affect the order in which the player's matched objects are handled; see Formicidae. We should not attempt to change the multiple object list after this point, because this is likely to introduce bugs.

Each time Inform tries the action on a new noun, it prefixes the action-attempt with the name of the item it's currently working on. This is where we get such output as "frog eyeballs:" and "newt toes:" in long lists like

frog eyeballs: Taken.
newt toes: Taken.

These names are generated by the "announce items from multiple object lists rule" in the action-handling rules; Escape from the Seraglio shows how to alter them. In the context of this rule, the thing we are currently printing the name of can be called "the current item from the multiple object list".

Suppressing names of objects entirely, while occasionally tempting, may have unintended consequences, especially if some of the attempted actions are prevented by check rules that themselves print things. It is safest to suppress the multiple object names in the case where we already know that the action will succeed wherever it is attempted (more often for observational actions like examining than for manipulative actions like taking, or where we mean to completely override default handling).

Given that our hypothetical "multiply-giving" applies to each given object in turn, it might seem to be useless to create "multiply-giving" as an action different from "giving" -- but the convenience is that manipulating the multiple object list makes it possible to group behavior artificially. The trick here is that, on the first pass of the multiply-giving rulebook, we look at the entire multiple object list, perform actions, print output, and set a flag saying that the action has been handled. The flag tells Inform not to do or print anything for any of the subsequent passes through that action rulebook; thus we artificially create a situation where, instead of performing an action on each object in turn, Inform acts once on the entire group. That allows us to assess the cumulative qualities of the group and have the action respond differently than it might when assessing each item individually.

The Facts Were These demonstrates how we might write an action for GIVE THREE DOLLARS TO MAN or GIVE PIE AND HAT TO MAN where the man would only accept the collective gift when its total proved satisfactory.

Western Art History 305 demonstrates how we might allow EXAMINE, which doesn't normally permit multiple objects, to take them, but to give vaguer responses to a mass examination than an individual one.

* See Examining for groups of objects that have a collective description different from their individual descriptions, and for commands that search multiple things at once

* See Dispensers and Supplies of Small Objects for ways to let the player pick up a number of identical items from a dispenser or supply


arrow-up.pngStart of Chapter 6: Commands
arrow-left.pngBack to §6.14. Remembering, Converting and Combining Actions
arrow-right.pngOnward to §6.16. Alternate Default Messages

*ExampleShawn's Bad Day
Allowing the player to EXAMINE ALL.

**ExampleWestern Art History 305
Allowing EXAMINE to see multiple objects with a single command.

**ExampleThe Best Till Last
Reordering multiple objects for dramatic effect.

**ExampleEscape from the Seraglio
Replacing the usual response to TAKE ALL so that instead of output such as "grapes: Taken. orange: Taken.", Inform produces variable responses in place of "grapes:".

**ExampleFormicidae
Manipulating the order in which items are handled after TAKE ALL.

Occasionally it happens that we want to process an action on multiple items differently than we would if the player had just typed each of the individual actions separately. In this example, the reason is that we can only successfully GIVE items when their combined value passes a certain threshold amount; otherwise the recipient will reject them.

This works as an implementation of money, if we give value only to cash objects (though several other implementations of cash are available, most of which are simpler and more efficient). We could also imagine a mechanic like this being used for a bargaining or auction game as well, given a society that deals in objects rather than credits.

In order to consider all the items in the gift at once, we create an action that applies to multiple objects, but will in fact test the whole object collection during the first pass and print a definitive answer to whether the action succeeded. All subsequent times the game consults the rulebook will be stopped at the very beginning. No further processing will occur or output be printed.

paste.png "The Facts Were These"

Section 1 - Procedure

We start by creating the idea that everything in the game has a monetary value:

A price is a kind of value. $10 specifies a price. A thing has a price.

Understand "give [things preferably held] to [someone]" as multiply-giving it to. Understand "give [things] to [someone]" as multiply-giving it to. Multiply-giving it to is an action applying to two things.

A subtlety here: we say "things preferably held" to prefer items that the player is holding (so if the player has two dollars in hand and a third lies on the ground, he will use just the two he has).

The second grammar line allows Inform to match things that aren't held if it can't make up the list from things that are. If all three dollars are on the ground, the player can pick them up before spending them.

We do not, however, make multiply-giving apply to a "carried" item, because that will generate implicit takes of those items in a way that will mess up our action reporting. Instead, we're going to build the implicit takes into the system in a different way, one that permits us to collate the reports more attractively and print a short, one-sentence list of anything that the player had to pick up.

A thing can be given or ungiven. A thing is usually ungiven.

This is for record-keeping purposes so that we can print an attractive list of what was given at the end of the turn.

First check multiply-giving it to:
    if already gave at the office is true:
        stop the action.

Already gave at the office is a truth state that varies.

"Already gave at the office" is the perhaps-excessively-named flag that keeps track of whether we've already done this action once.

Check multiply-giving something to the player:
        now already gave at the office is true;
        say "You can hardly bribe yourself.[paragraph break]" instead;

The following rule is longish because it processes the entire list at once, generating implicit takes if necessary (but processing those implicit takes silently according to its own special rule, so that the output can be managed attractively). We are also, at the same time, calculating the total value of the player's offer.

Check multiply-giving it to:
    let L be the multiple object list;
    let bribe-price be $0;
    repeat with item running through L:
        if the player does not carry the item:
            abide by the ungivability rules for the item;
            carry out the implicitly taking activity with the item;
            if the player does not carry the item:
                now already gave at the office is true;
                say "You can't include [the item] in your bribe, since you're not holding [them]![paragraph break]" instead;
        increase bribe-price by the price of item;
    if the number of entries in the recently-collected list is greater than 0:
        repeat with item running through the recently-collected list:
            now item is marked for listing;
        say "You pick up [the list of marked for listing things] and make your offer. [run paragraph on]";
        now everything is unmarked for listing;
    if the bribe-price is less than the price of the second noun:
        now already gave at the office is true;
        say "[The second noun] angrily rejects your piffling bribe.[paragraph break]" instead.

The bit about making some items "marked for listing", above, rather than printing the list directly, is that using the "[the list of....]" syntax guarantees that Inform will respect grouping rules in writing its description. For instance, if the player has automatically taken all three dollars, the output will say "the three dollars" instead of "the dollar, the dollar, and the dollar."

Carry out multiply-giving it to:
    let L be the multiple object list;
    repeat with item running through L:
        now the second noun carries the item;
        now the item is given;
    now already gave at the office is true;

Report multiply-giving it to:
    say "[The second noun] rather shamefacedly tucks [the list of given things] away into a pocket.[paragraph break]".

Now we create our own variation of implicitly taking in order to customize the output for the multiply-giving action. The "ungivability rules" should disallow any object that the player absolutely cannot take, because we want "carry out the implicitly taking activity" to succeed every time -- and therefore not print out any less-attractive results from implicit takes that don't succeed. Otherwise, the player's GIVE TREE AND DOG TO ATTENDANT might produce the reply "That's fixed in place" -- without specifying which object is fixed in place.

Because of the way this works, we will want to be careful: if we have any "instead of taking..." rules for special objects in the game, we should be sure to mirror those with an ungivability rule to print something more suitable in the case that the player tries taking that object as part of the multiple giving action.

The ungivability rules are an object-based rulebook.

An ungivability rule for a person:
    now already gave at the office is true;
    say "Slavery is illegal.[paragraph break]" instead.

An ungivability rule for something (called the item) which is enclosed by someone who is not the player:
    now already gave at the office is true;
    say "[The item] [aren't] yours to give.[paragraph break]" instead.

An ungivability rule for something which encloses the player:
    now already gave at the office is true;
    say "You don't want to end up as part of the gift.[paragraph break]" instead;

An ungivability rule for something (called the item) which is part of something:
    now already gave at the office is true;
    say "[The item] [are] attached to [a random thing which incorporates the item][paragraph break]" instead.

An ungivability rule for something (called the item) which is scenery:
    now already gave at the office is true;
    say "[The item] [are] unremovable.[paragraph break]" instead.

An ungivability rule for something (called the item) which is fixed in place:
    now already gave at the office is true;
    say "[The item] [are] fixed in place.[paragraph break]" instead.

An ungivability rule for a direction (called the item):
    now already gave at the office is true;
    say "[The item] [are] not susceptible to giving.[paragraph break]" instead.

Rule for implicitly taking something (called target) while multiply-giving:
    silently try taking the target;
    if the player carries the target:
        add the target to the recently-collected list.

The recently-collected list is a list of objects that varies.

And since we don't want to list the individual objects separately:

The selectively announce items from multiple object lists rule is listed instead of the announce items from multiple object lists rule in the action-processing rules.

This is the selectively announce items from multiple object lists rule:
    if multiply-giving:
        do nothing;
    otherwise:
        if the current item from the multiple object list is not nothing:
            say "[current item from the multiple object list]: [run paragraph on]".

And now, since this ought to work symmetrically if the player provides just one high-value item:

Check giving something to someone:
    if the price of the noun is less than the price of the second noun:
        say "[The second noun] angrily rejects your piffling bribe." instead.

As we've seen elsewhere, the giving action by default returns a refusal, but is also written to start working if we remove the blockage. So we do that here, and revise the report rule to match the report rule we have for multiple giving.

The block giving rule is not listed in any rulebook.

The new report giving rule is listed instead of the standard report giving rule in the report giving it to rules.

This is the new report giving rule:
    say "[The second noun] rather shamefacedly tucks [the noun] away into a pocket."

After each instance of the multiply-giving action, we need to clear the variables we used to track its state. We could do this in "Before reading a command", but that's unsafe because the player might type GIVE PIE AND CAP TO ATTENDANT. GIVE DOLLARS TO ATTENDANT. all on a single line, and we would like to be able to clear the variables between one action and the next. The correct place to attach this behavior is immediately before the generate action rule, thus:

The before-generation rule is listed before the generate action rule in the turn sequence rules.

This is the before-generation rule:
    now every thing is ungiven;
    now already gave at the office is false;
    truncate the recently-collected list to 0 entries.

Section 2 - Scenario

The Morgue Office is a room. "This is not the Morgue itself; this is only its outer office. The familiar room full of silver drawers and cold air lies beyond."

The Morgue Attendant is a man in the Morgue Office. "The Attendant has seen you come through a number of times, and is becoming suspicious of your abiding interest in dead people." The description is "The Morgue Attendant is fifty-four years, six months, five days, and three minutes old." The price of the Morgue Attendant is $3.

A dollar is a kind of thing. The player carries three dollars. The price of a dollar is always $1.

The player carries a miniature rhubarb pie. The price of the miniature rhubarb pie is $5.

The player carries a knitted cap. The price of the knitted cap is $2.

Test me with "test dollars / purloin three dollars / test multi-line / purloin three dollars / purloin pie / purloin cap / test specificity / purloin three dollars / test largesse / test mixed-gift".

Test multi-line with "give dollar and pie to attendant. give dollars and cap to attendant".

Test dollars with "drop all / give dollar to Morgue Attendant / give dollars to Morgue Attendant / get dollars / give dollars to morgue attendant / purloin three dollars / drop dollars / give dollars to Morgue Attendant".

Test specificity with "give three dollars to Morgue Attendant".

Test largesse with "give pie to Morgue Attendant".

Test mixed-gift with "give dollar and cap to Morgue Attendant / get cap / give dollar and cap to morgue attendant / give me and dollar to attendant".

PURLOIN, used in the tests here, is a special debugging command that allows the player to acquire objects that wouldn't otherwise be possible to take. It is only active in non-release versions of the story. For more about debugging commands, see the chapter on Testing and Debugging.

**ExampleThe Facts Were These
Creating a variant GIVE action that lets the player give multiple objects simultaneously with commands like GIVE ALL TO ATTENDANT or GIVE THREE DOLLARS TO ATTENDANT or GIVE PIE AND HAT TO ATTENDANT. The attendant accepts the gifts only if their total combined value matches some minimum amount.

Occasionally it happens that we want to process an action on multiple items differently than we would if the player had just typed each of the individual actions separately. In this example, the reason is that we can only successfully GIVE items when their combined value passes a certain threshold amount; otherwise the recipient will reject them.

This works as an implementation of money, if we give value only to cash objects (though several other implementations of cash are available, most of which are simpler and more efficient). We could also imagine a mechanic like this being used for a bargaining or auction game as well, given a society that deals in objects rather than credits.

In order to consider all the items in the gift at once, we create an action that applies to multiple objects, but will in fact test the whole object collection during the first pass and print a definitive answer to whether the action succeeded. All subsequent times the game consults the rulebook will be stopped at the very beginning. No further processing will occur or output be printed.

paste.png "The Facts Were These"

Section 1 - Procedure

We start by creating the idea that everything in the game has a monetary value:

A price is a kind of value. $10 specifies a price. A thing has a price.

Understand "give [things preferably held] to [someone]" as multiply-giving it to. Understand "give [things] to [someone]" as multiply-giving it to. Multiply-giving it to is an action applying to two things.

A subtlety here: we say "things preferably held" to prefer items that the player is holding (so if the player has two dollars in hand and a third lies on the ground, he will use just the two he has).

The second grammar line allows Inform to match things that aren't held if it can't make up the list from things that are. If all three dollars are on the ground, the player can pick them up before spending them.

We do not, however, make multiply-giving apply to a "carried" item, because that will generate implicit takes of those items in a way that will mess up our action reporting. Instead, we're going to build the implicit takes into the system in a different way, one that permits us to collate the reports more attractively and print a short, one-sentence list of anything that the player had to pick up.

A thing can be given or ungiven. A thing is usually ungiven.

This is for record-keeping purposes so that we can print an attractive list of what was given at the end of the turn.

First check multiply-giving it to:
    if already gave at the office is true:
        stop the action.

Already gave at the office is a truth state that varies.

"Already gave at the office" is the perhaps-excessively-named flag that keeps track of whether we've already done this action once.

Check multiply-giving something to the player:
        now already gave at the office is true;
        say "You can hardly bribe yourself.[paragraph break]" instead;

The following rule is longish because it processes the entire list at once, generating implicit takes if necessary (but processing those implicit takes silently according to its own special rule, so that the output can be managed attractively). We are also, at the same time, calculating the total value of the player's offer.

Check multiply-giving it to:
    let L be the multiple object list;
    let bribe-price be $0;
    repeat with item running through L:
        if the player does not carry the item:
            abide by the ungivability rules for the item;
            carry out the implicitly taking activity with the item;
            if the player does not carry the item:
                now already gave at the office is true;
                say "You can't include [the item] in your bribe, since you're not holding [them]![paragraph break]" instead;
        increase bribe-price by the price of item;
    if the number of entries in the recently-collected list is greater than 0:
        repeat with item running through the recently-collected list:
            now item is marked for listing;
        say "You pick up [the list of marked for listing things] and make your offer. [run paragraph on]";
        now everything is unmarked for listing;
    if the bribe-price is less than the price of the second noun:
        now already gave at the office is true;
        say "[The second noun] angrily rejects your piffling bribe.[paragraph break]" instead.

The bit about making some items "marked for listing", above, rather than printing the list directly, is that using the "[the list of....]" syntax guarantees that Inform will respect grouping rules in writing its description. For instance, if the player has automatically taken all three dollars, the output will say "the three dollars" instead of "the dollar, the dollar, and the dollar."

Carry out multiply-giving it to:
    let L be the multiple object list;
    repeat with item running through L:
        now the second noun carries the item;
        now the item is given;
    now already gave at the office is true;

Report multiply-giving it to:
    say "[The second noun] rather shamefacedly tucks [the list of given things] away into a pocket.[paragraph break]".

Now we create our own variation of implicitly taking in order to customize the output for the multiply-giving action. The "ungivability rules" should disallow any object that the player absolutely cannot take, because we want "carry out the implicitly taking activity" to succeed every time -- and therefore not print out any less-attractive results from implicit takes that don't succeed. Otherwise, the player's GIVE TREE AND DOG TO ATTENDANT might produce the reply "That's fixed in place" -- without specifying which object is fixed in place.

Because of the way this works, we will want to be careful: if we have any "instead of taking..." rules for special objects in the game, we should be sure to mirror those with an ungivability rule to print something more suitable in the case that the player tries taking that object as part of the multiple giving action.

The ungivability rules are an object-based rulebook.

An ungivability rule for a person:
    now already gave at the office is true;
    say "Slavery is illegal.[paragraph break]" instead.

An ungivability rule for something (called the item) which is enclosed by someone who is not the player:
    now already gave at the office is true;
    say "[The item] [aren't] yours to give.[paragraph break]" instead.

An ungivability rule for something which encloses the player:
    now already gave at the office is true;
    say "You don't want to end up as part of the gift.[paragraph break]" instead;

An ungivability rule for something (called the item) which is part of something:
    now already gave at the office is true;
    say "[The item] [are] attached to [a random thing which incorporates the item][paragraph break]" instead.

An ungivability rule for something (called the item) which is scenery:
    now already gave at the office is true;
    say "[The item] [are] unremovable.[paragraph break]" instead.

An ungivability rule for something (called the item) which is fixed in place:
    now already gave at the office is true;
    say "[The item] [are] fixed in place.[paragraph break]" instead.

An ungivability rule for a direction (called the item):
    now already gave at the office is true;
    say "[The item] [are] not susceptible to giving.[paragraph break]" instead.

Rule for implicitly taking something (called target) while multiply-giving:
    silently try taking the target;
    if the player carries the target:
        add the target to the recently-collected list.

The recently-collected list is a list of objects that varies.

And since we don't want to list the individual objects separately:

The selectively announce items from multiple object lists rule is listed instead of the announce items from multiple object lists rule in the action-processing rules.

This is the selectively announce items from multiple object lists rule:
    if multiply-giving:
        do nothing;
    otherwise:
        if the current item from the multiple object list is not nothing:
            say "[current item from the multiple object list]: [run paragraph on]".

And now, since this ought to work symmetrically if the player provides just one high-value item:

Check giving something to someone:
    if the price of the noun is less than the price of the second noun:
        say "[The second noun] angrily rejects your piffling bribe." instead.

As we've seen elsewhere, the giving action by default returns a refusal, but is also written to start working if we remove the blockage. So we do that here, and revise the report rule to match the report rule we have for multiple giving.

The block giving rule is not listed in any rulebook.

The new report giving rule is listed instead of the standard report giving rule in the report giving it to rules.

This is the new report giving rule:
    say "[The second noun] rather shamefacedly tucks [the noun] away into a pocket."

After each instance of the multiply-giving action, we need to clear the variables we used to track its state. We could do this in "Before reading a command", but that's unsafe because the player might type GIVE PIE AND CAP TO ATTENDANT. GIVE DOLLARS TO ATTENDANT. all on a single line, and we would like to be able to clear the variables between one action and the next. The correct place to attach this behavior is immediately before the generate action rule, thus:

The before-generation rule is listed before the generate action rule in the turn sequence rules.

This is the before-generation rule:
    now every thing is ungiven;
    now already gave at the office is false;
    truncate the recently-collected list to 0 entries.

Section 2 - Scenario

The Morgue Office is a room. "This is not the Morgue itself; this is only its outer office. The familiar room full of silver drawers and cold air lies beyond."

The Morgue Attendant is a man in the Morgue Office. "The Attendant has seen you come through a number of times, and is becoming suspicious of your abiding interest in dead people." The description is "The Morgue Attendant is fifty-four years, six months, five days, and three minutes old." The price of the Morgue Attendant is $3.

A dollar is a kind of thing. The player carries three dollars. The price of a dollar is always $1.

The player carries a miniature rhubarb pie. The price of the miniature rhubarb pie is $5.

The player carries a knitted cap. The price of the knitted cap is $2.

Test me with "test dollars / purloin three dollars / test multi-line / purloin three dollars / purloin pie / purloin cap / test specificity / purloin three dollars / test largesse / test mixed-gift".

Test multi-line with "give dollar and pie to attendant. give dollars and cap to attendant".

Test dollars with "drop all / give dollar to Morgue Attendant / give dollars to Morgue Attendant / get dollars / give dollars to morgue attendant / purloin three dollars / drop dollars / give dollars to Morgue Attendant".

Test specificity with "give three dollars to Morgue Attendant".

Test largesse with "give pie to Morgue Attendant".

Test mixed-gift with "give dollar and cap to Morgue Attendant / get cap / give dollar and cap to morgue attendant / give me and dollar to attendant".

PURLOIN, used in the tests here, is a special debugging command that allows the player to acquire objects that wouldn't otherwise be possible to take. It is only active in non-release versions of the story. For more about debugging commands, see the chapter on Testing and Debugging.