Hybrid container/supporter and darkness modeling [I7]

I have a hybrid container/supporter that I want the PC to be able to climb on top of:

A trash canister is a kind of container. A trash canister is always openable. A trash canister is usually closed. 

A lid is a kind of supporter. A lid is part of every trash canister. A lid is always enterable.

Alley is a room. The dumpster is a trash canister in Alley.

Aside from the “enterable” declaration, this is largely cribbed from the Inform Recipe Book # 58, “U-Stor-It.” (And I have eliminated a lot of the extra code that’s irrelevant here.) But making the lid enterable exposes a limitation of the modeling’s granularity in this case:

>stand on lid
You get onto the dumpster's lid.

It is now pitch dark in here!

This is of course not ideal.

I understand that Inform doesn’t realize that this is a part on the outside of the thing that it’s a part of, so it just applies the visibility rules in the same way as it would for anything else that was inside the container. I’m just not sure what to do in response to that. Making the lid lit would be an easy solution, but since the dumpster can be pushed into a darkened garage, it won’t work here. Is there a rule I can hook into somewhere that lets me override decisions about lighting?

Quick’n’dirty suggestion: What if you make the container part of the supporter rather than vice versa?

2 Likes

Or a better quick and dirty suggestion: Make the dumpster a thing that has a container and supporter as separate parts. This will require a fair amount of work with printed names and redirection to make sure that when you open the dumpster you’re opening the interior, etc. etc., but you already have to do some of that. It’s probably better to take an approach like this that works with the world model, so Inform doesn’t think the lid is inside the container, and fix the commands and output, rather than try to fake things around the world model.

A trash canister is a kind of thing. A trash canister is usually fixed in place and pushable between rooms.

A canister interior is a kind of container. A canister interior is part of every trash canister. A canister interior is always openable. A canister interior is usually closed. 

A lid is a kind of supporter. A lid is part of every trash canister. A lid is always enterable.

Alley is a room. The dumpster is a trash canister in Alley.

Garage is north of alley. Garage is dark.

The player carries a torch. The torch is lit.

I tried writing a rule to calculate whether the lid should be lit but it did not do well with the case where the room was dark, the dumpster was closed, and there was a light source in the dumpster; when the player is on the lid they can still see the light source, and when they get off, they get the room description before the adjust light rule runs and everything goes dark. In general trying to override the lighting rules seems like it would be very messy unless you really know your Inform 6!

In case you want to see it
A trash canister is a kind of container. A trash canister is always openable. A trash canister is usually closed. 

A trash canister is usually fixed in place and pushable between rooms.

A lid is a kind of supporter. A lid is part of every trash canister. A lid is always enterable.

Alley is a room. The dumpster is a trash canister in Alley.

Garage is north of alley. Garage is dark.

The player carries a torch. The torch is lit.

This is the calculate light for lids rule:
	if the player is on a lid (called the platform):
		let the hull be a random trash canister incorporating the platform;
		if the location of the hull is lighted:
			now the platform is lit;
		otherwise if the hull can see a lit non-lid that is not enclosed by the hull:
			now the platform is lit;
		otherwise if the hull can see a lit non-lid [enclosed by the hull] and the hull is open:
			now the platform is lit;
		otherwise:
			now the platform is not lit;
	otherwise: [the player is not on a lid so we reset the lighting status]
		now every lid is not lit.
			
The calculate light for lids rule is listed before the adjust light rule in the turn sequence rulebook.

Definition: a thing is non-lid if it is not a lid.
2 Likes

Even quicker and dirtier: create the container and supporter (lid) as separate objects which just happen to be in the same room. Then you don’t have to worry about a third object that has to redirect every action to one or the other.

The only wrinkle is if the dumpster is mobile; then you’d have to be careful to move the two objects in parallel. If the thing is fixed in place, this really is the easiest solution.

3 Likes

I figured that the dumpster was mobile, since it could be pushed into a darkened room–but I guess one way to use my solution and partially address the redirection problem might be to make the parent object privately-named (and excluded from all). If the player can’t name it and can’t interact with it, then you don’t have to worry as much about redirecting it.*

You’d still have to take care of redirecting opening the lid to opening the container, and putting something on the container to putting it on the lid, but you have to take care of it no matter what you do (and I assume that’s part of what you’re getting from the U-Stor-It code).

*This is reminding me of a comment in my Cragne Manor room code, “since it’s privately-named and scenery the player can’t interact with it at all,” whereupon somebody else made a thing that interacted with a random object and could pick that thing out. Which was too bad, because I’d set the printed name to include a message about how you should never see anything about this and should email me to explain what happened. But this is not a problem you have to worry about in most projects!

2 Likes

The rules seem to be inconsistent about this. The lid itself is viewable from outside the dumpster, as are any things placed on it. The general idea, as I understand it, is that parts of things are assumed to be on the exterior, which is why you need to use concealed possessions rules to hide them.

1 Like

It is extremely difficult to get this 100% reliable in Inform!

You might write:

The Kitchen is a room.

The elephant is privately-named scenery in the Kitchen.

Rule for deciding whether all includes the elephant: it does not.

Which results in:

>get elephant
You can't see any such thing.

>get all
There are none at all available!

>get
(the elephant)
That's hardly portable.

Oops. Well, how about we add:

Does the player mean doing something to the elephant:
	it is very unlikely.

Then…

>get elephant
You can't see any such thing.

>get
What do you want to get?

>get all
There are none at all available!

>put me in
(the elephant)
(first taking yourself)
You are always self-possessed.

Dammit.

Then there’s the chance of the elephant becoming “it” if the room description mentions it (allowing GET IT to refer to the elephant). And, as you say, game logic that selects a random object.

This is why my general advice is that if you don’t want the player to refer to an object, keep it off-stage. But for the dumpster example, you have a collection of parts and it’s important to keep them together. So creating a parent object might be the best solution. In that case, I recommend writing a description and some rules for it even if you’re really sure that the player will never refer to it.

4 Likes

And in fact, if we do:

A trash canister is a kind of thing. A trash canister is usually fixed in place and pushable between rooms.

A canister interior is a kind of container. A canister interior is part of every trash canister. A canister interior is always openable. A canister interior is usually closed. 

A lid is a kind of supporter. A lid is part of every trash canister. A lid is always enterable.

Alley is a room. The dumpster is a trash canister in Alley.

we get

Alley
You can see a dumpster here.

get on lid
You get onto the dumpster’s lid.

look
Alley (in the dumpster)

so the dumpster shows up in the room heading. So this would require being careful about the room heading (which is something you’d need to do anyway, I guess, because “on the dumpster’s lid” seems less than ideal too).

2 Likes

Yeah, it looks to me as though the difference is in the routine for calculating what a non-player thing can see and what a player can see. From Appendix B (this is a few Inform versions ago but I think still current):

§7. Visibility Parent. The idea of VisibilityParent is that it takes us from a given position in the object
tree, o, to the next visible position above. Note that
(1) A container has an inside and an outside: this routine calculates from the “inside of o”, which is why it returns nothing from an opaque closed container;
(2) Component parts are (for purposes of this routine) attached to the outside surface of a container, so
that if o is part of a closed opaque container then the visibility parent of o is its actual parent.

§9. Scope Ceiling. Scope is almost the same thing as visibility, but not quite, and the following routine
does not quite duplicate the calculation of FindVisibilityLevels. The difference arises in the first step, where we take the parent of pos, not the core of the parent of the core of pos: this makes a difference if pos is inside a container which is itself part of something else.

VisibilityParent is the first step in the calculation of FindVisibilityLevels.

I think what this means is:
When there’s a rock on the lid and the player is in the location, whether the player can see the rock is determined by using VisibilityParent for the rock, which uses a relation that (per an earlier comment in Appendix B) contracts together all nodes in the object tree where one thing is a component of another. So it goes rock -> lid -> room, skipping over the dumpster since the lid is part of it.

When the player is on the lid and the rock is in the room, the player’s visibility is determined by using ScopeParent, which doesn’t skip parts in this way. So it goes player -> lid -> dumpster and stops there, since the dumpster is closed and opaque.

You can also see that if you give the player a light source and go onto the lid, the room description heading becomes “The Dumpster” and the player can’t see anything in the room.

I’m not sure why it should be like this, though? Enterable containers that are part of things seem to get messed up, unless I coded it wrong:

Alley is a room. A pickup truck is in Alley. A bed is a closed openable opaque enterable container. The bed is part of the pickup truck.

The player carries a rock and a torch. The torch is lit.

yields

Alley
You can see a pickup truck here.

>open bed
You open the bed.

>put rock in bed
You put the rock into the bed.

>close bed
You close the bed.

>look
Alley
You can see a pickup truck here.

>open ed
You can't see any such thing.

>open bed
You open the bed, revealing a rock.

>look
Alley
You can see a pickup truck here.

>take rock
Taken.

>drop it
Dropped.

>enter bed
You get into the bed.

>look
Alley (in the pickup truck)
You can see a rock here.

>close bed
You close the bed.

>look
Alley (in the pickup truck)
You can see a rock here.

>showme me
yourself - person
    torch
location: in the bed , which is part of the pickup truck in Alley
singular-named, proper-named; unlit, inedible, portable; male
list grouping key: none
printed name: "yourself"
printed plural name: "people"
indefinite article: none
description: "As good-looking as ever."
initial appearance: none
carrying capacity: 100

>out
You can't get out of the closed bed.

At the end when I’m in the closed bed, I shouldn’t be able to see the rock and the Alley shouldn’t be the visibility ceiling, it seems.

EDIT: Curiouser and curiouser:

>look
Alley (in the pickup truck)
You can see a rock here.

>get rock
You can't see any such thing.
1 Like

I reported this particular container behavior as a bug.

1 Like

Well, here I am coming back online after having a day-long Internet service outage and discovering that what I thought was a simple problem that I just can’t quite wrap my head around is more complex than I assumed it would be. I’m always fascinated by emergent complexity affecting what seems like it “should be” a simple problem.

I appreciate everyone’s suggestions, and I’m going to play with them. My initial thought is that I may just take @zarf’s first suggestion–two items, neither part of the other–and keep the dumpster from being pushable between rooms after all. It’s a minor thing to do, and I can always silently hand-wave another object called “the dumpster” into existence in the garage and have rules to say, perhaps, “But the ceiling is too low!” if the player tries to open the lid inside … or otherwise try to treat the problems as design problems rather than technical problems.

Again, many thanks to everyone!

The short answer is that this sort of works, and was in fact the first thing I tried, but due to a number of interactions with other objects that didn’t make it into this simplified sample, the redirection rules got pretty baroque. (There was an awful lot of Instead of entering the canister's bin when the player wears the melodeon ...-type things going on.) I was trying to simplify by inverting which item was a part of which other item. The relevant rules became much simpler, but then there was of course the darkness problem. No such thing as a free lunch, I suppose.

It’s a good solution to the simplified version that I posted here, but doesn’t happen to work in the more complex project that the simple solution was abstracted from. :slight_smile: Of course, who could have seen that from the simplified code sample?

Many thanks. :slight_smile:

FWIW, I tried changing “parent” to “CoreOfParentOfCoreOf” in the ScopeParent routine and it didn’t solve the problem–it’s still dark when the player is on the lid. I don’t know if that means my original diagnosis was wrong.

So it looks to me as though the choices are probably:

  1. Find a person who knows how the darkness routines work, or figure it out yourself, and modify them so they do what they want
  2. Deal with the baroque redirects
  3. Make it a design problem and make sure the player never gets on the lid in a dark room, or whatever

…very much in ascending order of desirability.

1 Like

You may have that backward: VisibilityParent uses CoreOfParentOfCoreOf, so the chain would be rock -> dumpster -> nothing. ScopeCeiling uses parent for the first link, and then VisibilityParent for the rest of the chain, so it would go rock -> lid -> Alley -> nothing, and decide on Alley.

The rationale seems to be a container that is part of something else, like a drawer that is part of a desk. If X is in the drawer, then its parent is the drawer but CoreOfParentOfCoreOf(X) is the desk.

I wrote this code to check my understanding of how VisibilityParent works:

To decide which object is the visparent of (X - an object): (- VisibilityParent( {X} ) -).

Snagging is an action applying to one visible thing.

Understand "snag [anything]" as snagging.

Carry out snagging:
	let o be the noun;
	while o is not nothing:
		say "[o].";
		now o is the visparent of o;

Using this, you can see how the chains produced for the lid and the rock are different:

>put rock on lid
(first taking the rock)
You put the rock on the dumpster's lid.

>snag rock
rock.
dumpster.

>snag lid
dumpster's lid.
Alley.

I would think that VisibilityParent should use something like ParentOfCoreOf, so that the rock would not be considered inside the dumpster.

Here are two other weird behaviors:

>enter lid
You get onto the dumpster's lid.

On the dumpster's lid you can see a rock.

It is now pitch dark in here!

>x rock
You can't see any such thing.

>exit
You get off the dumpster's lid.

Darkness
It is pitch dark, and you can't see a thing.

Alley
You can see a dumpster (closed) and a desk here.

We get the message about what’s on the lid before being plunged into darkness, at which point the rock cannot be seen, but when we leave the lid we get two location headers.

I also tried creating a desk (supporter) incorporating a drawer, and a portable platter (supporter). I was trying to understand how scope works, so I made the drawer and platter enterable. This is some of the result:

>put platter in drawer
You put the platter into the drawer.

>enter platter
(getting onto the desk)
That's not something you can enter.

>enter drawer
You get into the drawer.

In the drawer you can see a platter.

>enter platter
You get onto the platter.

>exit
You get off the platter.

Alley (on the desk)
You can see a dumpster (closed) here.

I think I understand why some of this is happening, and it comes down to the collapsed tree that contracts all the components of a thing into a thing. This leads to an inconsistency where components are considered siblings of their core, but children of components are treated as children of the core.

A lot of this might be solved by treating components more like siblings in the object tree. The contents of a desk drawer should not be considered to be on the desk.

2 Likes

Huh, that two location headers thing reminds me of this old fixed bug where exiting a dark container would print two spurious location headers in the same way. Some of this may be light being recalculated at the wrong time, or not being recalculated at the right time.

1 Like

I keep coming back to the line in Appendix B that says the scope ceiling is calculated differently from the visibility ceiling, but does not explain why. If I had to guess, it’s trying to patch these weird behaviors that are ultimately caused by a mismatch in the world model.

Consider this:

>open dumpster then put orb in dumpster then close dumpster
You open the dumpster.

You put the glow orb into the dumpster.

You close the dumpster.

>put rug on lid
You put the rug on the dumpster's lid.

>stand on lid
You get onto the dumpster's lid.

On the dumpster's lid you can see a rug.

>l
The dumpster
In the dumpster you can see a glow orb.

>x orb
You can't see any such thing.

>x rug
You see nothing special about the rug.

>x lid
On the dumpster's lid is a rug.

>stand on rug
You get onto the rug.

>l
The dumpster (on the rug)
In the dumpster you can see a glow orb.

>x orb
You see nothing special about the glow orb.

>x rug
You can't see any such thing.

>x lid
You can't see any such thing.

>exit
You get off the rug.

The dumpster
In the dumpster you can see a glow orb.

>exit
You can't get out of the closed dumpster.

When standing on the lid, I can examine the lid and the rug, but not the glow orb. However, the glow orb inside the dumpster prevents the lid from being in darkness. and look acts as though I am inside the dumpster.

When standing on the rug (on the lid), I can examine the orb, but not the lid or the rug. Look acts as though I and the rug are inside the dumpster.

When I exit the rug, I enter the dumpster itself, not the lid. (Note that the dumpster is closed and not enterable.)

4 Likes