Determining where backdrops are

Against my better judgement, I’m messing around with backdrops again, and writing code that refers to arbitrary backdrops. (If I’ve asked this before, apologies. Couldn’t find if I asked anywhere.)

What I need is a way of determining the list of rooms that a given backdrop is presently in. I could create a new relation between rooms and backdrops, but that would be a royal pain (and seems super-inefficient). I’m not using regions, and defining them would be as onerous as creating a new relation.

(I know that backdrops, strictly speaking, have no location. But they surely have some kind of relation to the places where they appear. I want that.)

I suspect doing this properly would require dipping into I6 (which is beyond my skills); there seems to be a “found_in” I6 property which contains this information, but AFAICT it’s not exposed by the Standard Library.

However, as a quick and really ugly hack, the following brute force approach seems to more or less work:

To decide whether (the item - a backdrop) is found in (the spot - a room):
	say run paragraph on; [avoid introducing a line break if this rule is called in the middle of printing text]
	let the former location be the location;
	move the player to the spot, without printing a room description;
	let the result be whether or not the item is in the location;
	move the player to the former location, without printing a room description;
	decide on the result.

That was… one of the uglier last-resort options, yeah. I’m having flashbacks to the teleporting penis in Bob’s Garage.

The alternative is to just re-invent backdrops as magical teleporting things that pre-emptively follow the player around as appropriate, which would be pretty straightforward.

If you use “now the player is in …” you shouldn’t need to worry about printing stuff, which will simplify that phrase significantly.

Alas, that doesn’t seem to work as you suggest; in fact, Inform seems to interpret “now X is in Y” as an alias for “move X to Y”, which will print the room description if X is the player.

Ps. Here’s my test story, if anyone wants to play with it:

"Something Fishy" by Vyznev Xnebara

The Entrance is a room.
The Living Room is south of the Entrance.
The Office is east of the Living Room.
The Kitchen is west of the Living Room.

The unpleasant smell is a backdrop. "An unpleasant smell lingers here." It is not scenery.
The unpleasant smell is in the Kitchen.

Definition: a room is smelly if the smell is found in it.

Rule for printing the locale description when the unpleasant smell is not in the location:
	say "You smell something funny coming from [the list of smelly rooms]."

To decide whether (the item - a backdrop) is found in (the spot - a room):
	say run paragraph on;
	let the former location be the location;
	move the player to the spot, without printing a room description;
	let the result be whether or not the item is in the location;
	move the player to the former location, without printing a room description;
	decide on the result.

Hmm, you’re right. Well that’s silly!

My only better suggestions are:

(a) a function that works exactly like this but in I6, so it’s more efficient;

or

(b) define a separate region-in property for backdrops, and make sure it’s always the same as I7’s internal notion of where-the-damn-backdrop is. (This requires you to be careful every time you define or move a backdrop. And if you move a backdrop to a description of rooms, rather than a region, you’d need a second property, I suppose.)

No good answers, I’m afraid.

That’s pretty much exactly what backdrops are; internally, they are also referred to as “floating objects” since they are silently moved into the player’s location as she moves.

Surely the I6 code to populate a list with the contents of an object’s found_in array isn’t that difficult? The only complication would seem to be manipulating the list in I6, but there are helper functions for that. I don’t have time right now to give it a go, but maybe someone who’s quicker with I6 than I could try rolling it out?

Or maybe I’m missing something…?

–Erik

Exactly. Only these would be mine.

Found_in isn’t an array. It’s a function that tests the global location variable.

Went with Vyznev’s solution as the least objectionable of a bad lot. I7 emits slight wheeze and a billow of steam, but no alarming clunking noises as yet. Will monitor closely.

I see. It still seems as though one ought to be able to test that function w/o moving the player. That should be a lot faster: just one function call per location in the game rather than going through all of the processes of moving the player through all the rooms. Unfortunately, I tried a couple of different ways to implement this, and didn’t succeed:

  1. Based solely on zarf’s description (“found_in is a function that tests the global location variable”), I tried caching the location variable, changing the location to an arbitrary room, calling found_in for the backdrop, e.g., sun.found_in or sun.found_in(), and then restoring the location. Unfortunately, this seems to always return true.
  2. I tried to adapt some of the library code (from MoveFloatingObjects) to this purpose and found that my implementation always returns false… :frowning:

Here’s what I came up with for #2 in case anyone is interested:

[spoiler][code]House is a room. Garden is a room. Field is a room.

Sun is a backdrop. Sun is in Field and Garden.

To decide whether (B - a thing) is a floating object in (R - a room):
(- TestFloatingObjects({B},{R}) -)

Include (-
[ TestFloatingObjects o r k l m address flag;
address = o.&found_in;
if (address ~= 0 && o hasnt absent) {
if (ZRegion(address–>0) == 2) {
m = address–>0;
.TestPropositionally;
if (m.call(r) ~= 0) return true;
}
else {
k = o.#found_in;
for (l=0 : l<k/WORDSIZE : l++) {
m = address–>l;
if (ZRegion(m) == 2) jump TestPropositionally;
}

	}
}
return false;

];
-)

When play begins:
if the Sun is a floating object in the Field, say “It’s in the field!”;
if the Sun is a floating object in the House, say “It’s in the house!”;[/code][/spoiler]

I think you just forgot if (m == r || m in r) rtrue; after the jump to TestPropositionally. It seems to work fine for me otherwise.

I could also make Vyznev’s solution more efficient by using the jump-the-player technique only once for each backdrop, and using that to populate a list of rooms for each backdrop, which would be referred to thereafter.

(Of course, I could just write all the lists out in advance: but that would introduce lots of opportunity for transcription errors.)

So I did, and so it does! Thanks for taking a look!

Here’s the full implementation/example for maga’s request:

[code]House is a room. Garden is a room. Field is a room.

Sun is a backdrop. Sun is in Field and Garden.

To decide whether (B - a thing) is a floating object in (R - a room):
(- TestFloatingObjects({B},{R}) -)

Include (-
[ TestFloatingObjects o r k l m address flag;
address = o.&found_in;
if (address ~= 0 && o hasnt absent) {
if (ZRegion(address–>0) == 2) {
m = address–>0;
.TestPropositionally;
if (m.call(r) ~= 0) return true;
}
else {
k = o.#found_in;
for (l=0 : l<k/WORDSIZE : l++) {
m = address–>l;
if (ZRegion(m) == 2) jump TestPropositionally;
if (m == r || m in r) rtrue;
}

	}
}
return false;

];
-)

To decide what list of rooms is the list of loci for (B - a backdrop):
let L be a list of rooms;
repeat with locus running through rooms:
if B is a floating object in locus, add locus to L;
decide on L.

When play begins:
say “[List of loci for the Sun].”;[/code]

Works like a dream. Many thanks, all.

I’m afraid this does not work when the backdrop is set to a region. That’s the case when found_in tests location rather than its argument. Yes, it’s inconsistent.

You need to do something like this:

To decide whether (B - a thing) is a floating object in (R - a room):
   (- WrapTestFloatingObjects({B},{R}) -)

[ WrapTestFloatingObjects b r res tmploc;
	tmploc = location;
	location = r;
	res = TestFloatingObjects(b, r);
	location = tmploc;
	return res;
];

Thanks, zarf, that makes this a general-purpose solution for anyone who stumbles onto this thread.

I came across this problem when updating Conditional Backdrops. I think there might have been an Inform bug involving the found_in property - like it’s supposed to take an argument, but it ignores the argument and uses the location instead. I think I fixed that, with Zarf’s guidance… which makes the problem a simple matter of writing an I7 wrapper for found_in.

inform7.com/extensions/Mike%20Ci … index.html

Hmm, now I’m encountering a weird bug with this. It works fine when backdrops are in only a few locations; but for backdrops that are in a lot of locations (I think at least 16), it adds every location to the loci list.

I’m perplexed. Any ideas?