Bizarre trouble with taking items from a held container

My players have expressed frustration with a pizza box and a money envelope I have. The rules of Inform prohibit taking multiple copies of a ‘kind’ when the container they are in is held by the player.

This is the ‘exclude indirect possessions’ rule. Removing it causes bizarre behavior.

So, here’s a simple example:

"Sandbox" by Brian Rushton.

Parlor is a room.

The closet door is a door. It is north from parlor and south from Elsewhere.

The delivery box is a closed openable container. It is held by the player.

A pizza slice is a kind of thing. There are five pizza slices in the delivery box. 

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

The parser nothing error internal rule response (D) is "[The noun] [can't] contain things."

This gives the following gameplay:

>open box
You open the delivery box, revealing five pizza slices.
 
>take slices
The closet door can't contain things.
 
>get all slices
There are none at all available!
 
>get all from box
pizza slice: Taken.
pizza slice: Taken.
pizza slice: Taken.
pizza slice: Taken.
pizza slice: Taken.
 
> 

Edit: for some reason I can’t get the above transcript to happen again with the same code, but it can work (kind of) if typing TAKE SLICES twice.

Any clue what’s going on? This is in Inform 7, 6M62. If it’s a bug and already fixed in Inform 10, then I’ll leave it alone. But if there’s a way to fix it in Inform 7, 6M62, I’d love to know!

1 Like

Okay, it’s even weirder. Even if I don’t get rid of that rule, it still messes up:

"Sandbox" by Brian Rushton.

Parlor is a room.

The closet door is a door. It is north from parlor and south from Elsewhere.

The delivery box is a closed openable container. It is held by the player.

A pizza slice is a kind of thing. There are five pizza slices in the delivery box. 

The parser nothing error internal rule response (D) is "[The noun] [can't] contain things."

This gives similar results:

>take slices
The closet door can't contain things.

>get all from box
There are none at all available!

>get all slices
There are none at all available!

Edit:

The closet door doesn’t have to be a door, apparently it happens for any scenery object. So I tried making the closet an open container:

"Sandbox" by Brian Rushton.

Parlor is a room.

The closet is an open container in parlor.

The delivery box is a closed openable container. It is held by the player.

A pizza slice is a kind of thing. There are five pizza slices in the delivery box.

and got this result:

>open box

You open the delivery box, revealing five pizza slices.

>take slices

The closet is empty.

>showme closet

closet - open container

location: in Parlor

singular-named, improper-named; unlit, inedible, portable; opaque, open, unopenable, unlocked

list grouping key: none

printed name: "closet"

printed plural name: "containers"

indefinite article: none

description: none

initial appearance: none

carrying capacity: 100

>

It says the closet is empty but SHOWME CLOSET shows it’s open!

Editedit:

Looks like it’s connected to behavior described here:

My guess is it’s defaulting to the ‘remove’ action but interpreting the target of the ‘remove’ action as the held pizza box, since ‘GET SLICES FROM BOX’ works just fine.

1 Like

When using the first code you posted, I get this:

Sandbox
An Interactive Fiction by Brian Rushton
Release 1 / Serial number 231124 / Inform 7 build 6M62 (I6/v6.41 lib 6/12N) SD

Parlor
You can see a closet door here.

>open box
You open the delivery box, revealing five pizza slices.

>take slices
pizza slice: Taken.
pizza slice: Taken.
pizza slice: Taken.
pizza slice: Taken.
pizza slice: Taken.

>undo
Parlor
[Previous turn undone.]

>get all slices
pizza slice: Taken.
pizza slice: Taken.
pizza slice: Taken.
pizza slice: Taken.
pizza slice: Taken.

I get the same result in 6M62 or the current version.

2 Likes

I just noticed that. Try TAKE SLICES two times in a row to get behavior more like what I’m looking at, something messed up with my transcript.

1 Like

I’m having Baker of Shireton flashbacks: GET ALL DOUGH FROM OVEN.

Could you do a swap? Have a SLICED PIZZA in the box then “instead of taking a slice/pizza” put an off-stage slice in the player’s hand? That’s the kind of kludge I end up doing!

3 Likes

Hmm, that’s not a bad idea!

2 Likes

How about:

[note: doesn't work - see below] 
The exclude indirect possessions from take all rule does nothing when the particular possession is a pizza slice.

You can modify as appropriate with a definition to allow it to apply to multiple kinds.

EDIT: FYI for those coming across this later, there is an unintended side effect of this in that the command >TAKE ALL will have a tendency to remove the pizza slices from the delivery box, which may not be desirable.

EDIT 2: Note that the particular possession is not set correctly for this to work in the generic case, so the approach of trying to suppress the exclude indirect possessions... rule is not workable. However, a new decide whether all includes... rule that takes priority can be specified:

First rule for deciding whether all includes a pizza slice while taking or removing:
	it does.
3 Likes

I think this avoids most of the problems. It just doesn’t cover this one case:

"Sandbox" by Brian Rushton.

Parlor is a room.

The closet is scenery in parlor.

A pizza slice is a kind of thing. There are five pizza slices carried by the player.

The exclude indirect possessions from take all rule does nothing when the particular possession is a pizza slice.
>take slices

That can't contain things.

And what’s worse is the code parsing this is at an Inform 6 level, so doesn’t show up in rule tracing. I can only assume it’s something going wrong here:

if (etype == NOTHING_PE) {
	if (parser_results-->ACTION_PRES == ##Remove &&
    	parser_results-->INP2_PRES ofclass Object) {
    	noun = parser_results-->INP2_PRES; ! ensure valid for messages
        if (noun has animate) { PARSER_N_ERROR_INTERNAL_RM('C', noun); new_line; }
        else if (noun hasnt container or supporter) { PARSER_N_ERROR_INTERNAL_RM('D', noun); new_line; }
        else if (noun has container && noun hasnt open)  { PARSER_N_ERROR_INTERNAL_RM('E', noun); new_line; }
        else if (children(noun)==0) { PARSER_N_ERROR_INTERNAL_RM('F', noun); new_line; } ! <---  HERE
        else parser_results-->ACTION_PRES = 0;
    }
    if (parser_results-->ACTION_PRES ~= ##Remove) {
        if (multi_wanted==100) { PARSER_N_ERROR_INTERNAL_RM('A'); new_line; }
        else                  {  PARSER_N_ERROR_INTERNAL_RM('B'); new_line; }
    }
}

This is reminding me of Jim Aikin’s hamster problem. I think it has a similar cause; it has to do with the “most interesting” error that develops as parsing fails (before the part you posted).

I think it’s fixable, but I won’t have time to try until later. If someone else doesn’t come along before then, I’ll see what I can do.

2 Likes

Thansk! If not, I’ll probably use Hanon’s suggestion. For now I’ve patched it like so:

The parser nothing error internal rule response (D) is "[bracket]Inform has difficulty understanding what you want when grabbing multiple similar items. You may need to specify where you are taking them from, like GET SLICES FROM BOX or GET BILLS FROM ENVELOPE.[close bracket]"

1 Like

One pizza with extra kludge:

Understand "pizza/-- slices" and "pizza" as a pizza slice.

check taking a pizza slice (this is the you can't have all the pizza rule):
    if delivery box does not contain a pizza slice:
        say "The pizza's all gone, dude." instead;
    otherwise:
        let P be a random pizza slice in delivery box;
        try taking P instead;
2 Likes

Just to make sure that I understand what you’re after…

When the player has the box, you want output like:

holding box
>[1] open box
You open the delivery box, revealing five pizza slices.

>[2] take slices
pizza slice: Taken.
pizza slice: Taken.
pizza slice: Taken.
pizza slice: Taken.
pizza slice: Taken.

>[3] take slices
pizza slice: You already have that.
pizza slice: You already have that.
pizza slice: You already have that.
pizza slice: You already have that.
pizza slice: You already have that.

>[4] put slices in box
pizza slice: Done.
pizza slice: Done.
pizza slice: Done.
pizza slice: Done.
pizza slice: Done.

>[5] take slices from box
pizza slice: Taken.
pizza slice: Taken.
pizza slice: Taken.
pizza slice: Taken.
pizza slice: Taken.

>[6] take slices from box
You can't see any such thing.

>[7] put slices in box
pizza slice: Done.
pizza slice: Done.
pizza slice: Done.
pizza slice: Done.
pizza slice: Done.

>[8] take all
There are none at all available!

>[9] take all
There are none at all available!

>[10] take all from box
pizza slice: Taken.
pizza slice: Taken.
pizza slice: Taken.
pizza slice: Taken.
pizza slice: Taken.

and when the player does not have the box, you want output like:

not holding box
>[1] drop box
Dropped.

>[2] open box
You open the delivery box, revealing five pizza slices.

>[3] take slices
pizza slice: Taken.
pizza slice: Taken.
pizza slice: Taken.
pizza slice: Taken.
pizza slice: Taken.

>[4] take slices
pizza slice: You already have that.
pizza slice: You already have that.
pizza slice: You already have that.
pizza slice: You already have that.
pizza slice: You already have that.

>[5] put slices in box
pizza slice: Done.
pizza slice: Done.
pizza slice: Done.
pizza slice: Done.
pizza slice: Done.

>[6] take slices from box
pizza slice: Taken.
pizza slice: Taken.
pizza slice: Taken.
pizza slice: Taken.
pizza slice: Taken.

>[7] take slices from box
You can't see any such thing.

>[8] put slices in box
pizza slice: Done.
pizza slice: Done.
pizza slice: Done.
pizza slice: Done.
pizza slice: Done.

>[9] take all
delivery box: Taken.

>[10] take all
There are none at all available!

>[11] take all from box
pizza slice: Taken.
pizza slice: Taken.
pizza slice: Taken.
pizza slice: Taken.
pizza slice: Taken.
2 Likes

Yes, that covers even more use cases than I had anticipated.

OK. There are a lot of things that contribute to this odd behavior, and it took a while to figure out how to thread the needle.

Pizza Delivery II
"Pizza Delivery II"

Parlor is a room.

The closet door is a door. It is north from parlor and south from Elsewhere.

The delivery box is a closed openable container. It is held by the player.

A pizza slice is a kind of thing. There are five pizza slices in the delivery box. 

The plural of pizza slice is slices of pizza.

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

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

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:
		if the noun text names item:
			it does;
		otherwise:
			it does not;
	if removing:
		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.

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:
		unless the noun text names item:
			it does not.

Test me with "open box / take slices / take slices / put slices in box / take slices from box / take slices from box / put slices in box / take all / take all / take all from box".

Test dropped with "drop box / open box / take slices / take slices / put slices in box / take slices from box / take slices from box / put slices in box / take all / take all / take all from box".

[some additional items to test that the above is working generically]

A rock is a kind of thing.

A bucket is here. Five rocks are in the bucket.

Anything more refined (at least, anything more refined that I could come up with) requires I6 hacking on a bigger scale.

If this doesn’t work for you or you find bugs, let me know.

2 Likes

I tried popping it in my code for my long game. I ran through a TEST ME of the entire game, and then tried specifically messing with the pizza, and it worked. Thanks! I’ll include it, and I’ll put you in the credits. I have you in there now as ‘otistdog’; would you prefer that to be changed?

1 Like