Dialog Floating Objects

I’m looking for the best way to un-attract objects from a room, that is if I have an object attracted to multiple rooms how do I remove the attraction to one or more or all attracted rooms?

If I want to remove the object from all of the attracted rooms I can define the object as being in multiple rooms using (* is #in #room1)(* is #in #room2) and then now the object to nowhere. This seems to work, and does make it easy to move the object back into multiple rooms, but is there something I’m missing, does this break something else?

Thanks in advance.

1 Like

So you want it to only be attracted to a certain room under certain conditions?

((room $) attracts #moon) ~(eclipse is happening)

This means that the moon is attracted to every room, as long as the eclipse is not happening. Replace (room $) (“anything that is a room”) with the name of a specific room, or a region, etc, if you like.

You can also make a new per-object flag that removes a floating object from all rooms, if you want:

($ attracts $Obj)
    ($Obj is absent)
    (just) (fail)

This will need to be listed before all other attraction rules, in order to override them. But it allows (now) (#moon is absent) and (now) ~(#moon is absent) to remove and un-remove the moon, or any other object, from the world.


Thanks, the first option was what I was looking for. I am however having issues. Using the following:

(current player #player)
(#player is #in #room1)

(name *) Room 1
(look *) The first room. East
(room *)
(from * go #east to #room2)

(name *) Room 2
(look *) The second room. East and West
(room *)
(from * go #west to #room1)
(from * go #east to #room3)

(name *) Room 3
(look *) The third room. West
(room *)
(from * go #west to #room2)

(name *) moon
(appearance *) There is a full moon tonight.
(#room1/#room2/#room3 attracts *) (full moon)

(prevent [wait]) (full moon)
moon is absent
(now) ~(full moon)
(try [look])

(prevent [wait]) ~(full moon)
moon is present
(now) (full moon)
(try [look])

Waiting moves the moon into the three locations but waiting again only removes the moon from two locations. The room where the wait command was issued still has the moon. If I move to another room, wait twice, the moon is now in the new room and not the other two. What am I missing? Thanks in advance,


Am interested to hear the solution. As a sidebar, is there a terse reference/explanation for why the maneuver

~(#room1 attracts #moon)

is unsupported?

Ah, that comes down to how floating objects work. When the player enters a room $Room, the library runs a multi-query for ($Room attracts $Obj), and moves all those $Objs to be #in $Room.

But it never explicitly moves them away again. So changing the attraction will prevent it from being summoned into new rooms, but won’t stop it from lingering in the room where it already was.

The easiest way to fix this is just to add (now) (#moon is nowhere) after (now) (full moon).


I believe it does work; it just doesn’t automatically move things away again (because attraction only moves things into the location, it never gets rid of them again except by moving them somewhere else).

Changing the two prevents in the above code to the following solves my problem, thanks.

(prevent [wait]) (full moon)
	moon is absent
	(now) ~(full moon)
	(now) (#moon is nowhere)
	(try [look])
(prevent [wait]) ~(full moon)
	moon is present
	(now) (full moon)
	(update environment around player)
	(try [look])

Thanks again.


No, it rejects it out of hand demanding that the right side be anonymous. Which is a thing I don’t especially grasp.

Ohh, I see what you mean now.

“Per-object variables” in Dialog are effectively many-to-one relations, not many-to-many (I think the standard implementation is literally a property on the object, using the Z-machine property table). As soon as you use (now) with the predicate ($ attracts $), it becomes a per-object variable: each room can attract at most one object. Think of it as room.attracts = obj in C/Python/I6/etc terms.

And because of this, the compiler gets confused about (now) ~(#field attracts #moon): you’re saying that field.attracts should not be set to moon, but you haven’t said what it should be set to. As a special case, though, (now) ~(#field attracts $) is allowed: that’s equivalent to field.attracts = NULL (“now the field doesn’t attract anything at all”).

Currently, as far as I know, Dialog doesn’t support dynamic many-to-many relations. You could implement them with a list of pairs, but that would be messy and probably not very efficient.


So then, to expand on the floating object example from the manual:

(name *) wallpaper
(descr *) Brown and austere.

(#library attracts *)
(#foyer attracts *)
(#study attracts *)

Let’s say one wanted to make this brown, austere, and edible wallpaper, such that

>eat wallpaper

in the library gets you a “yum” message, and then the wallpaper doesn’t exist in the library anymore, but still exists in the foyer and the study.

Is there an elegant way to deal with that kind of scenario? Or is that a “don’t use $ attracts $ if that’s what you want to do” kind of deal?

1 Like
(prevent [eat #wallpaper])
    (current room $Loc)
    ($Loc has been depapered)
    There's no paper left to eat!

(perform [eat #wallpaper])
    (current room $Loc)
    (now) ($Loc has been depapered)
    (now) (#wallpaper is nowhere)
    Mm, tasty wallpaper.

((room $Room) attracts #wallpaper) ~($Room has been depapered)

That’s very helpful, thanks!

Two things:

  • I had to throw (edible *) on the #wallpaper to get past the default “isn’t edible” message. That seems normal.
  • The prevent never comes into play, if I try to eat wallpaper in a room where it’s already been eaten I just get the default
> eat wallpaper
(I only understood you as far as wanting to eat something.)

That also seems normal to me, but it also seems like you included it for a reason…

Ah, right, I wrote that quickly and didn’t actually test it. You’re correct, the prevent rule will never actually come up.

1 Like