Elegant way to test whether something is in a location (even if in a container)

It doesn’t help that the various (spatial) relations aren’t completely defined together in any one place in the documentation.

There are 5 mutually-exclusive basic spatial relations between objects:

support- applicable only to supporters supporting things
containment- applicable only to rooms or containers containing things, or regions containing rooms or other regions
wearing- applicable only to people wearing things
carrying- applicable only to people carrying things
incorporation-applicable to any thing incorporating any thing

(incorporation is usually asserted by phrases or conditions such as ‘A is a part of B’ or ‘if A is a part of B’ although ‘B incorporates A’ or ‘A is incorporated by B’ are equivalent ways to express the same relation).

All these basic spatial relations describe only direct spatial relationships- so (counter-intuitively) if for example A contains B, which contains C, then A does NOT contain C; similarly if A carries B, which supports C, then A does NOT carry C.

There are two shorthand spatial relations (possession and holding) that combine basic direct spatial relationships:

A person has something if he/she/it (directly) wears or carries that something. Note that the built-in verb for the possession relation is ‘to have’ not ‘to possess’. Note that you can’t assert ‘John has the teapot’, because Inform thinks you might be trying to say that John has a property called ‘the teapot’. However, you can write ‘now John has the teapot’ (since once play is underway, the time for allocating properties to things is long past) in which case it means the same as ‘now John holds the teapot’ (see below) or also, in the case of a person (as here), ‘carries’.

A thing or room holds (or is the holder of) something if he/she/it (directly) supports, contains, wears, carries or incorporates that something. ‘To hold’ is somewhat complicated because (unlike ‘to have’) it can be used in a narrower sense as an assertion (‘John holds the teapot’) in which case it means the same as ‘to carry’ and therefore applies only to people. However, used as a condition (if the tray holds the teapot) it can apply to any thing or room, as a shorthand for any of the basic direct spatial relations, and similarly for example in phrases such as ‘now the Crypt holds the coffin’ (containment) or ‘now the tray holds the vase’ (support). A person can therefore hold something in three different ways- by carrying, wearing or incorporating it. A container can hold something in two ways- by containing or incorporating it. A supporter can also hold something in two ways- by supporting or incorporating it. Rooms and regions can hold something only by containing it (rooms and regions cannot incorporate things). Finally, a thing that is not a supporter, container, region, room or person can hold something only by incorporating it (but see Addendum regarding moving things through code).

As an additional complication, although a region cannot hold a room it can hold one or more regions. Conversely, by a special rule a region can contain a room, this being the only situation where an object contains something without holding it. It follows that a room can be both contained and regionally contained by a region- indeed, if it is contained by a region, it must also be regionally contained by it (see below).

‘Vague holding’ implies possession bug Inform currently has a bug (or at least an idiosyncracy) whereby in conditions of the form ‘if nothing holds the spanner’ or ‘if the spanner is held by something’ or ‘if a room holds the spanner’- i.e. where the potential holder is left somewhat vague- holding has a different interpretation equivalent to the possession relation i.e. ‘if a thing holds the spanner’ is interpreted as ‘if a thing (which is a person) holds the spanner’, so will be true only if the spanner is carried or worn. In other words it is equivalent to ‘if a thing has the spanner’. This means that ‘if a room holds the spanner’ (interpreted as ‘if a room (which is a person) holds the spanner’) can never be true. Similarly, ‘if nothing holds the spanner’ is actually equivalent to ‘if no one holds the spanner’ or ‘if nothing has the spanner’ and ‘if something holds the spanner’ is actually equivalent to ‘if someone holds the spanner’ or ‘if something has the spanner’. This issue can be circumvented by rephrasing, for example, ‘if a room holds the spanner’ to ‘if the holder of the spanner is a room’, or ‘if nothing holds the spanner’ to ‘if the holder of the spanner is nothing’.

In addition to the direct basic spatial relationships there are some indirect spatial relationships:

enclosure applicable to a room or thing directly or indirectly holding a thing or to a region directly or indirectly holding a region
room-containment applicable to a room directly or indirectly holding a thing
regional-containment applicable to a region directly or indirectly regionally-containing a room, or a thing enclosed by that room, or a backdrop [and since Ver.10 a region]

Because the first two of these indirect spatial relationships never specify exactly where and how the contents are held, they can’t be used in assertions. You can’t for example write ‘Now John encloses the teapot’ or ‘John encloses the teapot’.

Room-containment also has no specific built-in verb. It usually appears in source as conditions like ‘if the Kitchen is the location of the teapot’. You can define a verb if you like: ‘The verb to locate means the room-containment relation. The verb to be located in means the reversed room-containment relation’, after which you can write the equivalent condition ‘if the Kitchen locates the teapot’ or ‘if the teapot is located in the Kitchen’ although ‘if the Kitchen encloses the teapot’ or ‘if the teapot is enclosed by the Kitchen’ would do just as well. Note that ‘if the teapot is in the Kitchen’ always implies direct containment, not room-containment, so you must use ‘the location of’ or ‘encloses’ or a specifically-defined verb like ‘locates’ if you want to include things indirectly contained or held by a room.

Regional-containment similarly has no built-in verb. It usually appears in source as conditions like ‘if the teapot is in the Mansion’. This condition might theoretically be ambiguous as to whether is in implies ‘contains’ or ‘regionally contains’ but the ambiguity is usually resolved by whether the Mansion is a region (regional containment) or a room/container (containment). Rarely, the ambiguity is not so easily resolved- for example ‘if the teapot is in an-object-that-varies’- since ‘an-object-that-varies’ (as an object variable) could conceivably be at various times a region, a room or a thing. The important point here is that if the Inform compiler can determine at the time of compilation that the putative ‘containing object’ is definitely a region, it will apply a test of regional-containment rather than a test of containment. Note that the compiler can sometimes even work out that a variable must be a region, if you have created a global variable as ‘a region that varies’ or created a local variable to be a region with, for example, ‘let my_putative_container be the Mansion’. Conversely, the compiler cannot know whether a global or local variable declared to be an ‘object’ or ‘object that varies’ is currently a region or not. If the putative ‘containing object’ is definitely a room or container, or if it might conceivably be any of a region, room or container because it is an ‘object that varies’, then the compiler will apply a test of containment.

The best relation to use in determining whether a region is directly located within another region is, counter-intuitively and despite the suggestion of the I7 documentation, not regional-containment or containment but holding. ‘if Region A is regionally in Region B’ always returns false. ‘If Region A is in Region B’ or ‘if Region A contains Region B’ will also return false, because (as explained above) these phrases are interpreted by the compiler as testing regional-containment. Thus, although regions holding other regions also do contain them, it’s not straightforward to test a region for containment. Use ‘if Region A holds region B’ or ‘if Region A is the holder of Region B’ or ‘if Region B is held by Region A’. Enclosure can be used to include indirect holding between regions, e.g. ‘if Region A encloses Region B’. Avoid ‘if nothing holds’ or ‘if a region holds’ on account of the ‘vague holding implies carrying’ bug (see above). Rephrase these conditions to use ‘holder of’.
small print As noted above, it is possible to force the test of a region for containment by putting the holding region into ‘an object that varies’, (or an object variable in a loop- e.g. repeat with obj_putative_container running through objects…). This can cause confusion, if you were expecting ‘in’ or ‘contains’ to test for regional-containment in these situations. It is also possible to force the test of a region for containment by invoking the relation explicitly in phrases such as ‘if the Mansion is (the region which relates to the East Wing by the containment relation)’ (the brackets are required to help the compiler understand this phrase) or ‘the list of regions that the Mansion relates to by the containment relation’. See §13.13 in the documentation. Generally it’s just easier to use ‘If the Mansion holds…’. [this information has been superseded since Ver.10: as of the time of writing (Ver.10.1.2)- regions now regionally-contain regions that they enclose (and also, unexpectedly, themselves!) so ‘if the East Wing is in the Mansion’ and ‘if the Mansion contains the East Wing’ now work as one would naturally assume they would and the need for ‘if the Mansion holds the East Wing’ has receded somewhat- but is still needed to easily test for direct containment.]

Importantly, since regions cannot hold rooms, and enclosure depends on direct or indirect holding, the ‘cascade of enclosure’ is broken between regions and rooms, so rooms or any of their contents are never enclosed by a region. Regional containment provides the indirect relation between regions and rooms or their contents.

Although assertions locating regions within regions (‘the East Wing is in the Mansion’ or equivalently and pedantically ‘the East Wing is regionally in the Mansion’) might appear to be asserting regional containment, in fact they create the containing and holding relations. Regions can never regionally-contain other regions. [until Ver 10 that is- they now can, and ‘the East Wing is in the Mansion’ will also always indirectly creates a regional-containment relation] Such assertions imply a direct relation: (‘the East Wing is regionally in the Mansion’ implies that the Mansion directly holds and contains the East Wing) and they can therefore only be used to place a region (or a room- see below) within a region. In the above example, the East Wing must therefore be either a room or a region, not a container or some other thing or object. In the case of locating rooms in a region, either the regional containment or containment relation can be asserted (‘the East Wing contains the Kitchen’, or ‘the Kitchen is contained by the East Wing’, or ‘the Kitchen is in the East Wing’ (could imply either containment or regional containment), or ‘the Kitchen is regionally in the East Wing’ (regional containment) and in either case both containment and regional containment relations are created. Assertions like this can’t be made in play- ‘now the East Wing is regionally in the Mansion’, ‘now the Kitchen is in the East Wing’, or ‘now the East Wing contains the Kitchen’ are all disallowed, as are phrases such as ‘move the Kitchen to the East Wing’, which produce a runtime error.

The explicit uses of room-containment and regional-containment in source are limited. The I6 routine [LocationOf] is used both to define ‘the location of’ and the room containment relation (should a verb such as ‘to room-contain’ be defined for it in source)- but in practice ‘the location of an-object’ is generally used and room-containment is left redundant. Regional-containment exists as a means both to assert the relationships of regions and rooms and to allow phrases like ‘if the teapot is in the Mansion’- regions can never enclose or hold rooms or the contents of rooms they regionally contain, so ‘if the Mansion encloses the teapot’ will never be true- assuming the Mansion is a region and the teapot a thing- and ‘the holder of a-room’ is always nothing. Note also that there’s no directly equivalent built-in phrase ‘the region of an-object’, perhaps because unlike rooms which cannot (in the Inform sense) contain rooms, large regions can encompass one or more smaller regions, so there is not necessarily a unique answer to ‘what region is this object within?’. However, every room provides a ‘map region’ property that gives the ‘lowest-level’ region (if any) that regionally contains and contains it. So ‘the map region of the location of a-thing’ is available. You can also use phrases like ‘let my-list-of-regions be a list of the regions which relate to <a-thing> by the regional-containment relation’ to produce and search a full list of relevant regions. Note that as mentioned above, the map region of a room contains and regionally-contains but does not hold that room.

To summarise the complicated potential spatial relations of regions, they can:
contain†, hold and/or enclose other regions
contain roomsǂ
regionally-contain backdrops, or rooms, or things enclosed by those rooms [and since Ver 10] other regions

† but see notes above about testing for containment of regions
ǂ Note that this appears to contradict the Inform 6 Designer’s Manual 4 (DM4) which states in ‘§24 The World Model Described’ that ‘A room is (never) contained’- but this is due to a difference in terminology: the corresponding ‘law’, which holds equally true in Inform 7, would be ‘A room is (never) held’.

Small-print (1) doors ‘the location of’ a two-way door is usually the one out of the two rooms it links that was first mentioned in the source text, this being defined by Inform as the ‘front side’ of the door. The exception to this is if the player is in the room on the ‘back side’ of the door, in which case that becomes temporarily the location of the door. The room that contains the door defaults to its ‘front side’ but subsequently, becomes the room holding the most-recently-player-facing side of the door, (which may therefore be either the front side or the back side of the door). The location of a door also usually therefore contains that door (which therefore is in that location). However, the room which is the ‘other side’ of the door, being the one not most-recently-player-facing, does not hold or contain it and the door therefore is not in that room. See the Addendum for why this is so. However, a paradoxical situation can arise if the door ends up either through code (e.g. ‘now the oak door is in the Library’), or through automatic repositioning via the wanderings of the player, in the room that is the ‘back side’ of the door when the player is not also in that room. In this instance the location of the door will default back to being reported as the ‘front side’, but the ‘back side’ rather than the ‘front side’ will still contain and hold it. In short, the location of a two-way door is always the room containing its front side except when the player’s location is the room containing its ‘back side’, in which case that room is the door’s location. Furthermore, by a special rule a two-way door is always enclosed by the rooms to both front and back. The paradox created here is that the door is enclosed by one room which neither room-contains or contains or holds it, or indeed satisfies any of the basic spatial relations with it. This is the only situation in which an object encloses something it does not (directly or indirectly) hold. One-way doors are simply always contained, enclosed, located in and held by the one room they lead from.

Small-print (2) - Backdrops are equally complicated. The I7 documentation states that a backdrop has no location and is enclosed and contained by nothing, but this is not quite true. In general terms a backdrop is held and contained by the last room the player occupied where the backdrop was to be found- unless or until the places where the backdrop is to be found are changed and updated, or it is moved off-stage. See the Addendum for more detail and an explanation, plus the even stranger behaviour of a backdrop’s location. Strangely, there is no simple condition in I7 that tests whether a backdrop will be found in a particular room when the player is not presently there. It can if required be provided by this simple example of I6 hackery-
To decide whether (B - a backdrop) is found in (R - a room): (- (BackdropLocation( {B}, {R} )) -);
Also, if a backdrop is found in one or more of the rooms regionally contained by a region, the regional-containment relation applies and the condition ‘if a-backdrop is regionally in a-region’ is true- even if neither the current location of the player or the current location of the backdrop is. In this instance, the regionally of regionally in is required, not optional.

Inform also defines a number of what might be termed ‘calculated’ spatial relations, which can be tested for in conditions but not asserted:

adjacency applicable to a room which ‘is adjacent to’ a room
visibility applicable to a thing which ‘can be seen by’ a thing
touchability applicable to a thing which ‘can be touched by’ a thing
concealment applicable to a thing which ‘is concealed by’ a thing that holds it

These relations are determined by (sometimes complex) rules that are in part dependent on the simpler spatial relations described above (or in the case of adjacency, the various mapping relations) and they cannot therefore be simply asserted to be true or false. To make them so, the simpler spatial relations or other elements of the world state must be manipulated and/or the relevant rules must be written or altered.

As a useful shorthand, an ‘adjacent room’ means one adjacent to the location of the player; a ‘touchable thing’ means one the player can touch ; a ‘visible thing’ means one the player can see – although the last of these, confusingly, has a subtly different meaning in the context of defining new actions:

The meaning of ‘visible thing’ in Inform Many action definitions are akin to Watching is an action applying to one visible thing. The choice of the word ‘visible’ in action definitions to distinguish objects anywhere in the universe (by way of contrast to those that are merely touchable, or actually carried), is one of the more confusing syntax features of Inform, as in this special context ‘visible’ can sometimes include things which the player cannot see. This is compounded by the parallel existence of a visibility relation that also makes use of the adjective ‘visible’ and which has a meaning that is both subtly different and more conventional. Any object, whether conventionally visible or not, is a ‘visible thing’ in the context of action definitions. If this were not the case, the player would not ordinarily be able to invoke actions involving objects that are not physically enclosed by the same room as the player, the latter representing the absolute limits of conventional visibility.

Likewise the use of the word ‘thing’ in action definitions to mean ‘object’- when elsewhere ‘thing’ means a subgroup of objects that, in the basic world model, are not rooms, directions or regions (see the Kinds tab in the Index of the Inform documentation).

In summary, in the context of action definitions, and action definitions alone, ‘visible thing’ actually means ‘any object’.

Note that action definitions do not have any interest in ‘scope’- which defines which objects the parser can use to build an action in response to a typed command. Scope is enforced by grammar tokens (such as [something]) in Understand phrases (such as 'Understand “photograph [something]” as photographing. Ordinarily, objects matched by grammar tokens must be ‘in scope’. Actions invoked directly by code e.g. ‘try photographing the triffid’ need only match the action definition- they are unaffected by scope or the need to match grammar tokens.

Objects that ‘can be seen by the player’- and which therefore satisfy the ‘visibility relation’ and can be referred to in descriptions and conditions (as opposed to action definitions) as ‘visible’ objects- are usually ‘in scope’ and vice versa, but there are multiple exceptions- for example in the dark, the player’s possessions are in scope but not visible.

The qualifier ‘any’ applied to objects (or descriptions of objects) appearing in tokens of grammar lines, e.g. ‘[any door] or [any closed container]’, allows them to override the requirement for such objects be in scope (or, looked at another way, brings said objects into scope for that particular action). 'Understand “open [any closed container] as remote opening” thereby allows the ‘remote opening’ action to be invoked on any closed container, in-or-out-of-play, anywhere in the game universe, whether in scope or not, as long as remote opening is defined as applying to a ‘visible thing’. Possibly more usefully, [any room], [any adjacent room] etc. therefore allow the player to invoke actions referring to rooms, which are never ordinarily in scope.

Note also that ‘in play’ has a technical meaning in Inform as an adjective that can be applied to objects, which is that the object in question is enclosed by a room. Even objects that by this definition are ‘out of play’, such as directions, or other objects created ‘off-stage’ or ‘removed from play’ to ‘nowhere’ may be considered ‘visible things’ in the context of action definitions if the scoping rules decide that they are nevertheless ‘in scope’. An ‘out of play’ object can also be said to ‘be nowhere’ and an ‘in play object’ to ‘be somewhere’.

Adjacency A room is adjacent to another room if it is possible to move directly from one to the other by a mapped direction- perhaps surprisingly, 2 rooms connected only by a door (regardless of whether the door is currently open or unlocked) are not adjacent to each other. Although the documentation states that adjacency applies only to two rooms, possibly as a bug it also sometimes applies to a room and a door, but that fact probably shouldn’t be relied upon. As a convenience, the adjective ‘adjacent’ applies to any room adjacent to the player’s current location.

Concealment The definition of concealment (as an adjective) is that a thing is concealed if its holder conceals it. The relation of concealment is governed by the verbs ‘ conceals’ or ‘is concealed by’ through the activity ‘deciding the concealed possessions’, which by default is an empty rulebook, meaning that nothing is concealed. New rules written regarding certain things (such as ‘Mr Darcy’), or things grouped under a description (such as ‘a person’), or even the all-encompassing ‘something’, can decide according to any criteria they choose that they conceal any other given thing. The potentially concealed thing under consideration when the activity is run is called ‘the particular possession’. An example rule might begin Rule for deciding the concealed possessions of a person who is wearing a cloak:

Anomalous treatment of concealment invoked by adjective vs. verb If a question regarding concealment is phrased using ‘concealed’ as an adjective e.g. ‘if the pistol is concealed’ or ‘a list of concealed things in the location’ the ‘deciding the concealed possessions’ activity is called regarding the holder of e.g. the pistol, or the holder of each of the things in the location in turn, so that only rules in the activity rulebook matching the holder (in the first example, if the holder of the pistol wears a cloak) will be considered. However, if the question is phrased as a condition regarding described or specified ‘concealer(s)’ and with ‘conceal’ as a verb, e.g. ‘if Mr Darcy conceals the pistol’ or ‘if the pistol is concealed by a woman’ –thereby invoking the concealment relation directly- the activity is called (in the first example) regarding Mr Darcy- and if Mr Darcy is wearing a cloak, the above rule will be considered whether or not Mr Darcy holds the pistol. If the rule itself doesn’t ask whether or not Mr Darcy is the holder of the particular possession (the pistol), it may decide he is concealing a pistol that is not even in the same room. In this instance the conditions ‘if Mr Darcy conceals <some distant object>’ or ‘if <some distant object> is concealed by something’ will test true, whereas ‘if <some distant object> is concealed’ will test false, and functionally the concealment will have no effect as the distant object will remain fully visible and interactive. EDIT: (This anomaly has been partially corrected in v10- by default (if no spatial relation is specified) a thing must directly hold a thing it conceals, and things cannot conceal things they do not enclose, but ‘Rule for deciding the concealed possessions of Mr Darcy when Mr Darcy encloses the particular possession…’ still leads to the anomaly)

The simplest way round this potential anomaly is either to always work with the ‘concealed’ adjective, or to ensure that rules for deciding the concealed possessions of something can only report a positive decision if the ‘particular possession’ is actually directly held by the ‘concealer’ under consideration. A good way to enforce this restriction is to include it in the opening declaration of the rule, e.g. ‘Rule for deciding the concealed possessions of a person (called the concealer) who holds the particular possession when the concealer is wearing a cloak:’

Indirect concealment Inform’s default definition can be counter-intuitive for indirectly held things- a thing is only concealed (adjective) if its direct holder conceals it. Conversely, a person who conceals (verb) a bag may also (in Version 9.3 if no holding requirement is enforced, or in Version 10 if the rule states ‘when (the person) encloses the particular possession’) conceal the bag’s contents, but the bag itself does not conceal its contents and the contents are not concealed(adjective). This is probably unintended, since functional concealment is only fully implemented when direct, so it is advisable to arrange things so that all concealed things are directly concealed by their holder. This will ensure that conceals (verb) is always aligned with concealed (adjective) and that concealed things are also functionally concealed in the game world. Indirect concealment is functionally implemented (in that the contents of concealed things are also functionally concealed), even though they are not ‘concealed’ (adjective) and ‘nothing conceals them’ (verb). To test for indirect functional concealment, conditions like ‘if something concealed encloses…’ or ‘list of things enclosed by something concealed’ work.

Useful undocumented phrases. Some useful built-in but undocumented phrases that work with spatial relations, although they don’t define new relations:

See Addendum below…