I7: Undersides, Visibility Levels, and Scope/Concealment

There are a few things I’ve been having trouble with for a long time, and as I am currently working on something that involves both of these issues it seemed like a good time to ask for some help on the problems.

I was working on some code for containers or supporters intended to simulate an “empty space” underneath these objects if such is desired. There is a fine extension on the Inform website, “Underside” by Eric Eve, that does this already; however since for various reasons I’m not interested in using that extension, I decided to make my own. I’m mostly finished and happy with the way the code below works:

Chapter 1 - Support Code

[not directly relevant to the matter at hand, but needed for the sample code to work as intended]

Include Plurality by Emily Short.

Rule for deciding whether all includes scenery:  it does not.
Rule for deciding whether all includes something fixed in place:  it does not.

Use full-length room descriptions.

Rule for printing room description details: stop.

Bulk is a kind of value.  The bulks are microsize, smallsize, cupsize, gallonsize, bagsize, suitcasesize, bathtubsize, bedsize, closetsize, shedsize, roomsize, and megasize.

A thing has a bulk.  A thing is usually smallsize.  A person is usually bathtubsize.

Before an actor inserting something into something (this is the sizecheck for inserting rule):
	if the actor is the player:
		if the bulk of the noun is greater than the bulk of the second noun:
			say "[The noun] [is-are] too big to fit into [the second noun]." instead;
	otherwise:
		if the player can see the actor:
			if the bulk of the noun is greater than the bulk of the second noun:
				say "[The actor] looks at [the noun], looks at [the second noun], and shakes [if the actor is male]his[otherwise if the actor is female]her[otherwise]its[end if] head." instead;
		otherwise:
			if the bulk of the noun is greater than the bulk of the second noun:
				stop the action.

Before an actor entering a container (this is the sizecheck for entering rule):
	if the actor is the player:
		if the bulk of the player is greater than the bulk of the noun:
			say "You can't fit into [the noun]." instead;
	otherwise:
		if the player can see the actor:
			if the bulk of the actor is greater than the bulk of the noun:
				say "[The actor] looks at [the noun] and shakes [if the actor is male]his[otherwise if the actor is female]her[otherwise]its[end if] head." instead;
		otherwise:
			if the bulk of the actor is greater than the bulk of the noun:
				stop the action.

A container is usually openable.  A container is usually closed.

Rule for printing room description details of a container (called UE) (this is the intermediate casual container looking rule):
	if UE is open or UE is transparent:
		unless UE contains a person:
			omit contents in listing;
		otherwise:
			let heldones be a list of things;
			repeat with sittas running through things in UE:
				if sittas is a person:
					add sittas to heldones;
			say " (in which [is-are] [heldones])";
			omit contents in listing;
	otherwise:
		continue the activity.

Report examining a container which contains something (this is the after xing a container rule):
	if the noun is open or the noun is transparent:
		say "In [the noun] [is-are] [list of things in the noun with indefinite articles].".

Rule for printing room description details of a supporter (called UQ) (this is the better supporter looking rule):
	if UQ does not support a person:
		omit contents in listing;
	otherwise:
		let loungers be a list of things;
		repeat with T running through things on UQ:
			if T is a person and the player can see T:
				add T to loungers;
		say " (on which [is-are] [loungers])";
		omit contents in listing.

Chapter 2 - Undersides

[This code is what was intended to be discussed in this thread]

Section 1 - What they are

An underside is a kind of container.  An underside is usually open and not openable.  The printed name of an underside is usually "[the holder of the item described]".  The bulk of an underside is usually bathtubsize.  An underside is usually scenery.  An underside is usually privately-named.  An underside is usually enterable.

The specification of an underside is "A conceptual representation of the spatial area underneath a thing.".

Section 2 - Miscellaneous Rules for Undersides

Report examining a supporter (called xedsup) which supports something (this is the after xing a supporter rule):
	unless the player is in an underside incorporated by xedsup:
		say "On [the noun] [is-are] [list of things on the noun with indefinite articles].".

Check looking under something:
	unless the noun incorporates an underside:
		say "You don't find anything of interest under [the noun]." instead;
	otherwise:
		let redir be a random underside incorporated by the noun;
		try searching redir instead.

Rule for deciding whether all includes something in an underside: it does not.

Instead of an actor examining an underside:
	try the actor searching the noun.

Procedural rule for an actor searching an underside: ignore the standard search containers rule.

Report searching an underside (this is the after xing an underside rule):
	if the noun is open:
		if the noun contains anything:
			say "Under [the holder of the noun] [is-are] [list of things in the noun with indefinite articles].";
		otherwise:
			say "You don't find anything unusual under [the holder of the noun].";
	otherwise:
		say "You don't find anything unusual under [the holder of the noun]."..

Check an actor taking an underside:
	if the actor is the player:
		say "You can't take a 'space.'" instead;
	otherwise:
		if the player can see the actor:
			say "[The actor] ignores your nonsensical request." instead;
		otherwise:
			stop the action.

Report an actor searching something that incorporates an underside (this is the thorough search of things with undersides rule):
	try the actor searching a random underside that is incorporated by the noun.

Carry out taking something that incorporates an underside (called curunder) (this is the addon taking something with an underside rule):
	if curunder is open and curunder contains anything:
		let undalist be a list of things;
		repeat with revealedstuff running through things in curunder:
			add revealedstuff to undalist;
			move revealedstuff to the holder of the noun;
		say "As you take [the noun], you reveal [undalist with indefinite articles] that [if the number of entries in undalist is 1]was[otherwise]were[end if] underneath it.".

After looking while the holder of the player is an underside (called curunder) (this is the thorough looking from an underside rule):
	try searching curunder;
	continue the action.

Section 3 - Putting into and Taking from Undersides

Putting it under is an action applying to two things and requiring light.  Understand "put [something] under/underneath/beneath [something]" as putting it under.  Understand "drop [something] under/beneath/underneath [something]" as putting it under.  Understand "place [something] under/underneath/beneath [something]" as putting it under.  Understand "move [something] under/underneath/beneath [something]" as putting it under.  Understand "hide [something] under/underneath/beneath [something]" as putting it under.

The specification of the putting it under action is "A courtesy redirect action for putting things into an 'underside' container.".

Instead of an actor putting something under something (this is the simulate putting under rule):
	if the second noun incorporates an underside:
		let curunder be a random underside incorporated by the second noun;
		if the noun is curunder or the second noun is curunder:
			if the player can see the actor:
				say "That's irrational.";
			otherwise:
				stop the action;
		otherwise:
			unless the noun is in curunder:
				if the bulk of the noun is greater than the bulk of curunder:
					if the player can see the actor:
						say "[The noun] is too big to fit under [the holder of curunder].";
					otherwise:
						stop the action;
				silently try the actor inserting the noun into curunder;
				if the noun is in curunder:
					if the player can see the actor:
						say "[if the actor is the player]You place[otherwise][The actor] places[end if] [the noun] under [the second noun].";
					rule succeeds;
				otherwise:
					rule fails;
			otherwise:
				if the player can see the actor:
					say "[The noun] is already under [the second noun].";
				otherwise:
					stop the action;
	otherwise:
		unless the noun is the second noun:
			if the player can see the actor:
				say "That's impractical in this case." instead;
			otherwise:
				stop the action;
		otherwise:
			say "That's irrational.".

Removing it from under is an action applying to two things and requiring light.  Understand "get [something] from under/underneath/beneath [something]" as removing it from under.  Understand "take [something] from under/underneath/beneath [something]" as removing it from under.  Understand "pull [something] from under/underneath/beneath [something]" as removing it from under.  Understand "remove [something] from under/underneath/beneath [something]" as removing it from under.

The specification of the removing it from under action is "A courtesy redirect action for retrieving things from an 'underside' container.".

Before an actor removing something from under something (this is the simulate removing from under rule):
	if the second noun incorporates an underside:
		let curund be a random underside incorporated by the second noun;
		unless the noun is in curund:
			if the player can see the actor:
				say "[The noun] isn't under [the second noun]." instead;
			otherwise:
				stop the action;
		otherwise:
			try the actor taking the noun instead;
	otherwise:
		if the player can see the actor:
			say "There isn't anything under [the second noun]." instead;
		otherwise:
			stop the action.

Section 4 - Entering and Exiting Undersides

Crawling under is an action applying to one thing.  Understand "get under/underneath/beneath [something]" or "crawl under/underneath/beneath [something]" or "hide under/underneath/beneath [something]" or "move under/underneath/beneath [something]" as crawling under.

The specification of the crawling under action is "A simulation for entering 'underside' containers.".

Check an actor crawling under something (this is the check and redirect crawling under rule):
	if the noun incorporates an underside (called curunder):
		if the bulk of the actor is greater than the bulk of curunder:
			if the player can see the actor:
				say "[if the actor is the player]You[otherwise][The actor][end if] can't fit under [the noun]." instead;
			otherwise:
				stop the action;
		if curunder is closed:
			silently try the actor opening curunder;
			unless curunder is open:
				if the player can see the actor:
					say "[if the actor is the player]You[otherwise][The actor][end if] aren't able to get under [the noun]." instead;
				otherwise:
					stop the action;
		if the holder of curunder is the holder of the actor and the actor is the player:
			say "You'll need to get [if the noun is a container]out of[otherwise]off[end if] [the noun] before you can get under it." instead;
		try the actor entering curunder instead;
	otherwise:
		if the player can see the actor:
			say "[The noun] isn't something [if the actor is the player]you[otherwise][the actor][end if] can get underneath in any practical sense." instead.

After an actor entering an underside (this is the reporting-redirect-for entering an underside rule):
	if the player can see the actor:
		say "[if the actor is the player]You get underneath[otherwise][The actor] gets underneath[end if] [the holder of the noun].".

Crawling out from is an action applying to one thing.  Understand "get out from under/underneath/beneath [something]" or "crawl out from under/underneath/beneath [something]" or "move from under/underneath/beneath [something]" as crawling out from.

The specification of the crawling out from action is "A courtesy redirect action for exiting from an 'underside' container.".

Instead of an actor crawling out from something (this is the redirect crawling out from to exiting rule):
	try the actor exiting.

After an actor exiting (this is the reporting redirect for exiting an underside rule):
	if the container exited from is an underside:
		if the player can see the actor:
			say "[if the actor is the player]You get[otherwise][The actor] gets[end if] out from under [the holder of the container exited from].";
		if the actor is the player:
			try looking;
	otherwise:
		continue the action.

Chapter 3 - Example Room

Persuasion rule: persuasion succeeds

The Bedroom is a room.  The description of the bedroom is "Your cozy bedroom.".

A bed is an enterable supporter in the bedroom.  The bed is bedsize.  The description of the bed is "Your comfy bed.".

An underside called bedspace is part of the bed.

A sock is in the bedspace.  The description of the sock is "A dusty sock.".

A blanket is on the bed.  The blanket is bathtubsize.  The description of the blanket is "A faded wool blanket.".

A marble is in the bedroom.  The description of the marble is "A shiny azure marble.".

Zeke is a man.  The player is Zeke.
Zelda is a woman.  The description of Zelda is "Your lovely wife, Zelda.".

Zeke and Zelda are on the bed.

Test me with "x bed / stand / look under bed / get sock / put sock under bed / search bed / get marble / get under bed / l / showme bed / drop marble / get out from under bed / zelda, get under bed / x bed / search bed / get on bed / l /zelda, stand / l.".

There are two remaining features I want to add, but both of them involve processes I’ve been unable to fully understand for quite some time now.

  1. Modifying the visibility ceiling

In this particular case, when the player is under the bed I’d like the room description to appear as:

Bedroom (under the bed)
Your cozy bedroom.

More generally, I’ve looked at the section in the Standard Rules dealing with the looking action and determining visibility levels several times; although I can mostly follow how the process works, I don’t understand how to intervene in or modify the process. I’ve had other situations before where, for example, the player is in container A which is inside container B. In that case I always wanted the room description while looking to say:

Room (in container B)
A room.

rather than

Room (in container B) (in container A)
A room.

If anyone can suggest a direct solution for the matter at hand involving undersides I’d be interested to hear it, but I would also be interested in hearing any discussion about how to generally affect the visibility levels processing.

  1. Removing things from scope

I’d like to set things up so that when the player (or all actors if possible) is in an underside of object XYZ, the player/actors cannot see other items on (for supporters) or in (for containers) object XYZ, except of course for items that are in the underside of XYZ along with the player; I’d also like to prevent the player (or other actors if possible) from interacting with any items on/in object XYZ unless such objects are in the underside of XYZ. For example, if I am hiding under a bed it’s not possible for me to read a magazine that’s on top of the bed; furthermore if Jane enters the room while I’m under the bed and drops a scarf on the bed, I shouldn’t know at all that a scarf is now on the bed until I stand up and look.

This is something I’ve had trouble with for some time now. While the Inform documentation is full of examples regarding how to add things to the scope of the player, it has little to say about deciding the scope of other actors and as far as I can determine it has not a single word about how to remove things from anyone’s scope (player or other actors).

So far I tried two things to address the issue in particular regard to undersides; both of them compiled fine, but neither worked:

[(a)] After deciding the scope of the player while the player is in an underside (called the smallerbox) (this is the can't see other side of holder while in underside rule): let the greaterbox be the holder of the smallerbox; unless the greaterbox is transparent: place the greaterbox in scope, but not its contents; repeat with adjustment running through things in the smallerbox: place adjustment in scope.
The above seemed to have absolutely no effect on anything.

[(b)] Rule for deciding the concealed possessions of a supporter (called cursup): unless cursup incorporates an underside: make no decision; otherwise: let curund be a random underside incorporated by cursup; if the player is in curund: if the particular possession is in curund: no; otherwise: yes; otherwise: make no decision.
(b) had the odd effect of hiding the player after entering the underside, as well as blocking the “After entering an underside” rule (both of which are undesirable effects), but otherwise had no effect on anything.

Despite the claim

I find that this is something I want to do on a fairly regular basis, for both the player and for other actors; sadly I don’t really know how to even start writing such rules.

Does anyone have any suggestions for dealing with these issues?

It’s late (early) here, so I’ll offer a quick and only partially tested solution to #1. I added this code to the above for testing purposes:The box is an enterable, open, bedsize container in the bedspace. Test box with "stand / get under bed / l / go box / l".

This seems to give the most basic result which follows the style of the standard rules:[code]This is the new room description heading rule:
say bold type;
if the visibility level count is 0:
begin the printing the name of a dark room activity;
if handling the printing the name of a dark room activity,
issue miscellaneous library message number 71;
end the printing the name of a dark room activity;
otherwise if the visibility ceiling is the location:
say “[visibility ceiling]”;
otherwise:
say “[The visibility ceiling]”;
say roman type;
let intermediate level be the visibility-holder of the actor;
repeat with intermediate level count running from 2 to the visibility level count:
if the intermediate level incorporates an underside enclosing the actor,
say " (under [the intermediate level])"; []
otherwise issue library message looking action number 8 for the intermediate level; [
]
let the intermediate level be the visibility-holder of the intermediate level;
say line break;
say run paragraph on with special look spacing.

The new room description heading rule is listed instead of the room description heading rule in the carry out looking rules.
[/code]Note, however, that you get descriptions like:

Bedroom (in the box) (under the bed)

Since you only want the most immediate holder of the actor named (if I read your post correctly), you could do this instead:[code]This is the other new room description heading rule:
say bold type;
if the visibility level count is 0:
begin the printing the name of a dark room activity;
if handling the printing the name of a dark room activity,
issue miscellaneous library message number 71;
end the printing the name of a dark room activity;
otherwise if the visibility ceiling is the location:
say “[visibility ceiling]”;
otherwise:
say “[The visibility ceiling]”;
say roman type;
let intermediate level be the visibility-holder of the actor;
if the intermediate level incorporates an underside enclosing the actor,
say " (under [the intermediate level])";
otherwise issue library message looking action number 8 for the intermediate level;
say line break;
say run paragraph on with special look spacing.

The other new room description heading rule is listed instead of the room description heading rule in the carry out looking rules.
[/code]… which, when the player is in the the box which is under the bed, results in:

Bedroom (in the box)

I’ll get back to you on this, but suffice it to say I don’t think it’s a good idea to mess with the visibility routines if you don’t have to. Even though they are involved in both of your issues, they affect other things as well; changing them could have unintended effects. I’m pretty sure we can solve your scoping issue another way. I’ll get back to you.

For #2, try this:[code][This affects scope, but not descriptions.]

Rule for deciding the concealed possessions of a supporter which incorporates an underside (called curund) which encloses the player:
if the particular possession is in curund or the particular possession is curund:
no;
otherwise:
yes.

[This affects descriptions.]

Rule for listing nondescript items for a supporter which incorporates an underside which encloses the player: do nothing.[/code]
I also noticed that you can refer to the sock even when you can’t see it because you’re standing up. If you don’t want that, you’ll need another “deciding the concealed possessions” rule. If you do want that, maybe you want to be able to refer to the blanket when you’re under the bed, in which case you don’t want this first rule either.

@Skinny Mike

Thanks for the response. The room description heading rule doesn’t seem quite so intimidating after reading your revised versions, especially since you provided two examples that do slightly different things; I didn’t fully understand before how the various lines of the room description header rule related to each other, and since I was worried about Bad Things happening (or more particularly, Subtle Bad Things That I Wouldn’t Notice Until Much Later When I Would No Longer Remember Doing Whatever Caused Them) I hadn’t tried to “get in there” and change anything before. I agree with your comment that great care should be taken when modifying the process, but I’m glad you provided both those examples as I will probably use both of them eventually in different contexts. The first example does indeed seem appropriate for the “undersides” idea, while the second second will solve a long-standing issue I’ve been having with the way I represent liquids (namely, as containers) in my game environment, resulting in what I feel are silly room descriptions like:

Bathroom (in the bathtub) (in the water)

(as opposed to floating above the bathtub full of water? Well, it is possible I guess).

Is there any reason (in the context of my worries about Subtle Bad Things happening as well as your comment about unintended effects) not to write several of these header rules for various conditions, and then use procedural rules to select the appropriate version for the current context? For example (not tested):

Procedural rule: if the holder of the player is a liquid, substitute the liquid-room description heading rule for the room description heading rule.

Your post was very helpful to me, thanks again.

@vaporware

Thanks for the response. I played around with various combinations of what I wrote and what you wrote (I had four :open_mouth: text files open at the same time with game transcripts from various combinations), and I think the functionality I like best is the inclusion of both your rules.

I hadn’t made up my mind about this as there’s some subtlety involved. I had already spent some time pondering variations of the point you raised in regard to the blanket while designing the undersides, and I spent some more time pondering the issue after reading your comment. My general opinion on design is that whenever a decision must be made between realism versus better gameplay, realism should lose; in this case though it’s not clear to me whether arguing that an edge of the blanket may be hanging down far enough to be visible from under the bed is a realism argument or a facilitating gameplay argument. I still haven’t made up my mind completely on the issue, but since I liked the way things worked while including both of your rules I guess I’m leaning toward saying that in the interest of gameplay everything on “the other side” of an underside should be excluded from view. On your other point about the sock being “visible” (in the Inform/technical sense) but not described anywhere, that’s actually by design. If someone has looked under a bed and seen something there, I don’t think presuming that they’ll remember what they saw (particularly since they always have the option of just looking again whenever they like) is asking too much; plus it makes things easier when it’s time to tell the player his character is tired and should go to sleep, without the character automatically noticing that Freddy Kreuger, Cujo, and the Blob of Doom from Planet X are currently holding a Union of Scary Monsters meeting under the bed.

Thanks again for your response, it was very helpful.

@anyone

–Is anyone able to particularly explain why the example rule (a) I gave above (After deciding the scope of the player while the player is in an underside) didn’t do anything? I really thought that should have worked, and I’m not feeling comfortable about failing to see the reasons for the rule’s failure to do anything.

Completely off topic: if there are any mathematics and geometry whizzes reading this thread who would like to amuse themselves for a few minutes by helping someone who never paid attention in math class (namely, me :frowning: ) solve a math-related problem, feel free to join in. Here’s the problem:

If we have:

a) a world where everything is a square (or sometimes a rectangle) with dimensions measured in inches; and

b) we have some liquids that are always squares with dimensions measured in inches; and

c) according to some research from Wikipedia:

1 gallon = 128 fluid ounces = 231 cubic inches = a figure 3 inches by 7 inches by 11 inches (or, according to my calculator, a cube 6.1358 inches by 6.1358 inches by 6.1358 inches; I could be wrong); and

d) according to my calculator then (I could be wrong), 1 fluid ounce = 1.8046875 cubic inches;

then

e) if we remove 1 (or 18, or 135, etc) fluid ounces from the gallon-cube of fluid, is there a general formula or concept for determining the resized dimensions (height, width, depth) of the gallon-minus X number of ounces-cube? What about if we add 1 (or 7, or 92, etc) fluid ounces to the gallon-cube: how would the gallon-cube’s resized dimensions be determined in that case? Bonus points :slight_smile: for you if the forumla is easily translated into Informese, but if not that’s no problem. Double bonus points if you can explain your answer in terms a grade-school kid could understand, since grade-school was around the time I stopped paying attention in math class :smiley: .

An “after deciding the scope” rule can only add things to scope: scope isn’t a list, it’s a process, and all the default objects have already been placed in scope by the time your “after” rule runs. The only ways to remove things from scope are (1) write a “deciding the concealed possessions” rule, or (2) completely replace the default scope behavior by writing a “for deciding the scope” rule. The latter is hard to do well, since the default implementation is part of an I6 function and uses some local state that isn’t available to an I7 replacement, but it would be complicated even if that weren’t a problem.

Also, scope doesn’t control what goes in descriptions, so removing things from scope would only prevent the player from referring to them. It wouldn’t stop them from being listed.

What you’re looking for is the cube root. As you might remember from middle school, square root is the opposite of squaring: if xx = y, then x is the square root of y, assuming x is positive. Likewise, if xx*x = y, then x is the cube root of y. You know y (the volume) and you want to find x (the length of each side).

So: take your 231 cubic inch volume, convert one fluid ounce to cubic inches and subtract it, then take the cube root of the result to get the length of each side.

Inform can calculate square and cube roots, either with a phrase (“the cube root of 125”) or indirectly through the equation feature, and it can also do the unit conversion for you: this is all described in chapter 14 of the manual. For example…

[code]Length is a kind of value. 1 in specifies a length scaled at 100.
Area is a kind of value. 1 sq in specifies an area scaled at 100. A length times a length specifies an area.
A volume is a kind of value. 1 cu in specifies a volume scaled at 100. 1 gallon (singular, in gallons) specifies a volume equivalent to 231 cu in. 10 gallons (plural, in gallons) specifies a volume equivalent to 231 cu in. 1 fl oz (in fluid ounces) specifies a volume equivalent to 1.8 cu in. A length times an area specifies a volume.

Equation - Cube Volume Equation
v = l^3
where v is a volume and l is a length.

When play begins:
let v be 1 gallon;
decrease v by 1 fl oz;
let l be given by the Cube Volume Equation;
say “[v] (~[v in fluid ounces]) fits in a cube [l] on a side.”[/code]
But since Inform internally does all math in integers, you won’t get much precision, and the conversion factor between cubic inches and fluid ounces won’t be very accurate. Scaling the units at 100 gives you two decimal places. Any more than that and you’ll get garbage results because of integer overflow.

Thanks for the help on the math, vaporware. I see now what I was doing wrong: I was trying to subtract the dimensions of the new cube from the original cube, rather than simply recalculating the original cube. I guess that career in physics is out the question for me. :laughing:

I’m able to get a bit more precision with these values because I’m actually using half-inches as my basic unit of measurement; it’s not a completely adequate solution by any means, but it helps (in addition to not doing well with math, I can’t relate to the metric system either–and I’m too old to change my ways).