Actions taking a list of objects, allowing repeats

I’m interested in writing a new action that takes a list of objects— that is, an ordered n-tuple of objects, possibly with repeated elements, for arbitrary n. As far as I can tell from the sparse documentation, I7 matches multiple objects with the [things] token and assembles them into the “multiple object list.” (The usual setup is also to run a transitive action on each element of the list in succession, but that’s easy to get around.) The problem is that the list eliminates duplicates, which I don’t want, and I don’t see any way of hacking the code for parsing that particular token to change it. I can drop in a custom “noun=customFunction” I6 verb-parsing routine, but it’s not worth it to have to deal with disambiguation, ALL, etc. by hand.

So, how do I write an action grammar token that accepts a list of objects (say, with ALL disallowed here) and gives me exactly those objects, in order and with repeats?

1 Like

Do you want TAKE and DROP to still remove duplicates—that is, is it important to preserve the current functionality for existing actions?

1 Like

I want this functionality to hold only for a specific custom action, but I should just be able to delete duplicates after the fact for actions like TAKE and DROP.

I am not aware of any simple way to accomplish this. In case no one has better ideas, here is how I would do it.

Hacky code

Vegan Sandwich Shop is a room. In the shop are sourdough, tomato, dill pickle, hummus, red pepper, green pepper, eggplant, and ketchup.

The matchable ingredient is a thing that varies. Definition: something is matchable if it is the matchable ingredient.

Sandwiching is an action applying to one topic. Understand "sandwich [text]" as sandwiching.
The sandwiching action has a list of things called the sandwiched layers.

Check sandwiching:
let T be "[the topic understood]";
replace the text "and" in T with "[line break]";
repeat with N running from 1 to the number of lines in T:
let the matched ingredients be a list of things;
change the text of the player's command to line number N in T;
repeat with possible referent running through things:
now the matchable ingredient is the possible referent;
if the player's command matches "[any matchable thing]":
add the matchable ingredient to the matched ingredients;
if the number of entries in matched ingredients is 0:
say "I don't know what you mean by '[the player's command]', so we can't include it in a sandwich." instead;
if the number of entries in matched ingredients > 1:
say "I can't tell what you mean by '[the player's command]'. We have [matched ingredients]. Chefs should always be specific." instead;
add entry one in the matched ingredients to the sandwiched layers.

Carry out sandwiching:
say "You sandwich [sandwiched layers].";
unless entry one in the sandwiched layers is sourdough:
say "But the bottom is [entry one in the sandwiched layers], so it's not really much of a sandwich.".

Test me with "sandwich sourdough and tomato and sourdough / sandwich tomato and pickle and green pepper and hummus / sandwich sourdough and pepper and sourdough / sandwich things / sandwich all".

2 Likes

Could you give a clearer example of the type of behavior you mean?

It sounds like you want something like:

>tap the wand, the rock, the can, the pen and the wand

Ok. You tapped the the wand, then the rock, then the can, then the pen and finally the wand (a second time).

1 Like

That’s pretty much what I’m going for, though mostly I just want the list [wand, rock, can, pen, wand]; what the new action then does with it is a bit more complicated (and something I can easily handle myself at that point).

Thanks, that was similar to some I6 code I had written for what I think was the same effect: Split up the user’s input at connectives (and, then, (comma), etc.), match each individual object mentioned, and bundle them into a list by hand. It probably works, but I’m a bit worried about edge cases: disambiguation prompts, modifying the player’s command directly, etc.

The easiest solution then is to edit this bit of code:

[ MultiAdd o i j;
    i = multiple_object-->0;
    if (i == MATCH_LIST_WORDS-1) { toomany_flag = 1; rtrue; }
    for (j=1 : j<=i : j++)
        if (o == multiple_object-->j) rtrue;
    i++;
    multiple_object-->i = o;
    multiple_object-->0 = i;
];

Just remove the bit that checks for duplicates.

Include (-
[ MultiAdd o i;
    i = multiple_object-->0;
    if (i == MATCH_LIST_WORDS-1) { toomany_flag = 1; rtrue; }
    i++;
    multiple_object-->i = o;
    multiple_object-->0 = i;
];
-) replacing "MultiAdd".

Now the multiple object list will contain duplicates if duplicates were found in the player’s input, and you can manually remove them again for any standard actions. The place to remove them would be in ReviseMulti, and that’s left as an exercise for the reader.

4 Likes

That works, thanks!