Scenery in multiple locations

I was poking through Calypso and saw it uses an Inform feature, a found_in property.

I figure it’s implemented one of two ways:

  • Either the object resolver has to iterate over all objects with a found_in property to see if they match the current room
  • Or the runtime “moves” the scenery object into the player’s current room as necessary.

I’m wondering if there’s a third way in the Z machine at least:

  • Make several dummy objects that exist in all necessary locations. This could get a bit expensive but
  • …all those objects could share the same property table.

The break-even point depends on how many places an object appears, how much code (and execution time) is required to implement other solutions, and whether you’re targeting V3 (9 bytes per object) or V5 (14 bytes per object).

Thanks,

-Dave

1 Like

This is what Inform does, both for the old found_in property and I7’s Backdrop type.

  • …all those objects could share the same property table.

Possibly interesting.

If you’re targetting z3, then objects are a tightly limited resource. If you’re targeting Glulx, saving bytes isn’t a high priority. So this would only be worthwhile for z5, I think.

The compiler isn’t set up to do shared property lists. You could make a bunch of objects with no properties and then manually repoint their property tables at startup time.

1 Like

Additional context:

If you program using PunyInform, there’s a constant (MAX_FLOATING_OBJECTS) you can define, to say how many such moving (AKA “floating”) objects the library needs to handle in a game. It defaults to 32. When the game starts, the library populates an array holding all the objects that have the found_in property, so it can iterate over them every time the player enters a new room, at a low cost.

IIRC, early versions of the Inform 6 library did this as well. Nowadays it iterates over all objects every time the player enters a new room.

1 Like

zillib (the “Infocom”-library for Zil) have two solutions for scenery objects.

  1. Define a number of objects as LOCAL-GLOBALS (ordinary objects but placed under the object - LOCAL-GLOBALS. Every room can then define in a property (GLOBALS) which local-globals-objects that exists in this room. Typical object for this is for example water that should exist in multiple rooms.

Example from Zork 1:

<OBJECT GLOBAL-WATER
	(IN LOCAL-GLOBALS)
	(SYNONYM WATER QUANTITY)
	(DESC "water")
	(FLAGS DRINKBIT)
	(ACTION WATER-F)>

<ROOM RESERVOIR-SOUTH
      (IN ROOMS)
      (DESC "Reservoir South")
      (SE TO DEEP-CANYON)
      (SW TO CHASM-ROOM)
      (EAST TO DAM-ROOM)
      (WEST TO STREAM-VIEW)
      (NORTH TO RESERVOIR
       IF LOW-TIDE ELSE "You would drown.")
      (ACTION RESERVOIR-SOUTH-FCN)
      (FLAGS RLANDBIT)
      (GLOBAL GLOBAL-WATER)
      (PSEUDO "LAKE" LAKE-PSEUDO "CHASM" CHASM-PSEUDO)>
  1. Rooms also allow a THINGS propery (also called PSEUDO in older versions of the library). This property lists a couple of dictionary words that is associated with a function. This approach doesn’t cost any extra objects.

Example from Craverly Heights (ZIL-version):

<ROOM INTERSECTION
    (DESC "Hallway Intersection")
    (IN ROOMS)
    (LDESC 
"Nobody's around.||
The hallway runs north, south, east, and west from here.||
A non-diegetic bulletin is posted on the wall.")
    (NORTH TO N-HALLWAY)
    (WEST TO W-HALLWAY)
    (SOUTH TO S-HALLWAY)
    (EAST TO E-HALLWAY)
    (FLAGS LIGHTBIT BACKSTAGE)
    (THINGS (NON-DIEGETIC DIEGETIC) (BULLETIN) BULLETIN-F)>

<ROUTINE BULLETIN-F ()
    <SETG PSEUDO-OBJECT-NAME "non-diegetic bulletin">
    <COND (<VERB? EXAMINE READ> 
           <TELL "The bulletin reads: ">
           <ITALICIZE 
"Hey! You, with the keyboard!
Let me know what you think of this game on Twitter
(\@rcveeder) or via email (rcveeder\@me.com).||
Here's a tip: To finish the game, you're going to have
to use the verb SHOW, as in \">show THING to PERSON\".
You might also have to \">point THING at PERSON\" at
some point.||Thanks for playing.">
           <CRLF>)
          (ELSE 
           <TELL "You're not supposed to pay too much attention to that." CR>)>>
4 Likes

The pseudo objects are particularly interesting, since they don’t consume any object slots.

My parser is table-based (big surprise) and scans each row for a verb match, and then can thunk to arbitrary routines to resolve the adj/noun to an object. The routines could then look at the player location for a pseudo property to match any of the nouns and call the matching pseudo handler on a match.

I was wondering why the first thing it does is set a global – but that makes sense, because the rest of the parser still needs to refer to an actual object, so I assume one object is reserved as a proxy for any pseudo object being processed?

Thanks,

-Dave

Oh, it’s a expansion PRINTD I used in that game so that the objects short description can be the result of a function and allow an object to be described differently at different phases of the game. The PSEUDO-OBJECT-NAME global is just a way to give the PSEUDO-object a full description text.

(I barely remember how I used it, but here is the code.)

PunyInform has a similiar concept as PSEUDO called cheap scenery but @fredrik can describe that better than me.

The cheap scenery extension that’s included with PunyInform (but can also be used with the standard library), adds one floating object that is moved from room to room. If the room object provides a cheap_scenery property, this should be an array, basically holding dictionary words that represent a scenery object, and either a string that’s used as the description for that object, or a routine that’s used as a before routine, possibly followed by a new set of dictionary words, another string or routine etc. It’s a quite efficient way of adding as much scenery as you like.

1 Like

There’s also GLOBAL-OBJECTS and there are ways of deciding scope, which I prefer when the scenery is in every room but one, for example.

1 Like

So I actually took a stab implementing this last night, but the syntax got ugly because you needed to declare a new dummy object name, and reference what you wanted to clone, and where to put it.

So an extra 9/14 bytes per scenery (plus the actual code to implement descriptions etc) seemed to be a wash compared to some of the other solutions presented here, which didn’t actually consume any objects (which as noted, are in extremely short supply in V3).

One interesting bit though… if you had identical objects in different parts of the world, cloning them like this (sharing the property table) could actually be useful, particularly since they would have a unique set of attributes.

Of course if you picked one up and moved it next to the other, the parser would be really confused.

But they could, for example, be used for two (fixed) switches for the same device in two different rooms. But that’s a bit of a stretch…

Dave

(Thinking it over some more, psuedo-objects would be another good use for something like a light switch, so I guess it’s just a silly idea to try to share the property tables)

2 Likes

PSEUDO objects in Infocom games are mainly used to provide small responses when a Player tries to interact with them and save on space by using the same ACTION routine for each copy. However, there are no persistent states (like flags and properties) in those objects.

So if you need persistent states then LOCAL-GLOBAL objects are better. You can make multiple copies of a single object and use it multiple locations. However, changing one property or flag will change it for all of the copies. If you needed copies to have their own individual states, then you’d need to use a table to store this. It is also more difficult to “move” a LOCAL-GLOBAL object around, but you could do it by altering the GLOBAL property in the source and destination rooms.

Are you just trying to save space with multiple copies of a minor object?

Because I’m writing an Inform-ish language myself from scratch, I was trying to think of weird outside-the-box ways of saving memory so that Z3 games could be as fleshed out as possible.

“PSEUDO” objects existed in the Magnetic Scrolls IF system too, and were also used for scenery.

FYI

A Pseudo is an object with multiple locations. It has a complete set of data properties, but the location field is instead a pointer to a zero-terminated list of locations. Scenery was often pseudos, when it was in multiple locations. Doors were usually pseudos because they existed in two adjacent locations. The state of the door (eg open/closed) was also then consistent.

You could locate another object to a specific pseudo. For example a note pinned to a door could be on just one side of the door. This was done by locating to the pseudo and a specific location.