Trying to take multiple identical things from a held container gives a confusing response

In this scenario, if I type “take pencils,” Inform responds with “The desk is empty.”

Lab is a room. 

A desk is a supporter in Lab.

A cup is a container carried by player.

A pencil is a kind of thing.

3 pencils are in the cup.

Test me with "take pencils".

I don’t know if there is a straightforward way to allow the player to just take the pencils out of the cup this way, but if not, how can I give a response that at least makes sense to the player? It seems like the built-in response can vary depending on the properties of the other thing (in this case, the desk). If you have something that’s not a supporter or container, you may get a response like “That can’t contain things,” for example.

Hmm.

If you say the cup is on the desk instead of carried by the player then “take pencils” works and you take them.

If you put another item in the room (A book is in Lab) then “take pencils” prompts the follow up “What do you want to take those things from?”

But if you start with the book on the desk then “take pencils” gives the response “There are none at all available!”

Regardless, “take pencil” always works.

It says it’s tripping the “exclude indirect possessions from take all rule.” Removing that rule makes it work but I’m not sure what other effects that would have.

1 Like

Maybe something like this would be safe enough?

Definition: a thing is plural-matched if it is listed in the multiple object list.

Definition: a thing is indirectly carried if (the player encloses it) and (the player does not carry it) and (it is not part of the player).

The exclude indirect possessions from take all rule does nothing when (the player's command matches the text "pencils") and (every plural-matched thing is a pencil) and (every plural-matched thing is indirectly carried).

A pencil is a kind of thing.


Lab is a room. 

A desk is a supporter in Lab.

A cup is a container carried by player.

3 pencils are in the cup.


See Bizarre trouble with taking items from a held container for a similar problem and a possible solution. [EDIT: Oops – wrong link when I first posted this. The now-correct link is to a post by mathbrush.]

This is related to the behavior that you called out in your last post. It happens for a pretty complicated reason, because there is a complex interaction of parsing features that drives the unexpected behavior. I very much agree that it feels like a bug, but my guess is that the official verdict would be “working as designed.”

To my knowledge, there is not a simple generic solution – mainly because author expectations differ about what constitutes “correct” behavior. However, it is usually possible to achieve a solution for any particular set of desired behaviors. Again, I’m asking: What specifically do you want the behavior to be?

2 Likes

Ideally, in this scenario, I’d like the pencils to move out of the cup and into the player’s (direct) inventory, with either a message or multiple messages saying that they’ve been taken. The same behavior you would get if the cup were on the desk and not in the player’s inventory would be fine.

If there are pencils that are indirectly held by the player and also pencils that are not in the player’s inventory at all, then I would want to prefer taking the pencils that are not in the player’s inventory. Or else maybe allow the players to specify somehow which pencils they mean.

It shouldn’t be possible to take pencils that are directly carried by the player.

More generally, I’ve got multiple sets of identical things in my game, so I’d like players to be able to manipulate them with as little hassle as possible when putting them into things, or putting them on things, or taking them. I don’t mind hard-coding special cases for the duplicate items if that’s necessary to minimize the risk of other problems.

1 Like

When you say “in this situation,” it sounds like you mean the specific pencils contained by a cup carried by the player scenario that you provided. The general case is things contained by a container enclosed by the player, which can’t be addressed by any specific features of the objects to be manipulated. You can keep trying to generate special cases, but it might be better to try to get at the root causes.

As you note, the “general case” in the previous paragraph is not exhaustive, because there can be more objects in scope that are identical to the enclosed items, and you want the behavior to prefer not-enclosed items. (Good news: That’s the default, effectively, by virtue of the enclosed ones being discarded when deciding whether all includes.)

You also mention the possibility of a response to >TAKE PENCILS that would prompt the player to revise the command to, e.g., >TAKE PENCILS FROM CUP versus >TAKE PENCILS FROM DRAWER. That would require a different understanding of the world by the parser than the template logic currently allows – not impossible, but a rewrite/expansion of some deep code.

Your phrase “as little hassle as possible” is a bit non-specific. Perhaps it would be helpful to construct a scenario of comparable complexity to that in your game and provide a transcript of the ideal behavior as you see it. The effort might (as it did for me) make some of the complications involved clearer.

In the meantime, to help make the problems more tractable, I’m pretty sure that the following deciding whether all includes rules replicate the underlying I6 template logic in its entirety (though as zarf notes in the other thread it would take exhaustive testing to prove that out):

Rule for deciding whether all includes something undescribed (this is the undescribed things are not included in all rule):
	it does not.

Rule for deciding whether all includes something worn by the person reaching (this is the worn things are not included in all rule):
	it does not.


Token type is a kind of value. The token types are noun token, held token, multi token, multiheld token, multiexcept token, multiinside token, creature token, special token, number token and topic token. [The ID for end tokens isn't contiguous and also isn't of interest here.]

To decide which token type is the current token context:
	(- ((line_tdata-->(pcount-1))+1) -). [perhaps not generically reliable, but seems OK for this]


Rule for deciding whether all includes something (called item) when current token context is listed in {multiheld token, multiexcept token} and item is not carried by the person reaching (this is the only carried things can be included in all for certain tokens rule):
	it does not.

Rule for deciding whether all includes (this is the generic all inclusion rule):
	it does. [As least specific, this will be invoked only if no other rule catches the case. It will always supersede the template logic.]

By using >RULES ALL and/or adding telltale output to the rules above, you should be able to observe how the system works more easily and add/adjust rules as you like to suit your purposes.

Ok, here is an imaginary transcript. I’m uncertain whether this is actually realistic, though.

Lab
You can see a sink (in which are five forks), a rug and a table (on which are a plate and a napkin) here.
[At the start of play, the player is carrying a box which contains 5 spoons]

>take spoons
spoon: You take a spoon out of the box.
spoon: You take a spoon out of the box.
spoon: You take a spoon out of the box.
spoon: You take a spoon out of the box.
spoon: You take a spoon out of the box.
[The player now carries all 5 spoons directly instead of in the box]

>take spoons
You already have those. [The only available spoons are already in direct inventory, so we won’t try to take any.]

>put 2 spoons in box
spoon: You take a spoon from your inventory and put it in the box.
spoon: You take a spoon from your inventory and put it in the box.
[The player now carries 3 spoons directly and 2 spoons indirectly, in the box]

>put 2 spoons in sink
[when putting things in containers or on supporters, spoons from direct inventory are preferred over spoons which are indirectly carried]
spoon: You take a spoon from your inventory and put it in the sink.
spoon: You take a spoon from your inventory and put it in the sink.
[The player now carries one spoon directly and 2 spoons in the box. Two spoons are now in the sink.]

>put 2 spoons in sink
[there aren’t enough spoons in direct inventory, so when we run out of spoons there, we’ll start using the ones in the box, as long as it’s open. We won’t try to put spoons in the sink that are already in the sink.]
spoon: You take a spoon from your inventory and put it in the sink.
spoon: You take a spoon from the box and put it in the sink.
[The player now carries no spoons directly and 1 spoon in the box. Four spoons are now in the sink.]

>take spoons
(from the sink) [when taking, reachable spoons not enclosed by the player are preferred over spoons that are enclosed by the player]
spoon: You take a spoon from the sink.
spoon: You take a spoon from the sink.
spoon: You take a spoon from the sink.
spoon: You take a spoon from the sink.
[The player now carries 4 spoons directly and 1 spoon in the box]

>put all in sink
You’ll have to be more specific about what you want to put in the sink.

>take 2 spoons from box
Only 1 spoon is in the box.
[No action taken.]

>put 2 spoons in box
spoon: You take a spoon from your inventory and put it in the box.
spoon: You take a spoon from your inventory and put it in the box.
[The player now carries 2 spoons directly and 3 spoons in the box.]

>put 2 spoons in sink
spoon: You take a spoon from your inventory and put it in the sink.
spoon: You take a spoon from your inventory and put it in the sink.
[The player now carries 3 spoons in the box. 2 spoons are in the sink.]

>take spoons
spoon: You take a spoon from the sink.
spoon: You take a spoon from the sink.
[The player now carries 2 spoons in direct inventory and 3 spoons in the box.]

>take spoons
spoon: You take a spoon from the box.
spoon: You take a spoon from the box.
spoon: You take a spoon from the box.
[The player now carries 5 spoons in direct inventory.]


If that’s not realistic, then I’d at least like to avoid responses that make no sense to the player.

Edit:

Here’s what I have now, which is not entirely working, but I’ll keep experimenting:

Lab is a room.

A fork is a kind of thing.

A knife is a kind of thing.

A spoon is a kind of thing.

A spoon can be shiny, average, or dull (this is the shine property). Understand the shine property as describing a spoon. The printed name of a spoon is "[shine] spoon". The printed plural name of a spoon is "[shine] spoons".


A sink is a fixed in place container in Lab.

A rug is an enterable supporter in Lab.

A table is a supporter in Lab.

A plate is a supporter on the table.

A box is a container carried by the player.

5 forks are in the box.

5 knives are in the sink.

5 spoons are in the box.


Every turn:
	say "Spoons carried directly by player: [number of spoons carried by the player][line break]";
	say "Spoons in the box: [number of spoons in box][line break]";
	say "Spoons in the sink: [number of spoons in the sink][line break]";
	

To decide which object is token-constraining item:
	(- advance_warning -).

To decide whether the noun text names (O - object):
	(- (Refers({O}, match_from)) -).
	

To decide if all the (L - a list of things) are enclosed by the player:
	repeat with item running through L:
		if item is not enclosed by the player:
			decide no;
	decide yes.
	

To decide if anything in (L - a list of things) is carried indirectly:
	repeat with item running through L:
		if item is indirectly carried:
			decide yes;
	decide no.


	
Definition: a thing (called T) is indirectly carried if (T is in a container (called C) and C is enclosed by the player) or (T is on a supporter (called S) and S is enclosed by the player).


Rule for deciding whether all includes something (called item) enclosed by the person reaching while taking or removing (this is the revised exclude indirect possessions from take all rule):
	if taking:
		say 1;
		if the noun text names item:
			say 2;
			let potential nouns be a list of things;
			now potential nouns is the multiple object list;
			if all the potential nouns are enclosed by the player:
				say 3;
				if item is indirectly carried:
					say 4;
					it does;
				otherwise: [item is either directly carried or part of the player]
					say 5;
					if anything in potential nouns is carried indirectly:
						say 6;
						it does not; [there's an indirectly carried thing available, so pick that instead]
					otherwise: [if the only options in the multiple object list are all carried by the player--or part of the player--choose that so we can reject it with a sensible error message, like "you already have that")]
						say 7;
						it does;
			otherwise:
				say 8;
				it does not; [When there are options not enclosed by the player, prefer those instead]
		otherwise:
			say 9;
			it does not; [don't allow "all" to work by itself]
	if removing:
		say "^";
		if the the token-constraining item contains the item:
			say "&";
			it does;
		otherwise:
			say "@";
			it does not.

The revised exclude indirect possessions from take all rule is listed instead of the exclude indirect possessions from take all rule in the for deciding whether all includes rules.

Rule for deciding whether all includes something (called item) contained by a portable container (called encloser) not enclosed by the player:
	if taking or removing:
		say "%";
		unless the noun text names item:
			say "#";
			it does not.
	

Test me with "take spoons / take spoons / put 2 spoons in box / put 2 spoons in sink / put 2 spoons in sink / take spoons / put all in  / 2 spoons from box / put 2 spoons in box / put 2 spoons in sink / take spoons / take spoons"

I know this is an infeasibly large change to the parser, but I’ve seen all sorts of bugs (as far as the author is concerned) arise over the years from the parser inferring missing nouns in opaque ways, and very few cases where the default behavior is what the author desires. I don’t think anyone would be too sad if it were cut out completely.

It would fix the unhelpful error messages here, make it impossible to interact with unscopable objects with a simple GET, but also just cut out a vast swath of bizarre error messages that make the parser seem dumber than it is. “> UNLOCK WARDROBE (with the wardrobe) That’s fixed in place.” gives new players a much worse impression than “> UNLOCK WARDROBE With what?”

3 Likes

I really think the answer is that the system should be improved. I’ve managed something that’s not too bad of an approximation of what bg is asking for.

Debugging-output-filled test transcript
Lab
You can see a sink (in which are five forks), a rug and a table (on which are a plate and a napkin) here.

>TAKE SPOONS
<raw context: multi><allow named enclosed items><spoon: YES>
<raw context: multi><allow named enclosed items><spoon: YES>
<raw context: multi><allow named enclosed items><spoon: YES>
<raw context: multi><allow named enclosed items><spoon: YES>
<raw context: multi><allow named enclosed items><spoon: YES>

spoon: You take a spoon from the box.
spoon: You take a spoon from the box.
spoon: You take a spoon from the box.
spoon: You take a spoon from the box.
spoon: You take a spoon from the box.

>TAKE SPOONS
<raw context: multi><special take rule><spoon: YES>
<raw context: multi><special take rule><spoon: YES>
<raw context: multi><special take rule><spoon: YES>
<raw context: multi><special take rule><spoon: YES>
<raw context: multi><special take rule><spoon: YES>

You already have those.

>PUT 2 SPOONS IN BOX
<raw context: multiexcept><included generically><spoon: YES>
<raw context: multiexcept><included generically><spoon: YES>

spoon: You take a spoon from your inventory and put it into the box.
spoon: You take a spoon from your inventory and put it into the box.

>PUT 2 SPOONS IN SINK
<raw context: multiexcept><included generically><spoon: YES>
<raw context: multiexcept><included generically><spoon: YES>

spoon: You take a spoon from your inventory and put it into the sink.
spoon: You take a spoon from your inventory and put it into the sink.

>PUT 2 SPOONS IN SINK
<raw context: multiexcept><included generically><spoon: YES>
<raw context: multiexcept><rejected context multiexcept token and location sink><spoon: NO>
<raw context: multiexcept><rejected context multiexcept token and location sink><spoon: NO>
<raw context: multiexcept><allowed context multiexcept token and location box><spoon: YES>

spoon: You take a spoon from your inventory and put it into the sink.
spoon: You take a spoon from the box and put it into the sink.

>TAKE SPOONS
<raw context: multi><included generically><spoon: YES>
<raw context: multi><included generically><spoon: YES>
<raw context: multi><included generically><spoon: YES>
<raw context: multi><included generically><spoon: YES>
<raw context: multi><override allow named enclosed items><spoon: NO>

spoon: You take a spoon from the sink.
spoon: You take a spoon from the sink.
spoon: You take a spoon from the sink.
spoon: You take a spoon from the sink.

>PUT ALL IN SINK
<raw context: multiexcept><included generically><spoon: YES>
<raw context: multiexcept><included generically><spoon: YES>
<raw context: multiexcept><included generically><spoon: YES>
<raw context: multiexcept><included generically><spoon: YES>
<raw context: multiexcept><included generically><box: YES>
<raw context: multiexcept><rejected context multiexcept token and location Lab><rug: NO>
<raw context: multiexcept><rejected context multiexcept token and location Lab><table: NO>
<raw context: multiexcept><rejected context multiexcept token and location sink><fork: NO>
<raw context: multiexcept><rejected context multiexcept token and location sink><fork: NO>
<raw context: multiexcept><rejected context multiexcept token and location sink><fork: NO>
<raw context: multiexcept><rejected context multiexcept token and location sink><fork: NO>
<raw context: multiexcept><rejected context multiexcept token and location sink><fork: NO>
<raw context: multiexcept><rejected context multiexcept token and location table><plate: NO>
<raw context: multiexcept><rejected context multiexcept token and location table><napkin: NO>
<raw context: multiexcept><rejected along for ride with box><spoon: NO>
<raw context: multiexcept><yourself: NO>
<raw context: multiexcept><rejected context multiexcept token and location Lab><sink: NO>

spoon: You take a spoon from your inventory and put it into the sink.
spoon: You take a spoon from your inventory and put it into the sink.
spoon: You take a spoon from your inventory and put it into the sink.
spoon: You take a spoon from your inventory and put it into the sink.
box: You take a box from your inventory and put it into the sink.

>TAKE ALL EXCEPT FORKS FROM SINK
<raw context: multi><sink: NO>
<raw context: multi><included generically><rug: YES>
<raw context: multi><table: NO>
<raw context: multi><included generically><box: YES>
<raw context: multi><rejected along for ride with box><spoon: NO>
<raw context: multi><included generically><spoon: YES>
<raw context: multi><included generically><spoon: YES>
<raw context: multi><included generically><spoon: YES>
<raw context: multi><included generically><spoon: YES>
<raw context: multi><included generically><fork: YES>
<raw context: multi><included generically><fork: YES>
<raw context: multi><included generically><fork: YES>
<raw context: multi><included generically><fork: YES>
<raw context: multi><included generically><fork: YES>
<raw context: multi><included generically><plate: YES>
<raw context: multi><included generically><napkin: YES>
<raw context: multi><yourself: NO>

<raw context: multiinside><included generically><box: YES>
<raw context: multiinside><included generically><spoon: YES>
<raw context: multiinside><included generically><spoon: YES>
<raw context: multiinside><included generically><spoon: YES>
<raw context: multiinside><included generically><spoon: YES>
<raw context: multiinside><included generically><fork: YES>
<raw context: multiinside><included generically><fork: YES>
<raw context: multiinside><included generically><fork: YES>
<raw context: multiinside><included generically><fork: YES>
<raw context: multiinside><included generically><fork: YES>
<raw context: multiinside><rejected along for ride with box><spoon: NO>

<raw context: multiinside><included generically><fork: YES>
<raw context: multiinside><included generically><fork: YES>
<raw context: multiinside><included generically><fork: YES>
<raw context: multiinside><included generically><fork: YES>
<raw context: multiinside><included generically><fork: YES>

box: You take a box from the sink.
spoon: You take a spoon from the sink.
spoon: You take a spoon from the sink.
spoon: You take a spoon from the sink.
spoon: You take a spoon from the sink.

>TAKE 2 SPOONS FROM BOX
"latest parser error" = command parser error: not enough of those available error
Only one of those is available.

>PUT 2 SPOONS IN BOX
<raw context: multiexcept><included generically><spoon: YES>
<raw context: multiexcept><included generically><spoon: YES>

spoon: You take a spoon from your inventory and put it into the box.
spoon: You take a spoon from your inventory and put it into the box.

>PUT 2 SPOONS IN SINK
<raw context: multiexcept><included generically><spoon: YES>
<raw context: multiexcept><included generically><spoon: YES>

spoon: You take a spoon from your inventory and put it into the sink.
spoon: You take a spoon from your inventory and put it into the sink.

>TAKE SPOONS
<raw context: multi><included generically><spoon: YES>
<raw context: multi><included generically><spoon: YES>
<raw context: multi><override allow named enclosed items><spoon: NO>
<raw context: multi><override allow named enclosed items><spoon: NO>
<raw context: multi><override allow named enclosed items><spoon: NO>

spoon: You take a spoon from the sink.
spoon: You take a spoon from the sink.

>TAKE SPOONS
<raw context: multi><allow named enclosed items><spoon: YES>
<raw context: multi><allow named enclosed items><spoon: YES>
<raw context: multi><allow named enclosed items><spoon: YES>
<raw context: multi><spoon: NO>
<raw context: multi><spoon: NO>

spoon: You take a spoon from the box.
spoon: You take a spoon from the box.
spoon: You take a spoon from the box.

There are probably still some lurking edge cases, but the progress made suggests that there might be more benefit obtained by refinement than demolition.

A word of caution: Your list potential nouns is unfortunately always evaluating to an empty list, as can be seen if you modify the relevant code to:

		...
		say 2;
		let potential nouns be a list of things;
		now potential nouns is the multiple object list;
		showme potential nouns; [ADDED]
		if all the potential nouns are enclosed by the player:
		...

The reason is that the Standard Rules phrase to retrieve the multiple object list depends on a value for the list’s length that is not updated until after the deciding whether all includes activity has been run on all applicable objects. The template logic backing the Standard Rules phrase thinks that the list has zero entries (or at least the number of entries it had before sifting through this cycle of matched objects) and ignores any entries being added during the period when the activity will be run.

I guess my question then is: what’s an example of a situation where inferring a missing noun gives a better result (from the author and player’s viewpoint) than asking for clarification? The main one I can think of is GET when there’s only one object around, but most modern players with the luxury of pronouns would say GET IT instead.

Even for cases like choosing a key to unlock with, the standard extensions for this (like Locksmith by Emily Short) have to deliberately bypass the inference machinery in order to give sensible results.

PUT TREASURE IN (the trophy case) is a reasonable target. If there’s one open container in scope, pick it. (Not that Inform does this, mind you.)

Might not work, depending on how the library handles pronouns. Is “it” the last thing the game referred to, or the last thing the player referred to? Inform leans towards the former but even then it’s not necessarily the sole portable object in scope.

(But it’s true that we’re comparing strategies with a significant failure rate! GET IT is probably a better bet than UNLOCK WARDROBE in most Inform games.)

ASK (guard) ABOUT DRAGON is a better example. Talking (and other animate actions) almost always can be phrased with or without the target name. If there’s exactly one person in scope, the library really should auto-target them. I think Inform is decent at this, due to the (otherwise hacky) creature grammar token.

That makes sense, but don’t most of the standard conversation extensions for Inform (Threaded Conversation, Conversation Framework) also hack around the library’s implementation to use their own “current interlocutor” instead?

I don’t know. :) I’m just thinking about the standard library and what its defaults should be. Extensions is too much.

Fair! The impression I get is that, in general, if people want to recognize commands missing nouns like ASK ABOUT CHEESE or UNLOCK CABINET, they do it by adding a separate action (like Locksmith’s “keylessly unlocking”) that supplies a useful default. The parser’s default is just so rarely correct, and the library (or extensions or author) can pretty much always do better—and, crucially, can give a much more useful error message.

Thanks for the heads up!

Here’s what I have now, which still does not entirely work, but it works somewhat:


To decide which object is token-constraining item:
	(- advance_warning -).


Rule for deciding whether all includes something (called item) enclosed by the person reaching while removing (this is the revised exclude indirect possessions from take all rule):
	if the the token-constraining item contains the item:
		it does;
	otherwise:
		it does not.

The revised exclude indirect possessions from take all rule is listed instead of the exclude indirect possessions from take all rule in the for deciding whether all includes rules.


Plural-taking is an action applying to one visible thing.

Understand "take [things]" and "get [things]" as plural-taking when (the player's command matches the text "knives") or (the player's command matches the text "forks") or (the player's command matches the text "spoons").

Definition: an object is plural-matched if it is listed in the multiple object list.

A multiple action processing rule when the current action is plural-taking (this is the taking duplicate items rule): 
	let potential sources be a list of objects;
	let reachable outside-the-player sources be a list of objects;
	let unreachable outside-the-player sources be a list of objects;
	let reachable in-inventory sources be a list of objects;
	let sample item be entry 1 in the multiple object list;
	repeat with item running through the multiple object list:
		let H be the holder of the item;
		add H to potential sources, if absent;
		if (H is not the player) and (H is not enclosed by the player):
			if H is a closed container:
				add H to unreachable outside-the-player sources, if absent;
			otherwise:
				add H to reachable outside-the-player sources, if absent;
		otherwise if H is enclosed by the player:
			if H is a supporter or H is an open container:
				add H to reachable in-inventory sources, if absent;
	[If there are reachable items outside the player's inventory, ignore the stuff in the player's inventory:]
	if reachable outside-the-player sources is not empty:
		let revised source list be a list of objects;
		add reachable outside-the-player sources to revised source list;
		add unreachable outside-the-player sources to revised source list;
		now potential sources is the revised source list;
		now reachable in-inventory sources is { };
		[now unreachable in-inventory sources is { };]
	if the player is listed in potential sources:
		[if all available items are directly carried by the player, reject the attempt to take]
		if the number of entries in potential sources is 1:
			say "The only [printed plural name of sample item] you see are ones you already have.";
			now potential sources is { };
		[if there are other options besides direct inventory, remove direct inventory from consideration:]
		otherwise:
			remove the player from potential sources;
	[If there is more than one open holder in inventory, ask the player to be more specific.]
	say 1;
	if the number of entries in reachable in-inventory sources > 1:
		say "There are [printed plural name of sample item] available from [reachable in-inventory sources with definite articles]. Try, for example, 'Take [printed plural name of sample item] from [entry 1 in reachable in-inventory sources].'";
		remove reachable in-inventory sources from potential sources, if present;
		now reachable in-inventory sources is { };
		[Since we're already spelling out the options rather than choosing one, also report on any containers that are closed at this time:]
		repeat with given holder running through potential sources:
			if the given holder is a closed container:
				let count be the number of plural-matched objects in the given holder;
				let capitalized count be "[count in words]" in title case;
				say "[Capitalized count] [printed plural name of sample item] [regarding count][are] in [the given holder], but [the given holder] [are] closed.";
		now potential sources is { };
	otherwise if the number of entries in reachable in-inventory sources is 1:
		say 2;
		repeat with given holder running through reachable in-inventory sources:
			repeat with item running through the multiple object list:
				if the holder of the item is the given holder:
					say "[item]: [run paragraph on]";
					silently try taking the item;
					if the player carries the item:
						if (the given holder is a container) or (the given holder is a supporter):
							say "You take [an item] from [the given holder].";
						otherwise:
							say "You take [an item].";
		now potential sources is { };		
	[Next we take any takeable items from sources outside of inventory:]
	say 3;
	repeat with given holder running through potential sources:
		if given holder is not a closed container:
			repeat with item running through the multiple object list:
				if the holder of the item is the given holder:
					say "[item]: [run paragraph on]";
					silently try taking the item;
					if the player carries the item:
						if (the given holder is a container) or (the given holder is a supporter):
							say "You take [an item] from [the given holder].";
						otherwise:
							say "You take [an item].";
	[Now report on the containers outside of inventory that are closed:]
	say 4;
	repeat with given holder running through potential sources:
		if the given holder is a closed container:
			let count be the number of plural-matched objects in the given holder;
			let capitalized count be "[count in words]" in title case;
			say "[Capitalized count] [printed plural name of sample item] [regarding count][are] in [the given holder], but [the given holder] [are] closed.";
	alter the multiple object list to { }.
	

A fork is a kind of thing.

A knife is a kind of thing.

A spoon is a kind of thing.

A doodad is a kind of thing.


Lab is a room.

An aquarium is a closed transparent container in Lab.
7 spoons are in the aquarium.

A sink is a fixed in place container in Lab.

A rug is an enterable supporter in Lab.

A table is a supporter in Lab.

A plate is a portable supporter on the table.

A box is a container carried by the player.

5 forks are in the box.

5 knives are in the sink.

5 spoons are in the box.

9 doodads are in the box.


Every turn:
	say italic type;
	say "Spoons carried directly: [number of spoons carried by the player][line break]";
	say "Spoons in box: [number of spoons in box][line break]";
	say "Spoons in sink: [number of spoons in the sink][line break]";
	say "Spoons on plate: [number of spoons on the plate][line break]";
	say "Spoons in aquarium: [number of spoons in aquarium][line break]";
	say roman type.
	


Test me with "look / take spoons / take spoons / put 2 spoons in box / put 2 spoons in sink / put 2 spoons in sink / take spoons / take 2 spoons from box / put 2 spoons in box / put 2 spoons on plate / take plate / take spoons".			

(Editing code to update it)

I came across this post: Intercept parser errors - #15 by Angstsmurf

When I add a similar rule, it seems to solve the problem where trying to take things from a carried container never works. (I’m using 6M62, in case that matters.)

Here’s what I have now, and at first glance it seems like it’s doing most of what I want:

[A rule from this thread: https://intfiction.org/t/intercept-parser-errors/46730/15]
Rule for deciding whether all includes things enclosed by the person reaching while taking (this is the new exclude indirect possessions from take all rule):
	it does not.

The new exclude indirect possessions from take all rule is listed instead of the exclude indirect possessions from take all rule in the for deciding whether all includes rulebook.



Plural-taking is an action applying to one visible thing.

Understand "take [things]" and "get [things]" as plural-taking when (the player's command matches the text "knives") or (the player's command matches the text "forks") or (the player's command matches the text "spoons").

Definition: an object is plural-matched if it is listed in the multiple object list.

Check plural-taking when the multiple object list is empty:
	try taking the noun instead.

A multiple action processing rule when the current action is plural-taking (this is the taking duplicate items rule): 
	let potential sources be a list of objects;
	let reachable outside-the-player sources be a list of objects;
	let unreachable outside-the-player sources be a list of objects;
	let reachable in-inventory sources be a list of objects;
	let sample item be entry 1 in the multiple object list;
	repeat with item running through the multiple object list:
		let H be the holder of the item;
		add H to potential sources, if absent;
		if (H is not the player) and (H is not enclosed by the player):
			if H is a closed container:
				add H to unreachable outside-the-player sources, if absent;
			otherwise:
				add H to reachable outside-the-player sources, if absent;
		otherwise if H is enclosed by the player:
			if H is a supporter or H is an open container:
				add H to reachable in-inventory sources, if absent;
	[If there are reachable items outside the player's inventory, ignore the stuff in the player's inventory:]
	if reachable outside-the-player sources is not empty:
		let revised source list be a list of objects;
		add reachable outside-the-player sources to revised source list;
		add unreachable outside-the-player sources to revised source list;
		now potential sources is the revised source list;
		now reachable in-inventory sources is { };
		[now unreachable in-inventory sources is { };]
	if the player is listed in potential sources:
		[if all available items are directly carried by the player, reject the attempt to take]
		if the number of entries in potential sources is 1:
			say "The only [printed plural name of sample item] you see are ones you already have.";
			now potential sources is { };
		[if there are other options besides direct inventory, remove direct inventory from consideration:]
		otherwise:
			remove the player from potential sources;
	[If there is more than one open holder in inventory, ask the player to be more specific.]
	say 1;
	if the number of entries in reachable in-inventory sources > 1:
		let sample source be entry 1 in reachable in-inventory sources;
		let all-caps source be "[sample source]" in upper case;
		say "There are [printed plural name of sample item] available from [reachable in-inventory sources with definite articles], and I'm not sure which ones you want. You could try, for example, TAKE [printed plural name of sample item in upper case] FROM [all-caps source].";
		remove reachable in-inventory sources from potential sources, if present;
		now reachable in-inventory sources is { };
		[Since we're already spelling out the options rather than choosing one, also report on any containers that are closed at this time:]
		repeat with given holder running through potential sources:
			if the given holder is a closed container:
				let count be the number of plural-matched objects in the given holder;
				[let capitalized count be "[count in words]" in title case;]
				say "[line break]There [regarding count][are] also [if count is 1][a sample item][otherwise][printed plural name of sample item][end if] in [the given holder], but [the given holder] [are] closed.";
		now potential sources is { };
	otherwise if the number of entries in reachable in-inventory sources is 1:
		say 2;
		repeat with given holder running through reachable in-inventory sources:
			repeat with item running through the multiple object list:
				if the holder of the item is the given holder:
					say "[item]: [run paragraph on]";
					silently try taking the item;
					if the player carries the item:
						if (the given holder is a container) or (the given holder is a supporter):
							say "You take [an item] from [the given holder].";
						otherwise:
							say "You take [an item].";
		now potential sources is { };		
	[Next we take any takeable items from sources outside of inventory:]
	say 3;
	repeat with given holder running through reachable outside-the-player sources:
		repeat with item running through the multiple object list:
			if the holder of the item is the given holder:
				say "[item]: [run paragraph on]";
				silently try taking the item;
				if the player carries the item:
					if (the given holder is a container) or (the given holder is a supporter):
						say "You take [an item] from [the given holder].";
					otherwise:
						say "You take [an item].";
	remove reachable outside-the-player sources from potential sources, if present;
	[Now report on any remaining closed containers: closed containers inside the inventory if there were no open ones in the inventory, and all closed containers outside inventory:]
	say 4;
	repeat with given holder running through potential sources:
		if the given holder is a closed container:
			let count be the number of plural-matched objects in the given holder;
			say "[line break]There [regarding count][are] [if count is 1][a sample item][otherwise][printed plural name of sample item][end if] in [the given holder], but [the given holder] [are] closed.";
	alter the multiple object list to { }.
	


To say take-the-forks:
	say "You're not [if the player encloses a fork]directly [end if]carrying any forks. If you want to do something with the forks as a group, try taking them first".
	
To say take-the-knives:
	say "You're not [if the player encloses a knife]directly [end if]carrying any knives. If you want to do something with the knives as a group, try taking them first".
	
To say take-the-spoons:
	say "You're not [if the player encloses a spoon]directly [end if]carrying any spoons. If you want to do something with the spoons as a group, try taking them first".




Understand "put forks in/into/inside/on/onto [text]" as a mistake ("[take-the-forks].") when (the player does not carry a fork) and (two forks are visible).

Understand "put [text] forks in/into/inside/on/onto [text]" as a mistake ("[take-the-forks].") when (the player does not carry a fork) and (two forks are visible).



Understand "put knives in/into/inside/on/onto [text]" as a mistake ("[take-the-knives].") when (the player does not carry a knife) and (two knives are visible).

Understand "put [text] knives in/into/inside/on/onto [text]" as a mistake ("[take-the-knives].") when (the player does not carry a knife) and (two knives are visible).



Understand "put spoons in/into/inside/on/onto [text]" as a mistake ("[take-the-spoons].") when (the player does not carry a spoon) and (two spoons are visible).

Understand "put [text] spoons in/into/inside/on/onto [text]" as a mistake ("[take-the-knives].") when (the player does not carry a spoon) and (two spoons are visible)


	
[I was trying to give a more helpful message than "You can't see any such thing" in these cases, but this code never seems to run:]

Understand "take [something] from [something]" as a mistake ("You don't see any such thing in [the second noun].") when the second noun is a container and the noun is not in the second noun.

Understand "take [things inside] from [thing]" as a mistake ("You don't see any such thing in [the second noun].") when the second noun is a container and the noun is not in the second noun.

Understand "take [thing] from [thing]" as a mistake ("You don't see any such thing on [the second noun].") when (the second noun is a supporter) and (the noun is not on the second noun).

Understand "take [things] from [thing]" as a mistake ("You don't see any such thing on [the second noun].") when (the second noun is a supporter) and (the noun is not on the second noun).


[This also  doesn't work:]
	
[Check removing something from something when the second noun is a container and the noun is not in the second noun:
	say "You don't see [the noun] in [the second noun]." instead.]
	
[Check removing something from something when the second noun is a supporter and the noun is not on the second noun:
	say "You don't see [the noun] in [the second noun]." instead.]



A fork is a kind of thing.

A knife is a kind of thing.

A spoon is a kind of thing.

A doodad is a kind of thing.


Lab is a room.

An aquarium is a closed transparent container in Lab.
7 spoons are in the aquarium.

A sink is a fixed in place container in Lab.

A rug is an enterable supporter in Lab.

A table is a supporter in Lab.

A plate is a portable supporter on the table.

A box is a container carried by the player.

5 forks are in the box.

5 knives are in the sink.

5 spoons are in the box.

9 doodads are in the box.


Every turn:
	say italic type;
	say "Spoons carried directly: [number of spoons carried by the player][line break]";
	say "Spoons in box: [number of spoons in box][line break]";
	say "Spoons in sink: [number of spoons in the sink][line break]";
	say "Spoons on plate: [number of spoons on the plate][line break]";
	say "Spoons in aquarium: [number of spoons in aquarium][line break]";
	say roman type.
	


Test me with "i / put spoons in sink / take spoons / take spoons / put 2 spoons in box / put 2 spoons in sink / put 2 spoons in sink / take spoons / take 2 spoons from box / put 2 spoons on plate / take plate / put 3 spoons in box / take spoons / take spoons from plate / take spoons from sink ".	

Feel free to point out anything that’s not working, dangerous, etc.

(I hear what you’re saying, OtisTDog, about addressing the root cause, but I’m not really sure how to do that.)

EDIT:

I’m editing way after the fact because there was a “like” on this post. I think I ended up having to make more changes to this code after doing some more testing. One thing was building in an exception for if a player uses numbers in a command–for example, “take 2 forks.” So if anyone decides to use some of this code, you should probably test that.

2 Likes

If you have something that’s working for you, then I think you should count it as good enough. The root problems here run pretty deep.