Removing a backdrop from one room

There are several ways to move backdrops around – you can move them to a specific room or region, move them everywhere, move them off-stage, or move them into a specific set of rooms.

But is there any way to remove one from a specific room while leaving it in all the other rooms or regions it’s currently in?

If it helps, there’s only one room in which I want the backdrop to be transient. Every other room featuring it does so permanently.

I think you’ve looked at this already: 8.8. Moving backdrops

I would set a property on all of the rooms that you want to keep the backdrop, let’s call it “permanent”, and then move B backdrop to all permanent rooms.

1 Like

So something like this? Another thread mentioned something about a Definition:, not sure if that can apply here (can a description refer to “all X rooms and Y”?).

A room can be seaside.

The Pier is a room. East of the Pier is Seaside Road. South of the Pier is Viewing Trolley. There is a button in the Viewing Trolley. The Pier is seaside. The Seaside Road is seaside.

There is a not scenery backdrop called the sea. When play begins: move the sea backdrop to all seaside rooms.

Instead of pushing the button for the first time:
	say "The trolley speeds forward, skidding to a halt right at the end of the pier!";
	now the Viewing Trolley is seaside;
	change the north exit of the Viewing Trolley to nowhere;
	change the south exit of the Pier to nowhere;
	change the north exit of the Pier to the Viewing Trolley;
	change the south exit of the Viewing Trolley to the Pier;
	move the sea backdrop to all seaside rooms.

That works. Is it the only way to achieve this?

I’m also running into an issue of needing the sea to be visible from the ferry, which is an opaque container (I’m using Emily Short’s Transit System). Maybe that one can just be a special case though…

While Phil Riley’s excellent solution is probably the simplest way to achieve what you’re looking for, it’s not the only way. Try this:

"Backdrop Removal Test"

Part - System

Include (-

Global current_backdrop;

[ SetCurrentBackdrop backdrop;
	current_backdrop = backdrop;
];

-).

To decide which backdrop is the current backdrop:
	(- current_backdrop -).

Include (-

[ BackdropLocation O target address m x i k l r sl;
	SetCurrentBackdrop(O);
	if (O has absent) return nothing;
	if ((target == nothing or real_location) && (parent(O) == real_location))
		return real_location;
	address = O.&found_in;
	if (address ~= 0) {
		k = O.#found_in;
		for (l=0 : l<k/WORDSIZE : l++) {
			m = address-->l;
			if (ZRegion(m) == 2) {
				sl = location;
				if (target) {
					location = target;
					r = m.call();
					if (r ~= 0) { location = sl; return target; }
				} else {
					objectloop (x ofclass K1_room) {
						location = x;
						r = m.call();
						if (r ~= 0) { location = sl; return x; }
					}
				}
				location = sl;
			} else {
				if (m ofclass K9_region) {
					objectloop (x ofclass K1_room)
						if (TestRegionalContainment(x, m))
							if (target == nothing or x)
								return x;
				} else {
					if (target == nothing or m) return m;
				}
			}
		}
	}
	return nothing;
];

-) replacing "BackdropLocation".

Include (-

[ MoveFloatingObjects toroom i k l m address flag;
	if (toroom == nothing) toroom = real_location;
    if (toroom == nothing) return;
    objectloop (i) {
	SetCurrentBackdrop(i);
        address = i.&found_in;
        if (address ~= 0 && i hasnt absent) {
            if (ZRegion(address-->0) == 2) {
                m = address-->0;
                .TestPropositionally;
                if (m.call(toroom) ~= 0) move i to toroom;
                else { if (i in toroom) remove i; }
            } else {
                k = i.#found_in;
                for (l=0 : l<k/WORDSIZE : l++) {
                    m = address-->l;
                    if (ZRegion(m) == 2) jump TestPropositionally;
                    if (m == toroom || m in toroom) {
                        if (i notin toroom) move i to toroom;
                        flag = true;
                    }
                }
                if (flag == false) { if (i in toroom) remove i; }
            }
            if ((i ofclass K4_door) && (parent(i) == nothing)) {
            	move i to (i.door_to());
            }
        }
    }
];

-) replacing "MoveFloatingObjects".

To move floating objects to (R - a room):
	(- MoveFloatingObjects((+ R +)); -).

Default presence relates various backdrops to various rooms. The verb to be present in means the default presence relation. The verb to view means the reversed default presence relation.

When play begins (this is the link starting backdrops rule):
	repeat with B running through backdrops:
		repeat with R running through rooms:
			move floating objects to R;
			if B is in R, now B is present in R;
	update backdrop positions;

[You must use these phrases for backdrops that can be removed. Others should not be affected.]

To unlink (B - a backdrop) from (R - a room):
	now R does not view B;
	process links for B;
	
To link (B - a backdrop) to (R - a room):
	now R views B;
	process links for B;
	
[This subphrase can be used alone after manipulating the "default presence" relation, for example to add or remove a backdrop to a description of rooms:]
	
To process links for (B - a backdrop):
	now B is off-stage;
	move B backdrop to all rooms viewing the current backdrop;
	update backdrop positions;
		
Part - Scenario

Light Woods is a room. "The forest presses in closer to the north." 

Forest is north of Woods. "The trees are denser here than they are to the south. To the east you can see a large machine."

Fan Station is east of Forest. "A huge fan is mounted here facing west[if the fan switch is switched on], sending gale-force winds out into the forest[otherwise], spinning only enough to repel the mist from the immediate vicinity[end if]. It is connected to a generator and a switch. A path returns to the west."

A device called the fan switch is in Fan Station. It has description "It controls the giant fan's speed."

A generator is a scenery thing in Fan Station. It has description "A basic electrical generator, connected to the fan."

The mist is a backdrop. It is in Woods. It is in Forest.

After looking when the player can see the mist:
	say "A faint mist swirls around your feet."

Flipping is an action applying to one thing. Understand "flip [thing]" as flipping.

Check flipping something when the noun is not a device:
	say "You can only do that to a device." instead.
	
Carry out flipping something:
	if the noun is switched on:
		silently try switching off the noun;
	otherwise:
		silently try switching on the noun;
		
Report flipping something:
	say "You flip [the noun] [if the noun is switched on]on[otherwise]off[end if]."

After switching on the fan switch:
	say "The fan starts blowing away the mist from the forest to the west, but it remains further out.";
	unlink the mist from Forest.
	
After switching off the fan switch:
	say "The fan stops. The mist soon rolls back in to the forest to the west.";
	link the mist to Forest.
	
Test me with "l / x mist / n / x mist / e / flip switch / w / x mist / s / x mist / n / e / flip switch / w / x mist / s / x mist". 

[A more complicated example follows to demonstrate that the system functions even with multiple overlapping removable backdrops:]

[Place is a room. Other Place is east of Place. Third Place is north of Other Place. Zone is west of Third. Second Zone is north of Zone.

The foo is a backdrop. It is in Place. It is in Other Place. It is in Third Place.

The bar is a backdrop. It is in Zone. It is in Place.

Instead of waving hands:
	unlink the foo from Place;
	unlink the foo from Other Place;
	
Instead of jumping:
	link the foo to Place;
	link the foo to Other Place;
	
Instead of waiting:
	unlink the bar from Zone;
	
Instead of taking inventory:
	link the bar to Zone.
	
After looking:
	say "Visible backdrops: [a list of visible backdrops]."
	
Test me with "wave / l / jump / l / wave / e / n / w / wait / l / jump / e / s / w". ]

Implementation notes

The difficulty of this problem arises from the fact that a backdrop does not directly keep track of which rooms it is in at a given time. Instead, whenever Inform tests whether a backdrop is in a room, it checks whether that room is included in a description of objects (represented as a function pointer at the I6 level) stored as a property for that backdrop. Since this description of objects must be generated at compile-time, and since I6 does not possess first-class functions or closures, it cannot reference local variables or be dynamically generated.

Thus, the problem is equivalent to constructing a routine, fully determined at compile time, that decides whether a backdrop is in a room in some way that allows you to remove it at runtime. In Phil Riley’s answer, the program checks a property of the room. Here, it’s linked to an I7 relation with some I6 connective tissue, allowing it to be generalized to other tasks that require the backdrop to explicitly track the rooms it is in.

(A complete conversion of the standard backdrop handling system to this relation-driven stateful model is possible, but since it would stop the built-in move backdrop to all… phrase from working, I opted for a middle ground where the author can still use the built-in features if the backdrop is not removable.)

Even more implementation notes

Although a description of objects can’t reference a local variable, which is allocated on the stack and thus quickly becomes a garbage pointer, it can reference a global variable set to the value of a local variable. But a single global set in the “link” and “unlink” functions doesn’t suffice, since multiple backdrops would need different globals, restricting the system to small, fixed numbers of backdrops.

However, since a given evaluation of the description of objects only runs for one backdrop at a time, a single global can be changed to reflect the backdrop that the system is currently checking. There are only two functions, as far as I could tell, that use the found_in function pointer property, and each of those was modified to set a global current_backdrop variable to the backdrop under consideration before performing the call. Thus, the single description of objects compiled by “all rooms viewing the current backdrop” is completely defined at compile time, but changes its behavior at runtime as desired.

Please note: this approach has not been extensively tested.

1 Like

Oh my goodness, that’s a lot of code. It took me a few read-throughs (including the implementation notes) to realize why you had to go to the trouble of inserting the giant chunks of I6 code – the I7 code almost looks like it should work without all of that, but almost is the key word there, I guess…

I think I’ll stick to the other solution for the time being, but I’ll keep this in mind in case I find I have a lot of backdrops that need to become transient.

For more useful technical details about backdrops, see this informative post by @drpeterbatesuk: In 10.1.2, only one of multiple statements to place a backdrop is implemented when at least one is implemented as a routine.

1 Like
The Rock Pool is a room.
The Upper Cave is above the Rock Pool.
The Ledge is east of the Pool.
The stream is a backdrop.
streamy is a region.
streamless is a region.
stream is in streamy.
all rooms are in streamy.

carry out jumping:
now the map region of the rock pool is streamless.

after looking:
  repeat with x running through all backdrops in the location begin;
    say "[the x] is here.";
  end repeat;
continue the action;

test me with "u / jump / d"
3 Likes

Ohhh, that’s quite an interesting approach. It would work for one of the two backdrops I need to do this for. Unfortunately, it doesn’t work for the sea, because the sea can be seen from more than one map region, and it’s not possible for map regions to overlap.

In other words, my layout (excluding the room where the seaside is transient) is similar to this:

Mainland and Island are regions.
The sea is a backdrop.
Big Tree and Small Pier are in Island.
Ferry Port and Pierside Road and Grand Park are in Mainland.
The sea is in Ferry Port and Pierside Road and Small Pier.

It may or may not be a good solution, but you could make two different backdrops with printed name “sea”.

1 Like

That’s true actually, and there could potentially be a good reason to do so (if the sea looks significantly different from the island, for example). I’ll keep this in mind.

I must be missing something since the Mad Scientists have written ominous code. Is it possible to make a kind of backdrop? “Ocean is a kind of backdrop. Big Ocean is an Ocean. Shallow Water is an Ocean.” Use “Big Ocean” where it remains, and then “Shallow Water” in individual rooms where the tide goes out so you can say “Now Shallow Water is off-stage” when necessary. Same backdrop, but divided into kinds? If you replace it you’d just have to declare each room “Now Shallow Water is in Under the Pier; Now Shallow Water is in Coral Reef”…

Not tested…I’m likely missing something.

1 Like

Oh, that’s also a very interesting idea. I did a quick test, and indeed a kind of backdrop is allowed. (Random aside: I’m still a touch annoyed that I can’t create a kind of scene.) So essentially the idea is that the instance of the backdrop in the room where it’s transient is not the same backdrop, but quite possibly has the same description and printed name.

I probably won’t adopt this approach myself, but it does seem to satisfy the requirements.

1 Like

This is an example of how you might use a definition to flexibly define which rooms contain a backdrop:

"Disappearing_backdrops" by PB

Section - The tides

tide-is-in is initially true.        [flag to hold the current position of the tide]
To decide whether the tide is in:   [semantic sugar so we can write 'if the tide is in']
	if the tide-is-in is true, yes.
To decide whether the tide is out:   [semantic sugar so we can write 'if the tide is out']
	if the tide-is-in is false, yes.
To tide goes out:                              [more semantic sugar to control tide-is-in so that we can simply write 'the tide goes out']
	now the tide-is-in is false;
	update backdrop positions.
To tide comes in:                             [similarly so that we can simply write 'the tide goes out']
	now the tide-is-in is true;
	update backdrop positions.
	
Section - Geography

Mainland and Island and Ferry are regions.
The sea is a not scenery backdrop with indefinite article "the".
Big Tree and Small Pier are in Island.
Ferry Port and Pierside Road and Grand Park are in Mainland.
Boat Deck and Cabin are in Ferry.

Big Tree is north of Small Pier.
Pierside Road is south of Grand Park and west of Ferry Port.
Boat deck is south of Ferry Port and north of Cabin. 

Definition: a room is seaside:
	if it is in Ferry, yes;
	if it is Ferry Port or it is Small Pier, yes;
	if it is Pierside Road and the tide is in, yes.

Section - Setup

The player is in Grand Park.
When play begins: move the sea backdrop to all seaside rooms.

Section - Controlling the tide

Carry out jumping:
	if the tide is in:
		the tide goes out;
	otherwise:
		the tide comes in.
		
Section - Testing

Test me with "s/jump/look/jump/look/e/s"

Depending what you want to do, you can give them properties like adjectives.

The kind of value “scene” is one which is allowed to have properties - it has a tick in the “properties” column in the chart in the Kinds index - and this can be very useful in describing scenes. For instance, we could write:

A scene can be thrilling or dull. Train Stop is dull.

So you can do things like Every turn during a thrilling scene: increase BP by 1.

1 Like

yeah, scenes aren’t objects, but they can have properties, so you can say:

A scene can be depressing, neutral, or happy.

And then refer to depressing scenes etc. Given single inheritance, this is mostly a win over creating subkinds.

1 Like

Yeah, I don’t think I’ve run into a case where I absolutely need to have a new kind of scene instead of adding a property to scenes… but I imagine if I had a lot of scenes it could become an issue that every property I add to scenes is valid on every scene. I haven’t reached that point, however.

2 Likes

I keep reinventing a task list using scenes for tasks so I would love to be able to say “a task is a kind of scene” instead of “a scene can be tasked”.

1 Like