found_in

I think it’s back to nuts and bolts with my Multitudes extension.

I just discovered that “move the player” doesn’t work with Multitudes. “move the player” (indirectly) calls the I6 routine PlayerTo, which calls MoveFloatingObjects. This sequence of calls is not accessible within I7, which means that Multitudes has no opportunity to update its locations to deal with the problems mentioned in this thread.

So it looks like to make this work, I’ll have to make multitudes into bona-fide I6 Floating Objects with their very own found_in routine, preferably one that calls on an I7 phrase to check the littering relation. (it’s a conditional relation between multitudes and rooms). How hard is that to do? I can read I6 okay, but writing it I’m a little rusty.

Or maybe I should just rewrite the Standard Library phrase “To move (something - object) to (something else - object)” and possibly also “To surreptitiously move (something - object) to (something else - object) during going” to give myself a hook…?

Am I on the right track with this? It compiles, but it doesn’t place sand in the location:

[code]A multitude is a kind of backdrop.

To decide whether (mess - a multitude) multitude is found in (place - a room) (this is multitude finding):
yes;

A multitude has a phrase (multitude, room) -> nothing called the floating location. The floating location of a multitude is usually multitude finding. The floating location property translates into I6 as “found_in”.

The beach is a room.

Sand is a multitude. It is not scenery.

test me with “showme sand”[/code]

That’s not going to work. The compiler sticks in a found_in property for every backdrop (defined as nowhere, unless you change it by saying “move BACKDROP to DESCRIPTION”.) I don’t see a way to override that at compile time.

The other problems are:

  • The definition of “found_in” is a function which takes just one argument, a room. (It implicitly tests the backdrop “self”, aka “the item described”.)

  • The implementation of a function property isn’t just a native I6 function pointer. There’s a closure object in there. Found_in has to be a native I6 function pointer.

I did some I6 hacking to try to make this work. Unfortunately, I don’t think it can.

The problem is down in the guts of the MoveFloatingObjects() function. By the time the object’s found_in property is invoked, the information about what object it is has been lost. (The found_in function is presumed to have been written specially for that object.) So there’s no way to look up any properties of the object at that time.

This is the problem that closures are intended to solve (a closure wraps up the object identity and the function together). But found_in is not a closure, as I said – it’s an old primitive thing. So that’s no help.

If you don’t mind me offering for you to do more work: Backdrops are kind of a crappy hack. You could solve more than one problem by providing an alternate implementation of backdrops using relations and scoping, and then building your multitudes functionality on top of that system.

–Erik

Very true. But rather a lot more work than the crappy backdrop hack. :slight_smile:

What about rewriting MoveFloatingObjects to insert a hook to an I7 “moving floating objects” rulebook? Possible? Dangerous?

It appears to be possible, but I’m not sure about the dangers.

Here’s a little proof-of-concept. I think the “ObjectFloats” routine needs some finesse - I’m not sure if every method of removing the sand from the beach would work properly:

I was wondering if the “presence rulebook” should fail if a floating object is not present, but “make no decision” if the object doesn’t float. Do you think that’s an abuse of the rulebook outcome?

[spoiler][code]

Include (-
[ MoveFloatingObjects i k l m address flag;
if (real_location == nothing) return;
objectloop (i) {
FollowRulebook( (+ presence rulebook +), i );
if (RulebookSucceeded()) move i to real_location;
else if (ObjectFloats(i) && parent(i)) remove i;
}
];

[ ObjectFloats B address;
return (B.&found_in ~= 0 && B hasnt absent);
];

[ ObjectFoundIn B R k l m address flag;
if (~~ObjectFloats( B )) rfalse;
address = B.&found_in;
if (ZRegion(address–>0) == 2) {
m = address–>0;
return (m.call® ~= 0);
}
else {
k = B.#found_in;
for (l=0 : l<k/WORDSIZE : l++) {
m = address–>l;
if (ZRegion(m) == 2 && m.call® ~= 0) rtrue;
if (m == R || m in R) rtrue;
}
}
rfalse;
];

[ MoveBackdrop bd D x address;
if (~~(bd ofclass K7_backdrop)) return RunTimeProblem(RTP_BACKDROPONLY, bd);
if (bd.#found_in > WORDSIZE) {
address = bd.&found_in;
address–>0 = D;
} else bd.found_in = D;
give bd ~absent;
MoveFloatingObjects();
];
-) instead of “Floating Objects” in “WorldModel.i6t”

A backdrop can be absent. The absent property translates into I6 as “absent”.

presence is an object based rulebook.

To decide whether (item - an object) is found in (place - an object): (- ObjectFoundIn({item}, {place}) -)

A presence rule for something (called the floater) (this is the found_in rule):
if the floater is found in the location, rule succeeds.

A multitude is a kind of thing.

The beach is a room. The road is west of the beach.

Sand is a multitude. It is not scenery. Presence of sand: if the location is beach, rule succeeds.

Water is a backdrop. It is not scenery. It is everywhere.

test me with “showme sand”[/code][/spoiler]

I don’t see anything obviously broken about that (but I haven’t compiled it or tested it).

It’s probably worth doing an I6 class test in the objectloop, before you call the presence rulebook. This loop is going to run every turn, and it loops over every object in the game. The standard version bypasses non-floating objects quickly, by doing the “i.&found_in ~= 0 && hasnt absent” test. Running a rulebook to make that determination is substantially more work.

What sort of class test do you mean? Can I check if the objects are of class “thing” or something? The problem is that we want the rulebook to run on things that don’t have a found_in property. We could give them another “floating” property if that would make it faster…

Working from the other direction, I could restrict floating objects to backdrops and doors, but allow the user to write “presence” rules that supersede the normal found_in property. Less flexible, but potentially faster?

Has that changed since before 5T18? I was just looking at Conditional Backdrops by John Clemens, which looks EXACTLY like what I was trying to do - and it’s implemented using the found_in property. Do you think I could stick my code in and call it Version 2…?

It hasn’t changed since 5U92, but I don’t have a 5T18 handy to look at. Does that extension still work?

“obj ofclass {My Backdrop Kind}” should work. Or you could assign a found_in property for your class.

That would work too.

No, it doesn’t seem to work anymore. Aside from a minor I6 syntax change, it uses an object-based rulebook within the found_in function, and that doesn’t seem to receive the correct object.

All right, I think I can do this.

That’s what I was afraid of.

I suppose I’ll file a bug about this, even though it’s only a problem for ambitious extension-writers.

(It looks like this handling of found_in changed in the Great Templatization of 5T18.)

I’ve decided to apply a minor hack to deal with the problem. Here is the full source of Conditional Backdrops, Version 2:

[spoiler][code]Version 2/110302 of Conditional Backdrops by Mike Ciul begins here.

“An extension to allow a single rulebook to determine the presence of multiple backdrops.”

Include (-
[ MoveFloatingObjects i k l m address flag;
if (real_location == nothing) return;
objectloop (i) {
if (ObjectFloats(i)) {
if (ObjectFoundIn(i, real_location)) move i to real_location;
else remove i;
}
}
];

[ ObjectFloats B address;
return (B.&found_in ~= 0 && B hasnt absent);
];

[ ObjectFoundIn B R k l m address;
if (~~ObjectFloats( B )) rfalse;
address = B.&found_in;
if (ZRegion(address–>0) == 2) {
m = address–>0;
parameter_object = B;
return (m.call(R) ~= 0);
}
else {
k = B.#found_in;
for (l=0 : l<k/WORDSIZE : l++) {
m = address–>l;
if (ZRegion(m) == 2 && m.call(R) ~= 0) rtrue;
if (m == R || m in R) rtrue;
}
}
rfalse;
];

[ MoveBackdrop bd D x address;
if (~~(bd ofclass K7_backdrop)) return RunTimeProblem(RTP_BACKDROPONLY, bd);
if (bd.#found_in > WORDSIZE) {
address = bd.&found_in;
address–>0 = D;
} else bd.found_in = D;
give bd ~absent;
MoveFloatingObjects();
];
-) instead of “Floating Objects” in “WorldModel.i6t”

A conditional backdrop is a kind of thing.

A conditional backdrop is always fixed in place. A conditional backdrop is never portable. A conditional backdrop is usually scenery.

Include (- with found_in [ ; ProcessRulebook( (+ Backdrop condition rules +) ); return (RulebookSucceeded()); ], -) when defining a conditional backdrop.

The specification of conditional backdrop is “Like a backdrop, but allows rules for determining presence or absence in a given room.”

Backdrop condition rules are an object-based rulebook.

Backdrop condition rules have outcomes present (success), it is present (success), it is absent (failure) and absent (failure - the default).

To decide which object is new location: (- location -).

Conditional Backdrops ends here.[/code][/spoiler]
The relevant line I’ve added sets “parameter_object = B” right before calling the found_in function. Is this safe, or can it mess with nested rulebooks? Should I save the old parameter_object on the stack?

I learned a lot from reading auto.inf while working on this. But I’m still not quite sure how certain global variables work.

One obstacle to understanding was that I kept reading lines like this:

Global parameter_object; ! = I7 "parameter-object" = I7 "container in question"

as “I6’s parameter_object is not equal to I7’s parameter-object, it is I7’s container in question.”

I just realized today that the exclamation point doesn’t mean “not” (that would be a tilde, wouldn’t it?), it means “comment!”

However, I’m still confused about why John Clemens instructs authors of backdrop condition rules to refer to his “new location” variable (translated into the I6 global “location,”) rather than having them use the “location,” which is equivalent to I6 “real_location.” Does anyone know how to contact John Clemens, or why he would have said that?

I haven’t been following this thread very closely, but I know the answer to that final question: yes, you should definitely preserve the value of parameter_object, because it’s just a global variable and the next rulebook that gets called will almost certainly wipe it out. In particular, any and all Activities use it, and if you begin an activity with parameter_object of one value but end the activity with it being another value, bugs are almost guaranteed.

Okay.

I was surprised because that never happens in auto.inf. I think the only time parameter_object is assigned a value is in the ProcessRulebook routine, and the old value is not saved there.

So I’m not really sure what the I6 stack is used for. Is it better to save parameter_object on the stack, or in a local variable?

It’s a matter of code style whether you use a local variable or the stack. There’s no practical difference.

(I haven’t looked at the library usage of parameter_object, but it makes sense to preserve it, if only for the sake of future hackers.)