I get so mixed up between ‘incorporates’ and ‘is incorporated by’. I usually just try one and test my game and flip it if it’s wrong.
This post is going straight to the pool room.
Easy way is probably to remember that ‘is incorporated by’ means the same as the similarly-structured and more intelligible phrase ‘is a part of’.
So, if ‘is a part of’ makes sense, just use that, otherwise it’s ‘incorporates’.
Reading this post, I realise my own understanding of the system was still missing some of the more baroque nuances. Can we agree that the standard Inform world model serves mostly as an opportunity to have a laugh at the expense of people’s seemingly solid implementation attempts and that we are fools for even trying?
Though I note a “visible thing” doesn’t mean what anyone would reasonably assume it means. Correct?
As I understand it
Asking-about is an action applying to one visible thing.
applies to a thing that is in-play. While
if grandpa is visible:
is true if grandpa is visible to the player.
Is that right?
You are correct. The choice of the word ‘visible’ in action definitions to distinguish objects anywhere in the universe that the player is allowed to refer to, by way of contrast to those that are touchable or carried, is one of the more bizarre and confusing syntax features of Inform, compounded by the parallel existence of a visibility relation that 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, that is brought ‘into scope’, as Inform puts it, is a ‘visible thing’ in the context of action definitions. If this were not the case, the player would never 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.
In summary, in the context of action definitions, and action definitions alone, ‘visible thing’ actually means ‘any object the player is allowed to refer to’. or, in more technical Inform-speak, ‘any object in scope’ **
PS in play also has a technical meaning in Inform, 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’.
** note that the use of 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 ‘visible things’ to be in scope. 'Understand “open [any closed container] as remote opening” thereby allows the action to be invoked on any closed container, in-or-out-of-play, anywhere in the game universe, whether in scope or not. 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 and thus are not ordinarily ‘visible things’.
The perverse and confusing terminology in action definitions is perhaps the thing I would most like changed in a future version of Inform 7 as a core language change. Replace “thing” with “object” and “visible thing” with “any object” or “object anywhere”, perhaps. It is very hard to keep track of the weirdness that is the use of “thing” and “visible thing” in action definitions.
I would also love it if the two different methods of declaring formal parameter names – one for actions
a container (called item)
and one for phrases
(item - a container)
…could be unified and made interchangeable, as I keep using one in the context of the other (I’ve reversed it both ways – it’s my single most common syntax error).
It’s perhaps not really ‘any object’ or ‘object anywhere’ because scoping rules are by default applied unless overridden by using ‘any’ in the relevant grammar token.
I assume ‘thing’ and ‘visible’ were chosen as more naturally intelligible terms than ‘object’, and ‘in scope’ so it’s unfortunate that they end up confusing because the former terms have more restrictive formal meanings elsewhere in Inform.
Personally, I think 'object in place of ‘thing’ would be OK (although ‘item’ would be an alternative) and I am struggling to think of a more intelligible synonym for ‘in scope’ that fully captures the sense of it. Candidates might be ‘accessible object’ or ‘available object’ or ‘mentionable object’. Perhaps, in the end, since ‘in scope object’ is formally what is meant here, that should be it!
The (called item) syntax is also the one used in ‘Definition:’ declarations, conditions, and the declaration of relations, whereas as far as I can recall the (item - container) is only used in phrase declarations? If so, at least it’s just the exception for phrases that has to be remembered
And if we are fantasizing… as Inform7 changes, it would be nice if it recognized the old syntax as an error and pointed you to the new syntax in the messages it produced ala git.
While revising old code it took me a while to realize that procedural rules had been deprecated. I was irritated that the compiler didn’t offer a friendly note about that
Hm. There was (and still may be) a use option for your source like this:
Use no deprecated features.
I remembered its existence and using it in version 6G60 of Inform, but searching for ‘deprecated’ in the docs now returns one results, and nothing about this option. So I don’t know if it has become undocumented, or if it’s been deprecated itself. But until someone who knows that chimes in, maybe add it and see if it throws complaints about procedural rules in your source.
Procedural rules went beyond deprecated and were removed entirely… [http://inform7.com/changes/CI_7_10.html]
While we’re on the topic of what could kindly be termed ‘idiosyncracies’ in Inform, others have previously expressed frustration at the bizarre way that ‘includes’ for snippets is equivalent to ‘matches’ for texts, while ‘matches’ for snippets is equivalent to ‘exactly matches’ for texts- in phrases such as 'if the player’s command matches “take aardvaark”, replace the matched text with “take anteater”.
This can be fixed by adding the following to source text, which also adds phrases to allow the negation of conditions matching regular expressions to texts:
To decide if (s - a snippet) matches (t - a topic): if s includes t, yes; no. To decide if (s - a snippet) does not match (t - a topic): if s includes t, no; yes. To decide if (s - a snippet) exactly matches (t - a topic): if s includes t : if the matched text is s: yes; no. To decide if (s - a snippet) does not exactly match (t - a topic): if s does not include t : yes; if the matched text is not s: yes; no. [these phrases align the syntax for matching snippets to that for matching texts- ordinarily 'matches' for snippets == 'exactly matches' for texts, and 'includes' for snippets=='matches' for texts] To decide if (t - a text) does not match the regular expression (r - a text): if t matches the regular expression r, no; yes. To decide if (t - a text) does not exactly match the regular expression (r - a text): if t exactly matches the regular expression r, no; yes. [this is a syntax inexplicably missing from Inform- without these phrase definitions compiler will throw an error as it tries to set up a match between a snippet and a topic (as in 'the player's command does not match "room [number]") rather than a text with a text, not helped by the absence of a logical 'not' in complex conditional phrases- so we can't say 'if X and not Y ...' or even 'if X and unless Y...']
I think you just wrote an Extension, once some documentation is written. Hint Hint Hint.
…or if you don’t want to, I can make that into an extension.
…snippet weirdness has been on my mind because I’ve been wrestling horribly with snippets lately. There is some high weirdness with rules which have a snippet involved.
Ordering it that is an action applying to one thing and one topic. Riposteing it that is an action applying to one thing and one topic. Understand "instruct [someone] to [text]" as ordering it that. Understand "answer [text] to [someone]" as riposteing it that (with nouns reversed). Check riposteing something (called item) that (this is the riposte redirect to order rule): try ordering item the topic understood;
The try doesn’t compile. I may just be missing a piece of syntax, but I haven’t figured out a way to do it.
I had an interesting exchange on this topic (ha ha) here- Topic variables and text in I7
If you haven’t already hit on it, what you’re looking for is
try ordering item that the topic understood;
Thank you very much. This deciphered a syntax puzzle for me and I now have it passing through a chain of checks properly…
…it’s amazing how deep into the code I’ve gotten trying to get “giving orders to NPCs” to work cleanly with multiple synonyms and good errors, while still making it easy enough for the game author to override. I’m far from done, but my hope is that a more generous parser and more comprehensible errors will give a better “feel” to NPCs even if the NPCs remain very simple. Work to date is in my Compliant Characters extension.
Addendum- understanding the behaviour of Inform’s spatial relations.
This is an addendum to my earlier post above regarding Inform 7’s spatial relations.
That has also been edited to:
(i) clarify and expand some passages
(ii) correct a number of inaccuracies, particularly with regard to regions
(iii) add some further useful undocumented information
Although there are a number of quirks to the implementation of Inform’s many spatial relations, in large part these are explicable by an understanding of the underlying implementatation model.
Objects in the Inform World Model are arranged into an Object Family Tree, within which any object can only be directly connected to one parent, sibling and/or child. This simplified description does not take account of incorporation, which uses similar ideas but is differently implemented and will be discussed later. Furthermore, in practice the Object Tree is typically broken up into a number of separate trees, usually with a room as the ‘top’ parent in each, and sometimes even with isolated objects that have no parents, siblings or children.
Library Nebulous Thingumajig | | <-contains v Bookcase----->Writing Desk----->Sherlock Holmes----->Green Door | | | | <-contains | <-supports |<-carries v v v Dictionary Lamp Pipe----->Deerstalker(worn)
In the Object Tree, objects are connected only in these three basic one-to-one correspondences- parent, sibling and child. Although formally an object only has one child and/or sibling by direct connection in the Object Tree, they are also talked about as groups of siblings and children, each in a group of siblings having the same parent, of which they are the children. In the above diagram, the child of the Library is the Bookcase and the children of the Library are the Bookcase, Writing Desk, Sherlock Holmes and the Green Door. The sibling of Sherlock Holmes is the Green Door and the siblings of Sherlock Holmes are the Bookcase, Writing Desk and Green Door. The parent of Sherlock Holmes is the Library. Although hidden deep within Inform 7, the structure of the Object Tree occasionally reveals itself. For example, when listing miscellaneous items in a room description, these are generally listed with the ‘eldest’ child of the room location first, then in sibling order. The ‘eldest’ sibling is the one most recently moved to its parent. When an object is moved to a parent, it therefore becomes the child of that parent, and the previous eldest child becomes its sibling. Knowing this allows the order of printing of miscellaneous items to be controlled- even if an object is already in the location, moving it to the location moves it to the top of the list for printing. You will notice that taking then dropping an object in the location has the same effect, and for the same reason.
Note that rooms do not have siblings or a parent. They are connected to other rooms by mapping relations and to regions via their ‘map region’ property, neither of which are part of the Object Tree.
Considering how parent, child and sibling connections are manifest in Inform’s basic spatial relations, the latter are determined by the kind of the parent object. A room or container’s children are contained by it. A supporter’s children are supported by it. A person’s children are carried by it, unless they have the I6 ‘worn’ attribute (in I7 terms, somebody wears them), in which case they are worn rather than carried. Put the other way round, something is contained if it is one of the children of a room or container, supported if it is one of the children of a supporter and worn or carried if it is one of the children of a person. An object such as the Nebulous Thingumajig in the above diagram is said to be ‘off-stage’ or ‘nowhere’.
It should now be clear why the basic spatial relations covered so far are mutually exclusive. Since the only way to know how a child relates to its parent is the kind of its parent, the parent cannot be allowed to be more than one of a room, a supporter, a container or a person. If an object were to be at the same time a supporter, a container and a person, Inform has no way of knowing if its children are being supported, contained or carried. Furthermore, an object cannot be both worn and carried, because the state of the either-or attribute ‘worn’ determines which it is. Also, since an object can have only one parent, it cannot be contained/supported/carried or worn by more than one object.
Small print Note that while in theory canonical, the restriction that the a parent must contain, support, wear or carry one of its (unincorporated) children by being one of the relevant kinds is currently only rigorously enforced when the world is being initially set up, or when objects are placed or moved through actions- such as typing ‘Put the cat in the aspidistra’ or code like ‘try putting the cat in the aspidistra’. Writing ‘The cat is in the aspidistra’ for example automatically creates the aspidistra as a container, even if elsewhere it is defined as a thing.
However, even if the aspidistra is none of container, supporter, room or person, placing or moving things directly through code once play is underway- through phrases such as ‘now the cat is in the aspidistra’ or ‘move the cat into the aspidistra’- is allowed (when it probably shouldn’t be), and this case results in the poor beast becoming trapped inside the herbaceous perennial. The cat ends up held and enclosed by the aspidistra- but not contained, supported, carried, worn or incorporated (since its parent is none of the relevant kinds and no incorporation relation has been created). In fact, code similar or equivalent to ‘Now the aspidistra carries…, Now the aspidistra wears…, Now the aspidistra contains…, Now the aspidistra supports…, Now the aspidistra has…, Now the aspidistra holds…’ are all interchangeable and simply insert the cat as a child object of the aspidistra without checking which of Inform’s spatial relationships are created!
Given that an object that is not a container cannot be made transparent, the unfortunate feline remains forever unreachable and invisible- like a fossil concealed inside a rock- unless the deus ex machina of further code releases her. The game effect is similar to sealing the animal inside a closed, opaque, unopenable container. Quite apart from the interest the RSPCA might take in the situation, it should go without saying that this kind of behaviour is not encouraged.
<--Estate Nebulous Thingumajig . | r . | <-holds, contains & encloses-++++++++++ e . v | g <--Mansion-------------------->Gardens encloses i . | v o . | <-holds, contains & encloses-++++++++++ n . v a <--East Wing------------------>West Wing l . . l . . (via 'map region') y . . <-contains (**but does not hold**) . v c .->Library o . | n . | <-contains & holds t . v a .->Bookcase----->Writing Desk----->Sherlock Holmes---->Green Door i . | | | n . | <-contains | <-supports |<-carries/wears s . | & holds | & holds | & holds & has . v v v .->Dictionary Lamp Pipe---->Deerstalker(worn)
Above is the previous object tree extended to show some regions. Regions exist in one or more object trees of their own, separate from other objects. In Inform, without exception every parent holds each of its children. Therefore rooms, containers, supporters and people hold their children as well as containing/supporting/carrying or wearing them. It also follows that regions hold their child regions, but do not support/carry or wear them. Regions also therefore enclose (directly or indirectly hold) their child regions and their grandchild regions etc. but never rooms, since regions can never hold a room. Although regions do contain any regions they hold, testing for this in Inform is awkward and often confusing due the the ambiguity (between containment and regional-containment) of the terms ‘in’ and ‘contains’ when talking about regions (see post 7 above). Generally it’s best to use the holding relation for regions.
Object trees of regions are connected to rooms and rooms’ object trees not by parent/child connections but through a property provided by every room- its map region. A room’s map region may be nothing, in which case it is not in any region, but if the property is a region, that establishes a connection which by a special rule means the said region contains that room. This is the only situation in which an object contains something it does not hold. It also means that the same region, and that region’s parent (if any), and grandparent, and great-grandparent etc. regionally-contain the room and the room’s entire object tree. It does not mean that the region holds the room- it does not- holding applies only to parent/child connections.
Writing Desk : | : | <-supports : | & holds : v : Lamp : : <-incorporates & holds v Left Drawer==========>Right Drawer====>Inkwell : | | : | <-contains & holds | <-contains & holds : v v : Pen Ink : : <-incorporates & holds v Secret Compartment | | <-contains & holds v Key
It remains to describe the implementation of incorporation. Above is an expansion of the Writing Desk encountered in the preceding example object tree. As well as supporting the Lamp, it incorporates two drawers and an Inkwell, containing some Ink. The left drawer contains a Pen but also itself incorporates a Secret Compartment, which contains a Key. Thus an extensive additional object tree is hung off the Writing Desk through the top-level incorporation relation. This does not break the object tree rule that an object has at most one child by direct connection, because the incorporation relation is not implemented within the main object tree model but through three I6 properties provided by things that either incorporate something or are part of something else: component_parent, component_sibling and component_child. These properties do exactly what their names suggest- they hold a reference to the thing (if any) that is the property-providing thing’s parent, sibling or child by incorporation. These relationships are shown by double-dotted lines in the above object tree- so the Left Drawer has component sibling of the Right Drawer, component parent of the Writing Desk and component child of the Secret Compartment. Although incorporation is implemented slightly differently and separately to the main object tree, it remains the case that a component parent holds its component children (as well as incorporating them) and that an object can have only one parent, which holds it, either through one of the four types of relation represented by the main object tree (containment/support/carrying or wearing) or through incorporation. Similarly, objects enclose all objects within an object tree they incorporate, so in the above example the Writing Desk encloses the Ink. Indeed, so does the Library- the ‘cascade of enclosure’ is not broken by incorporation.
It should now be evident how Inform’s holding and possession relations work: holding exactly represents any parent/child relationship (including being a parent/child through incorporation), and enclosure any unbroken cascade of parent/child relationships (including through incorporation). Possession represents the parent/child relationship (not including incorporation) between a person and its children.
Understanding the Object Tree also provides some insight into the quirky spatial relationships of doors and backdrops. An object can only ever have one parent and therefore can only occupy one place in the object tree. How then can doors and backdrops appear in more than one room? The answer is ‘by sleight of hand’. Inform keeps a record of (or knows how to work out) which rooms a door or a backdrop are found in, and if the player enters one of those rooms, quickly moves all relevant doors and/or backdrops to the player’s location before anything is printed, creating the illusion that they had had been there all along. This quick-change-act is ordinarily only triggered when the player moves to a new location, which for doors (being always static) is fine, but it can be caught out if between moves of the player some condition changes that means a backdrop should now suddenly be present in or absent from the player’s current location (e.g. the moon coming out from behind a cloud). This is the reason that Inform provides the phrase ‘update backdrop positions’ so that backdrops can be moved around the object tree between turns or even mid-turn if necessary. All this explains why despite being found in more than one room, a door or a backdrop has, at any given time no more than one room which holds and contains it. That will usually be the most recent location the door/backdrop was moved to- being generally the last room occupied by the player in which the door/backdrop is to be found. As noted previously, a backdrop is the only kind of object not to be enclosed by an object it is held by.
Very small print- location of backdrops With the location of two-sided doors and backdrops, especially backdrops, things get really weird. For small print on the location of doors, see the previous post. The I7 documentation states that backdrops have no location, but that isn’t true in the sense that ‘the location of a-backdrop’ is rarely nothing. To understand what’s going on, it needs to be appreciated that which rooms a backdrop (or two-sided door) is found in is information stored in an I6 property array called found_in. A two-sided door has an array with two entries, corresponding exactly to the front side and the back side of the door. For a backdrop, in the simplest case the array comprises a list of named rooms derived from assertions in the source such as ‘The moon is in the Skylight Room and the Carpark’. → I6 ‘with found_in skylight_room car_park,’. However, instead of being just one room, an entry in the array can instead reference an I6 routine that when called returns true if the player’s location is among one or more different rooms- similar to e.g. ‘with [; if (location == skylight_room or car_park) rtrue; rfalse;]’. Such a routine will usually be the first element of the array, and in deciding during play whether to move a backdrop to the current location in the object tree, if Inform finds a routine as the first element of the array it stops there and doesn’t consider further entries. Conversely, when determining ‘the location of’ a backdrop, if the backdrop hasn’t already been moved to the player’s current location Inform will cycle through all the entries of an array until it finds either (i) a routine that returns true for the player’s current location, or (ii) any simple named room.
During setup, if at least one statement defining where a backdrop is found is implemented as a routine (i.e. the backdrop is found in at least one region) the compiler rolls all such statements together into one routine and found_in only ever has one entry with one routine (the initial one or a replacement during play). Note that all statements redefining in play where a backdrop is found are implemented as a routine: (‘move the (a-backdrop) backdrop to all (description-of-rooms)’, ‘move the (a-backdrop) to (a-region)’, ‘now the (a-backdrop) is everywhere’)- a reference to this routine replacing the first entry in the found_in array. The exception is ‘now the (a-backdrop) is nowhere’, which moves the backdrop out of the object tree and sets its I6 ‘absent’ attribute to true, leaving found_in unchanged.
This means something odd happens if during setup found_in is created with multiple entries as a list of room names,e.g. (with found_in skylight_room car_park,) but then the backdrop is moved with e.g.‘move the moon backdrop to all windowed rooms’: now found_in still has two entries and looks something like ‘found_in <routine returning true when player’s location is a windowed room> car_park’. This leads to the following anomaly: when the player is not in a windowed room (e.g. in the Cellar, or the Car Park) the backdrop is not present, as the backdrop position updating routine bails after failing to find a match to the player’s current location from the routine reference by the first entry, but ‘the location of’ the backdrop is the Car Park, because in determining location, having failed to match a room corresponding to the player’s location in the routine referenced by the first entry, Inform moves on to found_in’s next entry and, finding a simple room name, returns that- whether or not the player is actually in the car park.
The rules determining the location of a backdrop can be summarised thus:
- if absent → nowhere
- if currently in the room enclosing the player → that room
- otherwise → the default room found in
- if no I6 found_in property → nowhere
- if no room matched by found_in → nowhere
- 1st room matched by I6 found_in property
- LocationOf() iterates through all entries of the found_in property until (i) a routine matches with any room or (ii) it’s a simple room name: this can lead to unexpected results when the first entry has been changed to a routine that matches no room, as location may be returned from the second or subsequent entries as a room the backdrop is no longer found in
- this outcome is made more likely by a bug with how ‘move a-backdrop backdrop to all a-description-of-rooms’ routines are implemented. found_in routines are supposed to consult the I6 global variable ‘location’ to match with, but I7 currently implements these particular routines such that they need to be called with the room to match with as a parameter. LocationOf() depends on the former mechanism when evoking found_in routines, consequently in I7 these ‘a-description-of-rooms’ found_in routines always return false to LocationOf() because it calls them with no parameters.
- in the case where found_in has the value FoundEverywhere- a routine that simply returns true- the room enclosing the player will be returned under the previous rule
- otherwise → nowhere
NB the showme command doesn’t use LocationOf() but iteratively prints the object tree and/or component tree enclosing the object- or if the object is at the top of an object tree, prints “out of play”. This means that in the case of a non-absent backdrop not yet moved to a location, showme indicates its location as ‘out of play’ while LocationOf() returns the default location.
Further small-print - off-stage and nowhere for backdrops It might be supposed that ‘is off-stage’ and ‘is nowhere’ are exact equivalents, but in the case of backdrops that’s not the case. ‘some-object is nowhere’ is exactly equivalent to ‘the location of some-object is nothing’ whereas on-stage is defined by these rules:
- if not a thing → no
- if a door → yes
- if a backdrop:
- if absent → no
- otherwise → yes
- if enclosed by a room → yes
- otherwise → no
In the case of an non-absent backdrop, it will be on-stage but may still have no location e.g if found_in comprises soley a routine that doesn’t match the player’s current location (see above)- in which case it will be on-stage but nowhere. Furthermore, the meaning of ‘out of play’ when location is shown by the ‘showme a-backdrop’ command has a different meaning again- as indicated above it means ‘the ultimate (in)direct holder is nothing’ which in the case of backdrop means it is removed from the object tree. In summary, for a backdrop
- off-stage == ‘absent’ attribute set (in I7 this results from ‘(now) a-backdrop is nowhere’)
- nowhere == ‘location of a-backdrop is nothing’
- ‘showme’ out of play == ‘a-backdrop is not (in)directly held by a room’
use of ‘location of a-backdrop’ and ‘a-backdrop is nowhere’ It’s probably advisable to avoid both these usages, since the behaviour of the former is difficult to predict and the latter depends on the former.
Dr Peter Bates, phd. Inform Studies.