WI §27.1. The status of extensions

The range of simulation offered by Inform's model world is intentionally limited to a core of basic essentials. We could argue at the margins, and the choice of what's in and what's out is partly traditional, but most people find the model reasonable as far as it goes.

Between 1993 and 2006, quite a range of "library extensions" for Inform 6 was written. Most of these extensions aimed to fill out the model by simulating other aspects of life, too: money, clothing, pourable liquids. None of these extensions was official and all of them were: it was a free-for-all, and in several cases different authors wrote rival extensions to model the same basic ideas. The development of Inform 7 was strongly influenced by this history and by the recognition that the base of rules and grammar inside a typical modern story are seldom written by a single author. They combine the standard Inform material with extensions by several third parties, together with anything specific to the story in question.

Inform 7 has a more organised idea of extensions, as we shall see. But anyone is free to write an extension on any terms or for any reason. Writers may wish to use the techniques in this chapter to develop private extensions of their own, used in several projects, or to share them with associates but not more widely.

But most writers of extensions do so to contribute to the Inform community, and for the satisfaction of solving a problem. Inform does not recognise anyone's approach to a particular need as "the official solution" - for instance, although the standard Inform distribution includes a copy of Locksmith by Emily Short, that is not the "official" way to make automatically unlocking doors, and anyone is welcome to try a better one.

However, the Inform project does recognise some extensions as "public". Public extensions are the ones archived on the Inform website for the free use of all Inform writers. Those who wish to contribute an extension as a public one are obliged to follow a number of guidelines, which are mostly stylistic points intended to make the range of extensions easier to work with. Extension writers are asked to join in the spirit of these rules and help make the whole cooperative enterprise work harmoniously. Extensions which do play by these rules are also accepted into the Public Library, which makes them easy for all Inform users everywhere to find and obtain them.

Writers who wish to make their extensions public on the Inform website should also be clear that by doing so, they are donating their work to the community on the basis of the broadest form of Creative Commons license: that is, they retain copyright and the right to be identified as the author (and as we shall see they are automatically credited in any work of IF which uses their extension), but are giving unlimited permission to use, circulate and republish their extensions in any form, even as part of commercial works (should that arise). To publish a public extension is a public-spirited act, done for only the reward of a modest acknowledgement.

If the author of an extension has not made it public, or indicated in some other way that it is free to be used without the need for permission, then it would be both polite and prudent to check with the author before publishing something which incorporates his work.

WI §27.2. The Standard Rules

When any source text is run through Inform, a secret first line is inserted, which reads:

Include the Standard Rules by Graham Nelson.

The "Standard Rules" file contains the definitions of the basic kinds, phrases, actions and grammar described in this documentation: for instance, it includes lines like

A container is a kind of thing.

...without which Inform would be lost. Although including the Standard Rules is compulsory, it is treated internally as if it were any other "extension".

What happens when an "Include" sentence is reached is that the sentence is replaced with the whole text of the file in question, often many paragraphs long.

If the file has already been included, then the sentence is simply ignored. This is so that we can have two extensions, each of which needs the other: if A says to include B, and B says to include A, the result is that including one automatically includes the other, so we always get both which ever we ask for - not that there is a hideous infinite regress.

WI §27.3. Built-in, installed and project-specific extensions

To recap: Inform builds projects from both the source text typed by the author and from Extensions; one of these, the Standard Rules, is always included; others are added as authors please. About 20 are "built-in" to Inform, meaning that they are stored inside the application and always available. Others must be "installed", and each Inform user will have a folder somewhere on his computer which contains these. Users typically obtain these from the Public Library feature in the application, but they can also download them directly from inform7.com and then use an Install Extension menu option in the application. Either way, the application then squirrels the file away, and it becomes available to any projects that that user may be working on.

It is also possible to have extensions available to just one project. These must be stored in the Extensions subfolder of the project's ".materials" folder, but otherwise are arranged the same as installed extensions - there's an outer folder for each author's name, and extensions are named with a ".i7x" extension within. For example:

Mourning Hypercritical.inform
Mourning Hypercritical.materials
    Extensions
        John Siracusa
            Fixing The Finder.i7x

When Inform needs to find an extension, it looks here first, then in the installed area, then in its built-in area. That means that we can make our own revised or hacked version of an extension, put it in the ".materials" area, and then have it take precedence over the installed or built-in one. We could even have our own private version of the Standard Rules here.

(This has a number of possible uses - for example, to provide a convenient test-bed when working on an experimental version of an extension.)

WI §27.4. Authorship

Extensions are identified by author and by name, so that a given author can produce his or her own range of extensions, and need only ensure that these are named differently from each other. If John Smith and Mary Brown each want to write an extension called "Following People", there is no conflict.

The name of an extension, and of an author, should be written in Sentence Capitalisation: that is, upper case for the first letter in each word. (Inform uses this to minimise problems on machines where filenames are read with case sensitivity.) It is permitted for author names to include upper-case letters within words, as with the "G" in "Jesse McGrew". In general it is best to avoid accented or unusual letters in titles and author names, but the standard ISO Latin-1 characters should be allowed - for instance,

Étude Pour La Fênetre by Françoise Gauß begins here.

The author name must not start with "The", nor contain the words "by", "and" or "version", or contain punctuation, as in "John X. Doe"; the title similarly, except that "and" is permitted. Name and author's name must each be no more than 50 characters long, including any spaces between words.

Authors are asked to use real names rather than cryptic handles like "ifguy", and to use genteel, plausible pseudonyms like "Emily Short" rather than, say, "Drooling Zombie" or "Team Inform". Authors are also asked to use the same author's name for all their own extensions, and (it should go without saying) not to masquerade as anybody else.

Sometimes authorship is complicated. What if Mary Brown finds some Inform 6 code written by John Smith in the mid-90s, and puts an I7 gloss on it to make an I7 extension, but then Pierre Dupont translates it into French: who's the author of the result? The rule is that the person making the current, latest version is the author listed in the titling line, so we end up with

... by Pierre Dupont begins here.

But Mary and John deserve their credits too: see the next section for how to give them.

WI §27.5. A simple example extension

Extensions are plain text files, and can be created with any text editor. (It is sometimes said that "there is no such thing as plain text", there being so many ways to represent exotic characters: so to be precise, an extension is a text file with the Unicode UTF-8 encoding, either with or without a BOM marker, using any of the possible forms of line-ending (Unix, Windows, Macintosh, or Unicode line divider). This is a detail which will only matter if the extension contains accented letters or other exotica.)

Extensions look very much like passages of Inform source, because except for a special introductory and concluding sentence, and one convention, that is all they are:

The Ducking Action by Graham Nelson begins here.

"An action for ducking one's head."

Ducking is an action applying to nothing. Report ducking: say "You duck!" Understand "duck" as ducking.

The Ducking Action ends here.

Not a useful or interesting extension, but those few words add a whole new action and everything needed to make it work. It is Inform's ability to mix up rooms, things, kinds, grammar, phrases and rules, in more or less any order, which makes it possible for extensions to work.

The introductory sentence must be placed as the only content of line 1 of the file, which must not contain comments, and has to be written in exactly the correct form. Inform checks this very carefully when performing its census of installed extensions, on each translation of the text. (In case the extension's title is a plural, we are allowed to write "begin" and "end" instead of "begins" and "ends". For instance, the last line of the standard rules is "The Standard Rules end here.")

The "one convention" mentioned above is that if a double-quoted text is placed immediately after the beginning sentence (and with no intervening comments), then it is taken to be a short description of the extension's content called the "rubric". Hence the line:

"An action for ducking one's head."

Providing a rubric is helpful, because it enables Inform to give a meaningful listing even for an as-yet unused and unindexed extension, and because it helps the Inform website to produce better directories. Note the word "short": such text is likely to be truncated if it exceeds 500 characters.

A second double-quoted text can also, optionally, be added in yet a third special starting paragraph. This is to provide additional credits to people who have contributed to this or earlier versions. For instance:

The Ducking Action by Graham Nelson begins here.

"An action for ducking one's head."

"based on original Inform 6 code by Marc Canard"

Note the typical style here: it's a phrase rather than a sentence, and neither starts with an upper-case letter nor ends with a full stop. (The additional credit is then used in documentation and also in the VERSION text of any Inform story file using the extension.)

Examples

449. Modern Conveniences ★★ Exemplifying the kind of source we might use in writing extensions for kitchen and bathroom appliances. (c.f. RB §8.5. Kitchen and Bathroom)

WI §27.6. Version numbering

As we have seen, extensions are referred to by name and author, but they can also (optionally) be referred to by version. For instance:

Include version 2 of the Ducking Action by Graham Nelson.

Version 1/040426 of the Ducking Action by Graham Nelson begins here.

A version number must be a whole number 1, 2, ..., 999 (version 0 is not allowed, and nor are decimal points), optionally followed by a slash '/' and then a six-figure date, in the form YYMMDD: so 040426 means 26 April 2004.

A request to include version 2 of something implicitly means "version 2 or later", and similarly "version 2/040426" means version 2 with a date of 26 April 2004 or later, or else any version higher than 2. If Inform loads the extension but finds that its version is not good enough, an error is issued.

Where no version number is quoted, the rule is that an unspecified version predates any numbered version. This means that the line

Include the Ducking Action by Graham Nelson.

will be happy with any version of the extension at all, whether numbered or not; but

Include version 2 of the Ducking Action by Graham Nelson.

will only accept the extension if it has a version number attached (and with that number being 2 or higher).

During play of any story compiled by Inform 7, typing VERSION lists various serial numbers of the pieces of software used to make it. The list concludes with names, authors and version numbers of any extensions used. So every author whose work contributes to a story automatically gets a modest credit within it. The same list can be printed, at the discretion of the designer, using the textual substitution:

say "[the/-- list of extension credits]"

This text substitution expands to one or more lines of text crediting each of the extensions used by the current source text, along with their version numbers and authors. Extensions whose authors have chosen the "use authorial modesty" option are missed out. Example:

Standard Rules version 2/090402 by Graham Nelson

If we want our extension to go uncredited - perhaps if it is a low-level enabling sort of thing, for instance - we can place the following sentence inside the definition of the extension:

Use authorial modesty.

The same sentence placed in the body of a source text causes all extensions by the same author as the main source text to go uncredited. In other words, if Isaac Miggins writes a source text and includes, say, Unlikely Events by Isaac Miggins, then this extension will go uncredited in the VERSION command.

A complete list, undiluted by modesty, can always be obtained using:

say "[the/-- complete list of extension credits]"

This text substitution expands to one or more lines of text crediting each of the extensions used by the current source text, along with their version numbers and authors. Every extension is included, even those whose authors have opted for "use authorial modesty". Example:

Standard Rules version 2/090402 by Graham Nelson
Locksmith version 9 by Emily Short

WI §27.7. Extensions and story file formats

Inform compiles to several different story file formats, and in each case uses only a small part of their abilities - especially when it comes to fancy tricks with the keyboard or screen. So people may well want to write extensions which provide access to some of these tricks (like "Basic Screen Effects", included in the standard Inform distribution, but more so). Unfortunately, these tricks are very likely to fail to compile - or fail to work - on some of the possible story file formats, so the resulting extension would probably go wrong (and mysteriously wrong) for users who have chosen a different format.

Inform therefore provides a way for extensions to declare the formats they are compatible with. All that is required is to add a proviso in brackets after the title is declared:

Version 2 of Basic Screen Effects (for Z-Machine version 8 only) by Emily Short begins here.

Other examples might be "(for Glulx only)", or "(for Z-machine only)". If no such proviso is given, the extension is assumed to be compatible with every story file format.

Extensions are also able to include material which is only used on some story file formats and not others - in principle, this might allow the same facilities to be provided to the author whatever story file format is used, but to achieve these effects differently depending on the current Settings. The convention here is exactly like "not for release": if a heading or subheading in the source text contains a bracketed proviso, then the material under that heading (and under its dependent subheadings) will be ignored if the current story file format does not match. For example:

Section 2.3G (for Glulx only)

To reveal the explosion:
    [...the Glulx way...]

Section 2.3Z (for Z-machine only)

To reveal the explosion:
    [...the Z-machine way...]

would ensure that "reveal the explosion" works nicely whichever story file format is used.

Examples

450. Tilt 3 ★★ Displaying the card suits from our deck of cards with red and black colored unicode symbols. (c.f. RB §12.1. Typography)

WI §27.8. Extensions can include other extensions

As was mentioned earlier, the same extension is sometimes requested several times. For instance, suppose the main source text asks to include version 2 of extension X, and also to include extension Y. Suppose further that Y contains a request to include version 4 of X. We now have two different requests for X. Inform works out the minimum version number needed to satisfy these requests (in this case 4) and gives an error if the extension it actually loads turns out to be earlier.

This is true even of the Standard Rules. Suppose that the Standard Rules had recently been republished in version 37, making the previously existing version 36 out of date, and that an extension is written which capitalizes on a new feature in v37. It will therefore not work if people try to use it with v36. All the extension needs to do is to say:

Include version 37 of the Standard Rules by Graham Nelson.

to guarantee that v37 or later will be used.

If an extension does include other extensions, it should do so in a paragraph immediately following the introductory sentence, so that anyone looking at the file can see these mutual dependencies at a glance.

WI §27.9. Extensions can interact with other extensions

When one extension is being used, it's probably only one among several. A really general-purpose extension might want to behave differently depending on which other extensions are also present. This can be achieved using headings which are "for use with" (or "without") other extensions. For instance:

Chapter 2a (for use with Locksmith by Emily Short)

specifies that everything under this heading (and its subheadings, if any) will be ignored unless the extension Locksmith by Emily Short is included. Conversely,

Chapter 2b (for use without Locksmith by Emily Short)

will be ignored unless it isn't included. This allows an extension to give two variations on the same material - one if Locksmith is present, the other if not.

Headings can also replace portions of extensions which have been included. For instance:

Section 6 - Hacked locking (in place of Section 1 - Regular locking in Locksmith by Emily Short)

places the source text under the new heading in the place of the old (which is thrown away). If there should be two or more headings of the same name in the given extension, the first is the one replaced; if two or more headings attempt to replace the same heading in the given extension, the final attempt in source text order is the one which succeeds; and finally, heading dependencies like the above are scanned in a top-down way. Thus, if we have:

Chapter 2a (for use with Locksmith by Emily Short)
...
Section 1 - Hacked marbles (in place of Section 4 in Marbles by Peter Wong)
...

and we don't include Locksmith, then the replacement of Section 4 of Marbles is not made, because Section 1 - Hacked marbles is subordinate to the Chapter 2a heading which we've told Inform to ignore.

If the name of the heading to replace contains the word "in", it's a good idea to use quotation marks for clarity:

Section - Hacked questions (in place of "Section 4 - Phrase used to ask questions in closed mode" in Questions by Michael Callaghan)

WI §27.10. Extensions in the Index

As soon as a project has successfully been translated, its Index is brought up to date: pages of the index record all the kinds and what they are for, all the phrases which can be used, and so on. Any kind or phrase created in an extension is automatically included. The extension's presence in the project is itself recorded - the Contents index for any project contains a brief list of all extensions used in that project, along with their authors and version numbers. For instance:

Standard Rules version 1/040731
Locksmith by Emily Short
Tupperware by Emily Short

The Kinds index aims to give the reader a brief note of what each kind is intended for. We can provide for this by writing a sentence like so:

The specification of player's holdall is "Represents a container which the player can carry around as a sort of rucksack, into which spare items are automatically stowed away."

There is no need to specify the properties which apply: that is all done automatically. "Specification" is a sort of pseudo-property used just for this: we can also give specifications to kinds of value and to actions, and these are similarly used in the Index pages.

Every extension has the right to its own set of headings and subheadings, independently of those used by the main source for the work or by any other extension which may be included. (So if the extension is divided into four sections and finishes on Section D, say, that doesn't mean that Section D will continue outside the extension as the main source of the story runs on.)

Extensions should, of course, be written so that they never produce Problem messages, so at first sight it appears that these headings will never be outwardly visible. In fact, though, Problems do occasionally turn up in extensions, usually when the user has made a mistake, or when two inconsistent extensions are used in the same project. But more importantly, the headings in an extension are used when indexing phrases (and also actions) to group similar phrases together. For instance, the Standard Rules contain the heading:

Section SR4/7 - Searching and sorting tables

The half-dozen phrases defined in this section of the Standard Rules are then indexed under the subheading "Searching and sorting tables": Inform looks for a hyphen in the heading and then uses any text which follows the hyphen. (If there is no hyphen, the entire heading text is used.)

If an extension contains no headings, its phrases (or actions) are indexed simply as "Miscellaneous".

Finally, any phrase or variable defined immediately under a heading whose name ends in the word "unindexed" will be omitted from the Phrasebook or Contents index respectively. (That won't apply to definitions under subheadings of the heading.) This is intended so that technical apparatus used only inside the extensions can be concealed from the outside user's immediate view. Inform as it is presently constituted does not allow extensions to make fully private definitions, but this feature at least allows them to make unadvertised ones.

WI §27.11. Extension documentation

A basic mechanism for documenting extensions is built into Inform. For many extensions, this will probably do instead of a manual; for more complex ones, it should still prove a useful supplement to one.

As described in Chapter 2 above, whenever an extension is installed, its documentation is made available to the user. Such text should be written concisely, while giving examples wherever appropriate. Stylistically, it should ideally follow the model of the main Inform documentation: just as an extension expands the standard rules, so its documentation expands this manual. "We need..." is preferred to "You need...", and so on: we're all in this together.

In order to be recognised as documentation, this text should appear at the foot of the extension file, after the compulsory end sentence. The first paragraph must have exactly the following form, with a skipped line before and after:

---- DOCUMENTATION ----

For instance, the "Ducking Action" example might end:

...
The Ducking Action ends here.

---- DOCUMENTATION ----

This is a modest extension, with much to be modest about. It allows us to use a new action for ducking, as in ducking the player's head (not as in ducking a witch). Ducking will do nothing unless rules are added:

    Instead of ducking in the Shooting Gallery, say "Too late!"

...

We obtain indented code examples by beginning a line with a tab. A double indentation can be got with two tabs in a row, and so forth. (Beware: some text editors, or emailers, flatten tabs into a row of four or perhaps eight spaces each. Inform will not recognise such a line of spaces as a tab.)

Note that text in square brackets should be avoided in the documentation, because that's taken as being comment matter on the extension, and omitted.

Tables should be similarly indented, and should begin with the word "Table ...": the top line is taken to be the name of the table, and subsequent lines are tab-divided columns. Inform will automatically group this into a table, like so:

Table of Exemplariness

stellar object

example

galaxy

"Andromeda Galaxy M31"

star

"Sirius"

planet

"Neptune"

moon

"Enceladus"

dwarf planet

"Ceres"

plutino

"38628 Huya"

cubewano

"Easterbunny"

(Footnote: Since the first appearance of this book, Easterbunny has been renamed Makemake, the creator god in the mythology of the people of Easter Island.)

WI §27.12. Examples and headings in extension documentation

Extensions with very large amounts of documentation can, if the author chooses, divide the material up using headings and/or subheadings. These must be written as paragraphs exactly like so:

Chapter: Avoiding Events

Section: Ducking examinations and tests

Inform will then typeset them to stand out, will number them automatically, and will add a table of contents at the top of the page. (For most extensions, the documentation will be short and sweet, and this would just be clutter: headings and subheadings are best used only where the text would otherwise be difficult to read.)

Any extension's documentation can contain Examples, just as the main Inform documentation does: these are automatically labelled A, B, C, ... rather than given numbers, to ensure that they do not clash with the numbering used in the built-in chapters. (The labels may be helpful in writing an extension's documentation: we can write, for instance, a note such as "see Example C below".)

Examples must be given last in the documentation, and there can be up to 26 of them, though most extensions will need one example at the most, and some will have none at all. Each example must begin with a paragraph exactly like so:

Example: ** We Must Perform a Quirkafleeg - Ducking to avoid arrows as one proceeds east across battlements.

Again, there must be a skipped line before and after. The row of asterisks must be *, **, *** or ****, just as in the main documentation, which we should follow on all points of style. The rest of the line contains the title, a hyphen, and then the description. The title should be given with Each Word except Prepositions and Similar Things Capitalized, while the description should look like a sentence, and end with a full stop.

The text of the example follows, of course, and continues until the end of the file, or the next "Example:" line, whichever comes first.

Each example should (normally) contain one single, complete, story, long enough to demonstrate the use of the extension and to have a little flavour to it, but not so long that the reader gets lost. It should have a title, which should match the name of the example (in the case above, "We Must Perform a Quirkafleeg"). It should conclude with a paragraph defining a test:

Test me with "east / duck / east / jump / east / duck / east / rescue esmerelda".

The idea is that typing one single command, TEST ME, into the resulting story should show off what the extension does.

When an extension contains more than one example, they should be given in order of asterisk rating, that is, starting with the * examples, then the ** examples, and so on up.

WI §27.13. Implications

Extensions often need to define new kinds or properties, which we want to make as helpful as possible for the user. In particular, we want them not to require additional work for the author just to obtain the effect which seems only natural.

For example, consider Inform's built-in "locked" property. If a door is locked, then it cannot be opened, which seems fair enough. But if the player tries to unlock the door, he might then find the following response:

That doesn't seem to be something you can unlock.

Which does not seem right. In real life, almost all locked items have outwardly exposed locks which it is perfectly sensible to try to unlock, given a key. The problem is that our door has the "locked" property, but not the "lockable" one.

The Standard Rules solve this problem by including the following line:

Something locked is usually lockable.

This ensures that any door said by the author only to be "locked" will be "lockable" as well, and adds a small but worthwhile touch of realism.

Such a sentence is called an "implication", as it is in the form "Condition A implies Condition B". Note that the two conditions must consist of either/or properties with or without kinds attached. Thus:

A room in the Open Desert is usually lighted.

will not work because "a room in the Open Desert" is a more complicated grammatical construction than, say, "lighted" or "a lighted room": it contains a relative clause. Inform can only deal with simple implications.

Inform never overrides certainties with mere implications, and is cautious about allowing them to build overly long chains of argument. This is to prevent the following kind of difficulty:

An open door is usually closed. A closed door is usually open.

Implications work just the same for values which aren't objects, so:

Colour is a kind of value. The colours are red, green and blue.
A colour can be zesty or flat. A colour can be bright or dull.
Red and blue are bright. Blue is flat.

A bright colour is usually zesty.

results in red being zesty, but blue and green being flat; blue because the source text explicitly says so (which trumps the "usually"), and green because this isn't a bright colour, so the implication doesn't arise.

Implications have not been mentioned up to now since they are only really needed by extensions, but also because they can be tricky, with unforeseen consequences. We should handle them with care.

WI §27.14. Using Inform 6 within Inform 7

To return to what was said on the first page of this documentation: Inform 7 (or I7), the current version, is not at all like Inform 6 (or I6). Internally, however, I7 works by translating the source text into an I6 program, so that in a practical sense the current version of Inform actually contains its predecessor.

The final sections of this chapter show how I6 code can be mixed directly in with I7. The remaining pages will therefore make little or no sense to those who do not already use I6. But for those who do know I6 already, it would be all too easy to write highly hybridised code, constantly mixing I6 and I7. The authors of Inform hope that this will not happen: for almost all purposes, I7 is much more powerful than I6, and fails - when it has to fail - in a way more helpful to the user. Ideally, all I6 content would be confined to extensions (and this may be mandated in future releases of Inform), and even writers of extensions are asked to pare down their usage of I6 to the minimum necessary.

The methods for incorporating I6 code into I7 have been designed with this in mind, that is, to encourage people to use I6 in as self-contained a way as possible: in particular to isolate the relatively few functions which need to be written in I6, and to give them natural language expression.

Finally, anyone hacking with I7 for a while is likely to become curious about the Standard Rules file, and to look at the text on which the Inform world model is founded. The file is, of course, no secret, but it can be misleading. For one thing, it appears to have great freedom to set up the world model as it pleases, but in fact the I7 compiler may well crash unless certain things are done just so in the Standard Rules: they depend on each other.

Moreover, the Standard Rules use a number of syntaxes which are not documented in this chapter: these are constantly being altered, and it would not be safe to imitate them. Any I6-related syntax which is not documented in this chapter may be removed or changed in effect at any time without warning, for instance in an update of Inform to fix bugs.

WI §27.15. Defining phrases in Inform 6

The phrases described in this documentation, such as "end the story", are all defined in the Standard Rules, and are for the most part defined not in terms of other I7 phrases but instead reduced to equivalents in I6. For instance:

To end the story (- deadflag=3; story_complete=false; -).

The notation "(-" and "-)" indicates that what comes in between is I6 code. The minus sign is supposed to be a mnemonic for the decrease from 7 to 6: later we shall use "(+" and "+)" to go back up the other way, from 6 to 7.

When a phrase is defined as containing only a single command, and that command is defined using I6 - as here - it is compiled in-line. This means that the phrase "end the story" will always be translated as "deadflag=3; story_complete=false;", rather than being translated into a call to a suitable function whose only statement is "deadflag=3; story_complete=false;".

This is an easy case since the wording never varies. More typical examples would be:

To say (something - number): (- print {something}; -).
To sort (T - table name) in (TC - table column) order:
    (- TableSort({T}, {TC}, 1); -).

When the braced name of one of the variables in the phrase preamble appears, this is compiled to the corresponding I6 expression at the relevant position in the I6 code. So, for instance,

say the capacity of the basket

might be compiled to

print O17_basket.capacity;

because "{something}" is expanded to "capacity of the basket" (I7 code) and then translated to "O17_basket.capacity" (I6 code), which is then spliced into the original I6 definition "print {something};".

Braces "{" are of course significant in I6. A real brace can be obtained by making the character following it a space, and then I7 will not attempt to read it as a request for substitution.

It's also possible for the pair of characters "-)" to occur in I6 code, for example here:

for (i=3 : i>0 : i--)

and I7 will read the "-)" as terminating the I6; we can get around this with an extra space:

for (i=3 : i>0 : i-- )

Warning: Inform 6 uses a restricted character set, allowing use of most of the accented characters in ISO Latin-1 (those found in a set called ZSCII) but little beyond that. It's therefore hazardous to use any exotic Unicode characters in an inclusion.

Examples

451. Pink or Blue ★★★ Asking the player to select a gender to begin play. (c.f. RB §5.2. Traits Determined By the Player)

WI §27.16. Phrases to decide in Inform 6

There are basically three forms of phrase in I7: phrases which do something, but produce no value or opinion as a result; phrases to decide whether or not something is true; and phrases to decide on a value. We have already seen examples of writing the first form in I6:

To say (something - number): (- print {something}; -).

Here the I6 form is required to be I6 routine code in void context, that is, it will normally be one or more statements each of which ends in a semicolon (unless there are braced code blocks present). In this case, we have just one I6 statement, ending in a semicolon.

An example of a phrase to decide whether something is true would be:

To decide whether in darkness: (- (location==thedark) -).

Here the I6 code providing the definition must be a valid I6 condition, and be in round brackets, but there is no semicolon.

Lastly, an example of a phrase to decide on a value:

To decide which number is the hours part of (t - time): (- ({t}/60) -).

Again, this is a value in I6 as well: no semicolon. It is probably safest to place the value in round brackets.

WI §27.17. Handling phrase options

The Standard Rules use the Inform list-writer with the following definition, which shows how a much more complicated I6 routine can be given a natural-language expression.

To list the contents of (O - an object),
    with newlines,
    indented,
    giving inventory information,
    as a sentence,
    including contents,
    including all contents,
    tersely,
    giving brief inventory information,
    using the definite article,
    listing marked items only,
    prefacing with is/are,
    not listing concealed items,
    suppressing all articles
    and/or with extra indentation:
    (- I7WriteListFrom(child({O}), {phrase options}); -).

This can be used by, say:

list the contents of O, as a sentence, using the definite article

"{phrase options}" is a special substitution: it is a bitmap which assigns the given options one bit each, starting with the least significant bit for the first-mentioned option ("with newlines" above) and going up to the most significant bit for the last ("with extra indentation").

WI §27.18. Making and testing use options

Use options (see Chapter 2 above) manifest themselves in the I6 code generated by I7 as constants which are either defined, or not. For instance, the "use American dialect" option results in the constant DIALECT_US being defined, a constant which otherwise would not be. Some use options define the constant as a particular value, others simply define it (so that I6 gives this constant the value 0).

New use options can be created as in the following examples, which are found in the Standard Rules:

Use American dialect translates as (- Constant DIALECT_US; -).
Use full-length room descriptions translates as (- Constant I7_LOOKMODE = 2; -).

Most Inform users will not need to test whether a use option is currently set: after all, they will know whether or not their own story uses American dialect. But an extension does not know what use options apply in the story which is using it. An extension which needs to print a list, using its own formatting, might want to know whether "use serial comma" is set. Or it might want to speak differently in American dialect.

To test for American dialect, we should ideally not use I6 to look for the constant DIALECT_US using #ifdef: there is no guarantee that this constant will not be renamed at some point. Instead we can perform the test directly in I7:

if the American dialect option is active, ...

and similarly for all other named use options. The adjectives "active" and "inactive" have the obvious meanings for use options. This means it's possible to describe the current options like so:

say "We're currently using: [list of active use options].";

The result might be, say,

We're currently using: dynamic memory allocation option [8192], maximum text length option [1024], maximum things understood at once option [100], American dialect option and fast route-finding option.

This may be useful for testing purposes.

Use options can also allow the writer to raise certain maximum values. If we write an extension which needs some I6 array, say, and therefore has some limitation - for instance a footnotes presenter which can handle at most 100 footnotes before its array space runs out - it would obviously be cleaner to allow this maximum to be raised. We can set this up like so:

Use maximum presented footnotes of at least 100 translates as (- Constant MAX_PRESENTED_FOOTNOTES = {N}; -).

With such a definition, the number given is the default value, and the I6 source is included whether or not anybody uses the option: the default value being given if nobody does. The text "{N}" is replaced with the value. So the above definition normally results in this being defined:

Constant MAX_PRESENTED_FOOTNOTES = 100;

but if the user writes

Use maximum presented footnotes of at least 350.

then instead the I6 inclusion becomes:

Constant MAX_PRESENTED_FOOTNOTES = 350;

The I6 constant MAX_PRESENTED_FOOTNOTES can then be used as the size of an array, for instance.

WI §27.19. Longer extracts of Inform 6 code

Whole routines, object and class definitions (or any other directives) can be pasted in wholesale using sentences like so:

Include (-
[ MyInform6Routine a b; return a*b; ];
-).

Such inclusions are pasted into the final compiled code at the end of the file, after the I6 grammar has been declared.

In such extracts, we sometimes need to refer to objects, variables or values which can't be described using I6: or rather, which can be described, but we don't know how. To this end, any text in an inclusion written in "(+" and "+)" parentheses is treated as an I7 value, and compiled accordingly, with all type-checking waived for the occasion. For instance:

Include (-
Global my_global = (+ the tartan rucksack +);
-).

Here "the tartan rucksack" is translated into "O18_tartan_rucksack", or something similar: the I6 object created to represent the rucksack. Thus the actual line of code produced is

Global my_global = O18_tartan_rucksack;

The material between "(+" and "+)" is generally treated as a value, and thus compiles to the I6 form of that value. But it could also be a property name, which compiles to the I6 form in question, or a defined adjective, which compiles to the name of the routine to call which tests whether that adjective is true.

Three warnings. The material in "(-" and "-)" is called template code, and it is not quite treated as literal. That means certain characters cause Inform to react:

1. Beware of accidental "(+" usage - for instance,

Include (-
[ MyCleverLoop i; for (++i; i<10; i++) print i; ];
-).

looks reasonable, but contains "(+" and "+)". Spaces around the first "++" would have been enough to avoid this one; "+)" is only significant where it follows a "(+".

2. Beware of placing an "@" character in the first column, that is, immediately following a new line. (In template code this marks off paragraph divisions.) So for instance,

Include (-
[ Set_Stream ret;
@glk 67 ret;
];
-).

is tripped up by the Glulx assembly language opcode "@glk" because this occurs in column 1. Indenting it with a little space or a tab is enough to avoid the problem.

3. Be careful if you're creating an I6 variable holding initialised I7 text. For example,

Include (-
Global saved_optional_prompt = (+ "!!>" +);
-) after "Definitions.i6t".

looks as if it will work, but doesn't, for reference-counting reasons we needn't go into; instead you need

Include (-
Array sop_storage --> PACKED_TEXT_STORAGE "!!>";
Global saved_optional_prompt = sop_storage;
-) after "Definitions.i6t".

But it's far better to avoid initialising text variables from I6 entirely. The same problems arise with constant lists.

Examples

452. Status line with centered text, the hard way A status line which has only the name of the location, centered. (c.f. RB §12.2. The Status Line)

WI §27.20. Primitive Inform 6 declarations of rules

By writing a sentence like this:

The underground rule translates into I6 as "UNDERGROUND_R".

we create a new rule, the "underground rule", and also notify Inform that it will have no definition as I7 source text: instead, it will be provided as an I6 routine called "UNDERGROUND_R". We can define this with an Include like so:

Include (-
[ UNDERGROUND_R;
    if (real_location hasnt light) { RulebookSucceeds(); rtrue; }
    rfalse;
];
-).

The rule should return false if it wants to make no decision, but call either RulebookSucceeds or RulebookFails and return true if it does. These routines can optionally take an argument: which will be the return value from the rulebook.

Note that UNDERGROUND_R itself has no arguments. In the case of an action based rulebook, the I6 variables noun, second and actor can be referred to, while for a value based rulebook the parameter is stored in the I6 global variable parameter_object (which is not necessarily an object, in spite of the name).

We can put this rule into a rulebook in the same way that any named rule can be:

The underground rule is listed in the spot danger rules.

WI §27.21. Inform 6 objects and classes

As might be expected, I7 compiles an I6 class for each kind, and an I6 object for each of its own objects. We can meddle with its compilation process here using a further refinement of Include. For instance, suppose we want the I6 class definition for things to come out containing a property like this:

Class K2_thing ...
    with marmalade_jar_size 6,
    ...

How to arrange this? One way is to create an ordinary I7 property, like so:

A thing has a number called marmalade jar size. The marmalade jar size of a thing is usually 6. The marmalade jar size property translates into I6 as "marmalade_jar_size".

(Without that last sentence, the property won't get any familiar name.) But sometimes we need more, and want to actually write new material to go into the definition. This can be done like so:

Include (- with before [; Go: return 1; ], -) when defining a vehicle.

This glues in a new property to the class compiled to represent the I7 kind "vehicle". (See the DM4 for why. However, since the entire actions machinery is different in the I7 world, note that "after", "react_before" and "react_after" no longer have any effect, and nor does "before" for rooms.)

And similarly:

Include (- has my_funny_attribute, -) when defining the hot air balloon.

If we need a particular I7 object or kind to end up with a particular I6 name, we can write:

The whatsit object translates into I6 as "whatsit".
The thingummy kind translates into I6 as "thingummy_class".

WI §27.22. Inform 6 variables, properties, actions, and attributes

I7's variables are usually compiled as entries in an array rather than as I6 variables. However, we can instead tell Inform to use an existing I6 variable (either one that we declare ourselves, or one in the I6 template layer). For example:

Room description style is a kind of value. The room description styles are Brief, Verbose and Superbrief.
The current room description style is a room description style that varies.
The current room description style variable translates into I6 as "lookmode".

This is a feature provided to help I7 source text to use variables internal to the I6 template code. It can, if really necessary, also be used to give I7 names to entirely new I6-level variables, created like so:

Include (- Global my_variable = 0; -) after "Definitions.i6t".

This style of hybrid coding is really not encouraged.

I7's properties are compiled sometimes as I6 properties, sometimes as I6 attributes, sometimes as bits in a bitmap somewhere. However, we can override I7 by telling it that one of its property names is equivalent to an already-existing I6 property or attribute: if so then I7 will use that name and will not compile any directive to create it. For example:

The switched on property translates into I6 as "on".
The initial appearance property translates into I6 as "initial".

We do not need to translate "switched off", the opposite to "switched on": I7 will now compile this to "~on".

Lastly, actions can also be translated (though it's usually better to translate their rules instead and invent new I7 actions covering them):

The unlocking it with action translates into I6 as "Unlock".

WI §27.23. Inform 6 Understand tokens

The parser which deciphers the player's typed commands is written in I6, and many of the basic tokens of Understand grammar are implemented as "general parsing routines" (GPRs), the specification of which is described fully in the Inform 6 Designer's Manual. I7 translates much of the source text's Understand grammar into GPRs, and once again we can bypass this process and supply an Understand token directly as an I6 GPR. For example:

The Understand token squiggle translates into I6 as "SQUIGGLE_TOKEN".

We then have to include a routine of that name into I7's output using the "Include" instruction, on which more later.

This creates a token "[squiggle]"; so for instance if the source text contains:

Understand "copy [squiggle]" as ...

then Inform would parse the command COPY FIGURE EIGHT by calling the SQUIGGLE_TOKEN routine as a GPR with the word marker at 2, that is, at the word FIGURE.

As always, this should be done only where there seems no better way, or where speed is very important. For any fairly simple range of possibilities, it's better to use the techniques in the Understand chapter, or to use unit specifications.

WI §27.24. Inform 6 adjectives

There are three ways to specify that an adjective is defined at the I6 level. For example:

Definition: a number is prime rather than composite if I6 routine
    "PRIMALITY_TEST" says so (it is greater than 1 and is divisible only by itself and 1).

Inform now actually tests if a number N is prime by calling PRIMALITY_TEST(N), and it assumes that we have also included such a routine in the output. The routine is expected to return true or false accordingly.

The text in brackets does nothing functional, but is the text used in the Lexicon dictionary part of the Phrasebook index for the user's benefit; it should be a brief definition. Extension authors are asked to provide these little definitions, so that their users won't be confused by blank lexicon entries.

The second way makes a more capable adjective, since it can not only be tested, but also made true or false using "now". For example:

Definition: a scene is crucial if I6 routine "SceneCrucial" makes it so
    (it is essential to winning).

The difference here is "makes it so", not "says so", and as this implies, the routine has more power. "SceneCrucial" is called with two arguments: SceneCrucial(S, -1) tests whether the scene is crucial or not and returns true or false; SceneCrucial(S, true) must make it true; and SceneCrucial(S, false) must make it false. Another useful difference is that if the kind of value is one which is stored in block form (e.g. for an adjective applying to text), the routine is given a pointer to the block, not a fresh copy.

A third way to define an adjective, which should be used only if speed is exceptionally important, is to provide a "schema" - a sort of I6 macro, like those provided by the C preprocessor. For example:

Definition: a rulebook is exciting if I6 condition
    "excitement_array-->(*1)==1" says so (it is really wild).

The escape "*1" is expanded to the value on which the adjective is being tested. (This is usually faster than calling a routine, but in case of side-effects, the "*1" should occur only once in the condition, just as with a C macro.) To repeat: if in doubt, use the I6 routine method above.

WI §27.25. Naming Unicode characters

Inform allows the Unicode characters to be identified either with a decimal number or by name, but it has none of the character names built-in, and for efficiency reasons it only learns them when necessary.

Users normally teach these names to Inform by including one of the extensions "Unicode Character Names" or "Unicode Full Character Names", which consist of many hundreds of sentences like so:

anticlockwise open circle arrow translates into Unicode as 8634.

Nothing restricts this usage to those extensions.

WI §27.26. The template layer

When Go is clicked, Inform translates the I7 source text into I6 code, but the directly translated code could not survive on its own: it needs a large body of supporting code, also written in I6, to sustain it. (Just as a program like iTunes or Firefox cannot run on a bare machine, but needs an operating system already up and running to support it.) Until 2008, this supporting code was provided by the I6 library, that is, the standard distribution of useful I6 code supplied with distributions of Inform 6.

However, the supporting code is now generated from a collection of about 35 "segments" of I6 code which together make up "the template layer". The reason for the term "template" is that the segments are not quite directly copied into I7's output, but instead act as templates from which I7 generates code - the final output contains variations according to what the original source text needs.

Each segment has its own name, which looks like a leafname plus the ".i6t" filename extension (which stands for "I6 template"). Internally, a segment is itself divided up into named parts. For instance, the segment "Relations.i6t" contains a part called "Symmetric One To One Relations" which provides I6 routines for changing and testing such relations. There are more than 600 named parts across the template as a whole; it is quite a large program. An annotated, typeset version of the template - amounting to a roughly 500-page book - is available for download from the Inform website.

The most powerful use of "Include" allows code to included before, instead of or after any named part or segment in the template. For example:

Include (- ... -) before "Relations.i6t".
Include (- ... -) instead of "Relations.i6t".
Include (- ... -) after "Symmetric One To One Relations" in "Relations.i6t".

Multiple such inclusions can be made for the same segment or part. If so, all will take effect in the case of "before" or "after", but for "instead of" only the most recent one takes effect. Inclusions requested before, or after, a segment or part which has been replaced with "instead of" will take effect and appear before or after the code which appears instead of it.

The pre-2008 syntax

Include (- ... -) before the library.

has been withdrawn; the new syntax

Include (- ... -) after "Definitions.i6t".

should have the same effect.

Template files are not written in literal I6, but in a marked-up, annotated form of I6 which has special transcription commands embedded into it. These commands should absolutely not be used except in the built-in template files, with one exception:

{-segment:Flowers.i6t}

places the whole of the template file "Flowers.i6t" in this position. The built-in template does not of course contain "Flowers.i6t", but Inform allows the optional "I6T" subfolder of the ".materials" folder of a project to hold additional or replacement template files. Thus the project "Botanic Gardens.inform" might store:

Botanic Gardens.materials/I6T/Flowers.i6t

It could even contain:

Botanic Gardens.materials/I6T/Relations.i6t

in which case this would automatically be used instead of the built-in copy of "Relations.i6t", without any change to the I7 source text being needed. In this way, projects can (if they need to) use partly or entirely customised templates.

One application of this might allow for chunks of I6 code generated by external utilities - Perl scripts, lex and yacc, or other code generators - by compiling those to suitable template files in .materials/I6T and then using an inclusion like

Include (- {-segment:MyStuff.i6t} -).

in the I7 source text.

Template hacking, as it's called, is a last resort. If there is any way to achieve the same ends by writing ordinary I7 source text, then that will always be better. If it is possible to write "Include (- ... -)" without mentioning any segment or part, that's much to be preferred, because it has more chance of continuing to work into the future when the template might have been rewritten.

WI §27.27. Translating the language of play

The "language of play" is the natural language used to communicate with the player at run-time: this is normally English.

That means that it is difficult to write, say, Spanish-language IF using Inform 7, though heroic work by the Spanish IF community has overcome this. Inform 6 provided for translation by isolating its linguistic code in a part of the I6 library called the "language definition file", which was normally "English.h". Translations were gradually made to most major European languages, resulting in alternative language definition files called "French.h", "Italian.h" and so on. Full details on how to write a language definition file were given in the Translations chapter of the DM4, that is, the fourth edition of the Inform 6 Designer's Manual.

In I7 the system is different. We use the template, not a library. Instead of providing a language definition file such as "French.h", a translator should create an extension called something like "French Language by Jacques Mensonge". (The language should be named in English, so "French Language by ...", not "Langue français by ...") This extension should then contain broadly the same material as an I6 language definition file, but written in a mostly higher-level way. See the extension "English Language by Graham Nelson" supplied with I7, which is included automatically by default.

WI §27.28. Segmented substitutions

A "segmented" substitution is a syntax where text is placed between two or more different text substitutions. Examples include:

"This hotel is [if the player is female]just awful[otherwise]basic[end if]."
"Annie [one of]dances[or]sulks[or]hangs out at Remo's[at random]."

To create such syntaxes, it is not enough just to define how each expands into I6 code: for one thing we may need to know about the later terms in order to expand the earlier ones, which is normally impossible, and for another thing, the individual text substitutions mean nothing in isolation. For instance, Inform produces a problem if the following is tried:

"The hotel [at random] is on fire."

because "[at random]" is only legal when closing a "[one of] ..." construction. But if "[at random]" had been defined as just another text substitution, Inform would not have been able to detect such problems.

Inform therefore allows us to mark text substitutions as being any of three special kinds: beginning, in the middle of, or ending a segmented substitution. There can be any number of alternative forms for each of these three variants. The syntax policed is that

(a) Any usage must lie entirely within a single say or piece of text.
(b) It must begin with exactly one of the substitutions marked as "beginning".
(c) It can contain any number, including none, of the substitutions marked as "continuing" (if there are any).
(d) It must end with exactly one of the substitutions marked as "ending".

A simple example:

To say emphasis on -- beginning say_emphasis_on: (- style underline; -).
To say emphasis off -- ending say_emphasis_on: (- style roman; -).

This creates "[emphasis on]" and "[emphasis off]" such that they can only be used as a pair. The keyword "say_emphasis_on", which must be a valid I6 identifier (and hence a single word), is never seen by the user: it is simply an ID token so that Inform can identify the construction to which these belong. (We recommend that anybody creating such constructions should choose an ID token which consists of the construction's name but with underscores in place of spaces: this means that the namespace for ID tokens will only clash if the primary definitions would have clashed in any case.)

Examples

453. Chanel Version 1 Making paired italic and boldface tags like those used by HTML for web pages. (c.f. RB §12.1. Typography)

WI §27.29. Invocation labels, counters and storage

The process of expanding the I6 code which represents a phrase is called "invocation". As we have seen, when a phrase is defined using a single piece of I6 code, invocation consists of copying out that I6 code, except that tokens in braces "{thus}" are replaced:

To say (something - number): (- print {something}; -).

Ordinarily the only token names allowed are those matching up with names in the prototype, as here, but we have already seen one special syntax: "{phrase options}", which expands as a bitmap of the options chosen. And in fact the invocation language is larger still, as a skim through the Standard Rules will show. The notes below deliberately cover only some of its features: those which are likely to remain part of the permanent design of Inform, and which are adaptable to many uses. Please do not use any of the undocumented invocation syntaxes: they change frequently, without notice or even mention in the change log.

The first special syntaxes are textual tricks. {-delete} deletes the most recent character in the I6 expansion of the phrase so far. {-erase} erases the I6 expansion of the phrase so far. {-open-brace} and {-close-brace} produce literal "{" and "}" characters.

The following:

{-counter:NAME}
{-counter-up:NAME}
{-zero-counter:NAME}
{-counter-makes-array:NAME}

create (if one does not already exist) a counter called NAME. This is initially zero, and can be reset back to zero using "{-zero-counter:NAME}", which expands into no text. The token "{-counter:NAME}" expands into the current value of the counter, as a literal decimal number. The token "{-counter-up:NAME}" does the same, but then also increases it by one. Finally, the token "{-counter-makes-array:NAME}" expands to nothing, but tells Inform to create an "-->" array called "I7_ST_NAME" which includes entries from 0 up to the final value of the NAME counter.

This allows each instance in the source text of a given phrase to have both (i) a unique ID number for that invocation, and (ii) its own word of run-time storage, which can allow it to have a state preserved in between times when it is executed. For example:

To say once only -- beginning say_once_only:
    (- {-counter-makes-array:say_once_only}if (I7_ST_say_once_only-->{-counter:say_once_only} == false) {-open-brace} I7_ST_say_once_only-->{-counter-up:say_once_only} = true; -).
To say end once only -- ending say_once_only:
    (- {-close-brace} -).

To complete the tools available for defining a segmented substitution, we need a way for the definition of the head to know about the middle segments and the tail:

When invoking either the head or the tail, {-segment-count} expands to the literal decimal number of pieces of text in between the two, which is always one more than the number of middle segments, since the text comes in between the segments. When invoking any middle segment, {-segment-count} expands to the number of pieces of text so far -- thus it expands to 1 on the first middle segment invoked, 2 on the next, and so on.

Lastly {-final-segment-marker} expands to the I6 identifier which marks the end segment, or to I6_NULL if the end segment has no marker. The idea of markers is to enable the head's definition to know which of a number of choices has been used for the tail, supposing that this is a construction with a variety of legal endings. For example:

To say emphasise -- beginning say_emphasise:
    (- style {-final-segment-marker}; -).
To say with italics -- ending say_emphasise with marker underline:
    (- style roman; -).
To say with fixed space type -- ending say_emphasise with marker fixed:
    (- style roman; -).

The markers used for the tails here are "underline" and "fixed", and when the head is invoked, the marker for its tail is expanded into the argument of I6's "style" statement.

The examples above are all to do with segmented substitutions, which is where they are most useful, but most of the syntaxes above work equally well for ordinary "To..." phrase definitions.

WI §27.30. To say one of

Many of the invocation syntaxes described in the previous section are used in the definition by the Standard Rules of the "[one of] ... [or] ... [purely at random]" construction, so it makes a good example of how they can be used.

First, this is a segmented substitution with a single possible beginning ("[one of]"), a single possible middle ("[or]") but a choice of many possible endings. Almost everything is compiled by the invocation of the beginning:

To say one of -- beginning say_one_of (documented at phs_oneof): (-
    {-counter-makes-array:say_one_of}
    {-counter-makes-array:say_one_flag}
    if (I7_ST_say_one_flag-->{-counter:say_one_flag} == false) {
        I7_ST_say_one_of-->{-counter:say_one_of} = {-final-segment-marker}(I7_ST_say_one_of-->{-counter:say_one_of},
{-segment-count});
        I7_ST_say_one_flag-->{-counter:say_one_flag} = true;
    }
    if (say__comp == false) I7_ST_say_one_flag-->{-counter:say_one_flag}{-counter-up:say_one_flag} =
false;
    switch ((I7_ST_say_one_of-->{-counter:say_one_of}{-counter-up:say_one_of})%({-segment-count}+1)-1)
{-open-brace}
        0: -).
To say or -- continuing say_one_of (documented at phs_or):
    (- @nop; {-segment-count}: -).
To say purely at random -- ending say_one_of with marker I7_SOO_PAR (documented at phs_purelyrandom):
    (- {-close-brace} -).

The 3rd invocation of this (say) might compile the following:

I7_ST_say_one_of-->2 = I7_SOO_PAR(I7_ST_say_one_of-->2, 4);
switch((I7_ST_say_one_of-->2)%5 - 1) {
    0: ... first text ...
    1: ... second text ...
    2: ... third text ...
    3: ... fourth text ...
}

First, we notified Inform that it needs to allocate an array (I7_ST_say_one_of) providing storage associated with the counter "say_one_of". This we used to count off individual invocations of "[one of]", so that each would have its own word of storage - for the 3rd invocation, I7_ST_say_one_of-->2. We then call a state-changing routine, in this case I7_SOO_PAR, which is allowed to know the previous state and also the number of options available, and which returns the new state. The state is supposed to be the option chosen last time, but that means that there are not 4, but 5 possibilities: 0 for "there was no last time", then 1 to 4 for the possible outcomes. We reduce the state mod 5 to obtain the decision this time, and subtract 1 because it happens to be convenient to make the switch statement run from 0 to 3 rather than 1 to 4. (The reason we reduce the state mod 5 is to allow the state-changer to squirrel away secret information in the upper bits of the state, if it wants to. Note that subtracting one means that the switch value might be -1, which results in no text being printed: thus if the state-changer chooses 0, it can decide on none of the above.)

In this design, the marker attached to the choice of ending substitution is the name of the I6 state-changer: here is the I7_SOO_PAR routine.

[ I7_SOO_PAR oldval count; if (count <= 1) return count; return random(count); ];

As it happens, this ignores the old value: after all, it is meant to be purely at random, and nothing could be less pure than taking the last outcome into consideration when choosing the next.

Note that the counter say_one_of is advanced in invocation of the head. It might seem that the tidier design, somehow, would be to advance the counter in the invocation of the tails, but this is not a good idea. In general it is not safe to assume that the counter will have the same value when the tail is invoked that it had when the head was invoked, because segmented say constructions can legally be nested in Inform strings. Because of this, it is best to deal with a counter entirely in a single invocation, either of the beginning or the ending.

Because "[one of] ... [or] ..." is such a useful construction - switching between alternative forms of text, which writers of IF very often do - the above implementation is intentionally left open for new endings to be added, and the examples below show how easily this can be done.

Examples

454. Blink Making a "by atmosphere" token, allowing us to design our own text variations such as "[one of]normal[or]gloomy[or]scary[by atmosphere]". (c.f. RB §2.1. Varying What Is Written)

455. Uncommon Ground ★★ Making a "by viewpoint" token, allowing us to design our own text variations such as "[show to yourself]quaint[to Lolita]thrilling[to everyone else]squalid[end show]" depending on the identity of the player at the moment. (c.f. RB §5.6. Viewpoint)