Inform7/10 Reference Manual

“The puddle is fixed in place” in particular is relatively common and parallel to “the puddle is scenery”.

1 Like

Okay, so “puddle is lit” and “puddle is fixed in place” both compile. And so does this:

A thing can be current.
The puddle is current.

And this:

A thing can be current or obsolete.
The puddle is obsolete.

And even this:

A thing can be current, fading away, or obsolete.
The puddle is fading away.

And wow, even this!

A thing has a number called age.
The age of the puddle is 3.

So it’s not even limited to either/or properties – seems like any property on things will infer that something is a thing.

However, this doesn’t work, so it’s not a question of “is it the only kind the property can possible apply to”:

A container has a number called bulk capacity.
The bulk capacity of the trolley is 42.

I suspect it’s more that Inform automatically assumes that an unknown name is a thing, so if the property is one that applies to things, everything’s fine and it just sets it.

I assume you meant an enumerated value here?

Ah, that’s true, and Inform does in fact treat it that way if you use “called” in your relation definition or define a verb to mean a property (as mentioned in my assertions post).

Loving relates one number to various texts.
Hating relates various numbers to one text.

The verb to love means the loving relation.
The verb to hate means the hating relation.

2 loves "two".
2 loves "duo".
4 hates "four".

Why? I mean, why not? Values can have properties and relations. Numbers are values.

Oh, I missed that you said “relation” instead of “property” there.

I already covered the two biggest giants in Inform7 syntax, so in this post and the next big post I’ll go through all the bits and pieces I missed:

  • Headers
  • Literals
  • Comments
  • Asides
  • Punctuation and articles
  • Imperative assertions
  • Basic phrases

I think that should cover everything.


A header takes the following general form:

«level» «number» - «title» [( «special instruction» )]

The level is one of the following, ordered from highest to lowest:

  • Volume
  • Book
  • Part
  • Chapter
  • Section

The number doesn’t need to be an actual number, but I think it has to be a single word. A heading must be preceded and followed by a blank line. The title can be any text. I think it can even be omitted entirely along with the separating hyphen (and the number can similarly be omitted). Most special instructions are specified in parentheses, but there are some that can also be set off with an additional hyphen instead. I won’t note which ones those are. Though all three parts of the heading other than the level itself are optional, you must have at least one of them in order for it to count as a heading.

The special instruction can be any of the following:

not for release
for release only
for use with «extension»
for use without «extension»
for «interpreter» only
not for «interpreter»
in place of «section» in «extension»

The «interpreter» can be either Z-machine or Glulx.

When using in place of, the section being replaced must be of the same level as the section replacing it, and the section name specified must be the full, exact name of the substituted section (probably including any special instructions). The section name can be enclosed in quotes to resolve ambiguity (needed if it contains the word in). When naming an extension, you must use the full, exact name of the extension and its author.

Other than headings, there are a few heading-like special syntax cases. The first is the story header:

«quoted title» by «optionally-quoted author»

This is syntax sugar for setting the variables story title and story author.

An extension must be bracketed by the following paired sentences:

[version «number» of] «extension name» by «author» begin/begins here.

«extension name» end/ends here.

Immediately following the extension opening sentence, there may be one or two paragraphs consisting of nothing but a single quoted string. The first is a short description of the extension’s content, known as the “rubric”, and should be formatted as a proper paragraph. The second text is intended as a way to provide credit to additional authors, and should be written in a way that makes sense when placed in parentheses after the extension’s name.

After the extension closing sentence, you may add an optional documentation section, introduced by a line exactly like this surrounded by blank lines:


Everything after the documentation header is treated as a comment. (However, actual comments are still parsed and thrown out, meaning they won’t appear in the generated documentation at all.) There are some special syntaxes used to control the format of the generated documentation.

First of all, any series of paragraphs indented by a single tab is treated as sample code, and will be formatted as such in the generated output.

Next, the documentation section has its own set of headings, which work sort of like the main source text headings in that they must be preceded and followed by a blank line. There are three types:

Chapter : «title»
Section : «title»
Example : (* | ** | *** | ****) «name» - «summary»

The asterisk(s) specify the example’s level. An example section should contain a complete code sample that can compile if copy-pasted into a fresh project, culminating with one or more test assertions that demonstrate the scenario. If there are multiple examples, they should be ordered by increasing level (number of asterisks).

An indented code sample can begin with the special syntax *: to request that a paste button be inserted. The paste button will paste the sample code from the point where *: is placed up until the end of the indented passage. Examples don’t automatically get a paste button, so one of these should generally be included at the top of each example.

Everything in the code sample must be indented in order for the paste button to work – unlike the examples in Writing with Inform, extension document doesn’t support any way to add commentary interspersed with the example code. You can add unindented commentary, but it will interrupt the operation of the paste button, so it’s best not to in most cases.


Inform7 supports three categories of literal values – quoted values (text and topics), arithmetic values (numbers, time, units, etc), and lists. Most other kinds, such as objects or enumerations have named values, which I’m not counting as literals. This includes the truth state type with its values true and false.

Arithmetic Literals

The number kind in Inform7 is what most other programming languages (and mathematicians for that matter) would refer to as integers. There isn’t really anything special about how they’re represented – just a sequence of digits, potentially preceded by a minus sign. The only unusual details are that numbers from zero to twelve can be written out in words, and that ordinal forms of the numbers can be used in some contexts (and again, first through twelfth can be written out in words). An ordinal is formed by adding the th suffix to the number, but it is purely sugar and has no actual effect on how the line is interpreted. However, it doesn’t seem to be allowed in static assertions.

Real numbers are represented very differently from most programming languages, but in a form that would be more familiar to a mathematician:

1.2345 x 10^26

The x can be either the letter X or an actual multiplication sign. Of course, the exponent can be omitted if not required for the range of number being represented. Inform predefines e and pi as constants, and also understands plus infinity and minus infinity.

Note: One thing to be wary of when working with numbers in Inform7 is that it does not honour standard rules of mathematical precedence and associativity when using mathematical operators in a phrase. If you have any math more complicated than basic addition or multiplication, it’s recommended to use an equation instead.

Any integer constant can be turned into a unicode character constant by simply prefixing the word unicode to it. This is still considered to be a constant and thus can be used in static assertions.

Custom arithmetic types can define arbitrary syntax around the core of what makes a number, using almost any combination of symbols or words imaginable. One such type is built-in – the time type, which can be expressed in the following ways:

«HH»:«MM» AM
«HH»:«MM» PM
«number» hours [«number» minutes]
«number» minutes

Quoted Literals

Most of the time, something enclosed in double quotes is text. The contents of text is usually literal, but there are three exceptions to this:

  • A literal apostrophe character is treated specially. Unless it’s both preceded and followed by a letter, it will be replaced by a double quote. You can explicitly specify an apostrophe where it would otherwise be replaced using ['] or [apostrophe]. Similarly, you can explicitly specify a double quote where it wouldn’t normally be inferred with [quote].
  • Any string ending with a literal period, exclamation mark, or question mark (., !, or ?) automatically has a line break appended. (Literal here means that it won’t occur if the period is present as a result of another substitution.) Take note that this doesn’t occur with other punctuation, such as an ellipsis (), though three successive dots of course does produce this behaviour (since that’s ending in a period). You can disable this behaviour by simply adding a space after the punctuation. If you want this behaviour when it wouldn’t be implicit (for example, after an ellipsis character), just add [line break].
  • Anything enclosed within square brackets is treated as a substitution. The syntax shown above used to work around the preceding two rules are just some basic examples of substitutions.

There are a few contexts where text is not allowed to have substitutions (with a special exception for [']). The story title is the primary one. Possibly it applies to all bibliographic information.

Substitutions can either be expressions that evaluate to a sayable value, or specially-defined say phrases.

The first type is already extremely versatile. Nearly all kinds of value are sayable in Inform7, including names of objects, values of enumerated kinds, and literal values. Any phrase that returns a value (ie, phrases defined with to decide which/what) can be used as a substitution. Conditional phrases can similarly be used, by converting the condition to a truth state value with the whether or not phrase. You can also use the names of properties without specifying the object you want to take the property from – in this case it infers you’re referring to a property of the item described.

And perhaps the most powerful type of value substitution in Inform7 is verbs. Verbs are treated as values in Inform7, and substituting a verb into text will automatically adapt the verb to the current story tense, story viewpoint, and current object being discussed[1]. Pronoun phrases and the special phrase regarding «something» updates said object in the middle of the text, and substituting the name of an object also automatically updates it.

Say phrases are extremely powerful, allowing you to do anything you want, even altering game state in response to text being printed. However, you must be careful if doing this, as text may be expanded for purposes other than printing. There is a conditional phrase to help with this. There are built-in say phrases for automatically substituting the right pronoun or article for a given context, and many other things as well.

There are several advanced types of substitutions where several square-bracketed sections work together in concert to produce the final result. These are called segmented substitutions. The simplest of these is the if/else substitution.

Usually, quoted passages are treated as text meant to be output to the screen and read by the player. However, in some contexts, quoted passages are instead treated as topics used to match the player’s input. In a topic, square brackets don’t mean substitution, but instead enclose either descriptions of values or specific matching tokens. There are only a small number of tokens available, though new ones can be defined as needed.

In addition to square bracket matching patterns, topics support two other syntaxes. The first is word alternations, which is a sequence of words separated by forward slashes, potentially ending in /--. This syntax within quoted topics has the exact same semantics as the same syntax used in defining phrases – it’ll match exactly one of the specified words, or possibly none if -- is included.

The second syntax is that two or more topics can be joined together with or to represent something that must match exactly one of the topics in question. This is sort of halfway between an expression and a value. It can be used in understand assertions and also in a table column called topic or explicitly declared as being of kind topic. It’s not allowed in general assertions or rulebook preambles. I’m not sure if it can be used anywhere else.

List Literals

List literals are, strangely enough, simpler to define than the other two types. They take the following form:

{ [«value» (, «value»)] }

A list literal can only contain constants, not variables.


Comments in Inform7 are probably one of the simplest parts of the language. Any text enclosed in square brackets ([]) outside of a quoted string is treated as a comment. Furthermore, comments can be nested – all open brackets encountered during the comment must be matched before the comment ends.

There is just one special syntax within comments, used when generating an HTML page displaying the source text. A comment beginning with * will be converted to a footnote on the resulting page.


I’m using the term “asides” for chunks of text set apart from the source text. There are either two or five types of asides, depending on how technical you want to get on the topic of what exactly constitutes an aside.


A table is a chunk of text set apart from the source text (with a blank line before and after it) which has the following overall line structure:

Table «table title» [( continued/amended )]
«optional blank line»
«table header row»
«table content row»*
[with «number» blank rows.]

The table title can take on one of the following forms:

of «name»
«number» - «name»

As with headers, the number need not be an actual number, but should be a single word. The third form is interesting in that it actually defines two separate names for the table – the table may henceforth be referred to either as “table «number»” or as “table of «name»”. Note that it may not be referred to as “table «number» - «name»”.

The optional parenthetical after the table title allows adjusting a previously declared table, either adding extra rows at the end or modifying previously-defined rows. When amending tables, Inform searches for a match based on the leftmost columns, one at a time, until the possible matches are narrowed down to a single row. It’s an error if no rows are matched, or if more than one row is matched. Columns used for matching are limited in the kinds they can contain. Enumerated values are allowed, as are most arithmetic values. The documentation doesn’t mention real numbers in the list of permitted values, which may mean that real-valued units are not allowed (I have not tested it). Activities, objects, and action names are also permitted.

The header and content rows both consist of tab-separated cells. The cells are separated by exactly one tab. The header and each content row must have the same number of cells, with the exception that content rows can omit trailing blank cells entirely (ie, not even adding the tabs as placeholders).

If using an IDE other than the official IDE, the fact that tables require exactly one tab between columns can be problematic, as few IDEs allow for elastic tabs as the official one does (though the official IDE’s elastic tabs are very buggy and only properly align the table about one-third of the time). Fortunately, spaces between table columns have no effect whatsoever on how the table is parsed, so it’s not hard to manually align a table by inserting an appropriate number of spaces before each of the column-separating tabs.

Each table header cell has the following form:

«name» [( «kind» )]

Each table content cell can take one of the following forms:


The special syntax -- specifies a blank cell. Such a cell doesn’t even have the default value for the column’s kind – there’s nothing there at all. For those familiar with databases, you can think of it as a “null”. In some programming languages, this kind of situation is also called an “optional”.

Placing the name of a kind in a table cell is an alternative to specifying the kind after the name of the column. It’s only allowed in a column that’s blank (there are no values in any row) and even then only in the first row.

As long as a column contains at least one value, it’s generally not necessary to specify the kind of the column – it will be inferred from the value. Each cell in a given column must contain the same kind. Usually, quoted text is inferred as the text type, but an exception is made if the column is named topic – such a column is inferred as the topic type. You can also explicitly declare a differently-named column as a topic column, of course.

Defining a table also defines each of its columns as value of type “table column of kind K”. The practical outcome of this is that you can’t have two tables that have a column with the same name but a different type. If you do happen to declare a second table which reuses a column name, the type will be assumed to match that of the first table (and any attempt to override that is an error).


Like a table, an equation is a chunk of text set apart from the source text. It has the following overall line structure:

Equation «title»
«equation content»
where «variable declarations».

Similar to tables, the equation title can take on one of three forms:

- «name»
«number» - «name»

And similarly to tables, the third version defines two different names for the same equation. The only difference between table names and equation names is that equation names don’t use the word of when referring to an equation by name – it’s simply “equation «name»”.

The equation content consists of the mathematical equation written according to conventional mathematical style. It must contain exactly one equals sign (=. It’s common to indent the equation, but this is not required. Conventional mathematical style means that implicit multiplication is supported, so for example if m and a are defined as variables, then ma is read the same as m*a. The supported operators are just + - * / ^. Other than that, parentheses are understood for grouping.

Several common mathematical functions are understood. Parentheses are not required for function application, in keeping with conventional mathematical style for well-known functions; however, you do need a space after the function name (but a space before is optional). The full list of understood functions is:

abs (absolute value)
root (square root)
ceiling, floor
int (I’m not sure what this does; I thought it would be truncation but got very weird results when trying it)
log, exp (log is specifically the natural logarithm)
sin, cos, tan, arcsin, arccos, arctan
sinh, cosh, tanh, arcsinh, arccosh, arctanh

The variable declarations at the end of the equation specify the meaning of each of the variables. It’s essentially one or more simple assertions stating the kind or value of each variable, separated by commas. Variable names in equations don’t have to be a single letter, but they do need to be short. Also, unlike normal mathematical convention (but like everything else in Inform), variable names should be considered to be case-insensitive. Examples:

a, b, and c are numbers
m is a mass and a is an acceleration
m is a mass and g is 9.8 m/s/s and h is a length

An equation is more than just a function that can calculate one value from several inputs. In fact, Inform7 understands algebra enough to solve the equation for any variable it uses (as long as there is an unambigious solution). Additionally, unlike in phrases containing arithmetic operators, equations correctly respect mathematical precedence and associativity.

When solving an equation, Inform looks for the variables needed by the equation amonst those variables visible to the local scope. Thus, it’s typical to locally define all but one of the required variables prior to solving the equation.

It’s possible to define an anonymous equation inline in a phrase. The syntax is essentially the same, but without the title – that is, it looks like the following:

«equation content» where «variable definitions»

Assuming the input variables all exist already, you don’t need to specify their types again, but you do need to specify at least the type of the variable being solved for (generally the sole variable to the left of the equals sign in this case).

Other Asides

The other three types covered here are figures, sounds, and external files. It’s debatable whether these actually qualify as asides, but from a literary standpoint, they serve a similar purpose, so I’ve included them here. As far as I can tell, they don’t share the binary naming convention of tables and equations, though they’re often named as though they did. They can be declared with the following assertions:

figure/sound «name» is the file «quoted filename» [( «quoted alt text» ).
[binary] file «name» [( owned by (another project | project «quoted UUID») )] is called «quoted name without extension».

  1. I’m not completely clear on how this is determined. I know there’s a prior named object, but I don’t think that can cover all the ways in which verbs adapt, such as the regarding «description/number» forms. ↩︎

1 Like

There’s not really a passive and active voice and “prepositions” are just any word beyond the first word in a verb.

When you say

R relates K to L.
The verb to V means the R relation.

then, assuming V is a single word, three verbs get created:

  • to V → the R relation
  • to be Ving → the R relation [“for meaning only” – can be used in code but not say statements ]
  • to be Ved by → the reversed R relation [ for meaning only ]

If V is multi-word or to V means a reversed relation, the other forms aren’t automatically created.


Whatever the mechanics behind it, the fact remains that you can use a verb you defined for a relation in the passive and progressive forms. So, close enough in my book.

This I was aware of, probably didn’t make it clear enough in the post though.

Ah, this is good to know, that it’s based entirely on the number of words rather than being special handling for “to be”.

I gave this a try but it doesn’t seem to be accurate:

Boredom relates various things to various people.
The verb bore means the boredom relation.
Ben is a person.
Cribbage bores Ben.
Ben is bored by Scrabble.
Poker is boring Ben.
The verb to abhor means the reversed boredom relation.
Ben abhors Bridge.
Ben is abhorring Blackjack.
Crazy Eights is abhorred by Ben.


Boredom relates various things to various people:
  Cribbage  >=>  Ben
  Scrabble  >=>  Ben
  Poker  >=>  Ben
  Bridge  >=>  Ben
  Blackjack  >=>  Ben
  Crazy Eights  >=>  Ben

(Actually it prints the entire list twice, but that’s beside the point.)

Something else I accidentally discovered from this: the word to is actually optional.

sorry, I said it all wrong. If you say to be Ved by means the reversed R relation you don’t get the other forms. So it’s really just another case of the multi-word verbs don’t get the automatically created variants.

1 Like

I haven’t proofread it in detail this time, so there might be some typos, but here’s the last three sections I mentioned earlier.

Punctuation, articles, plurality
Punctuation The most important unit of punctuation in Inform source text is the period, which naturally enough ends a sentence. Normally, every sentence (and every phrasebook) is expected to end with a period. However, periods are implicitly inserted under two circumstances:
  • Before a blank line (paragraph break)
  • After quoted text ending in a period, exclamation mark, or question mark.

The comma (,) is also pretty significant, but it’s not really discussed in the documentation as far as I can tell. In many contexts it can precede (or even substitute for) the words or and and… but there are some places where that doesn’t appear to work. In assertions it can be placed between adjectives, which can help disambiguate multi-word adjectives in some cases, but that doesn’t seem to work in conditions.

Next on the list of general-purpose punctuation is parentheses (()). Though they have special meanings in many places, and using them in an assertion is not allowed outside of those special meanings, they can be used for grouping in both descriptions and conditions.

For example, suppose you have a room called “Road to Paradise” and want to disable exiting it on foot in a specific direction. The obvious way won’t work:

Instead of going west from Road to Paradise by nothing:

The parser unfortunately sees the “to” in the name and (if I understand correctly) thinks you’re trying to match the room gone to, so it would only match if west of the Road to Paradise was the Road to Paradise. You can work around this issue by enclosing the name of the room in parentheses:

Instead of going west from (Road to Paradise) by nothing:

Lastly, I’ll give an honorable mention to the colon and semicolon, which play a role in phrasebooks. However, their usage was already specified in the section in question, so I won’t say any more than that.

Filler Words

Some people might see my syntax definitions earlier in the thread and wonder, where are the articles? Well, I omitted them for a good reason. The words a, an, the, and some are in most cases treated by Inform as the same as whitespace – they have no semantic effect on the source text.

There are some cases where a specific article is required (such as an actor doing something), and articles can be significant in the name of a phrase because Inform prefers to use a phrase with more words, even if those words are articles. Besides that, there’s at least one more way in which articles are significant – when defining an object (but not a value), Inform looks at the article used and takes it into account when defining the object.

To be more precise, every object has an indefinite article property, which is blank by default. (I think being blank is exactly equivalent to setting it to "a" or "an", whichever is appropriate.) If you define the object via called the «name», Inform sets the indefinite article property to "the". It doesn’t seem to do this with some however, and I’m not completely clear on the rules for this.

However, if the object is defined with some, it does get the plural-named property. Or, if it’s defined with no article at all, it receives the proper-named property. So, the presence or absence of an article will affect how Inform thinks your object should be referred to. Of course, in all cases you can override its guess with a specific assertion.

Speaking of plurality, plurals are another thing that exists in the syntax but has no semantic significance. You can happily write ungrammatical sentences like 'The dogs is in the kitchen" or “Some water are scenery in the beach” and Inform won’t care at all. In other words, the plural and singular forms of a noun or verb are, in nearly all cases, completely interchangeable. The one case I know of where this isn’t true is rule and rulesrule refers to a single rule, but rules is a synonym for rulebook.

The ordinal suffix (and ordinal forms of small numbers) is another example of syntax that exists solely for familiarity but doesn’t have any special meaning. Though ordinal numbers seem to be an error (or misunderstood as part of a name) when used in assertions, in conditions and descriptions they’re synonymous with the equivalent cardinal number.

Imperative assertions

Understand «topic» as «action name» [( with nouns reversed)] [when/while «condition»].
Understand the command «command-list» as «command».
Understand the command «command» as something new.
Understand nothing as «action name».

These forms all work with verbs – defining a verb to mean an action, giving word-level synonyms, or clearing out previously-defined grammar.

For the first one, there’s a special restriction on the topic – there may not be any alternations on the first word.

Understand «topic» as «value or kind» [when/while «condition»].
Understand «topic» as the plural of «value or kind» [when/while «condition»].

These forms work on nouns. I don’t really have anything more to say here.

Understand «topic» as «token».
The understand token «name» translates into I6 as «quoted I6 identifier».

The token to be defined in the first form must be a quoted string containing nothing but a single square-bracketed token. The topic here is also restricted – it may contain at most one token in it, and if you use alternatives with or, every alternative must be compatible. Either they all contain no tokens, or they all contain a token of the same kind.

Understand «property» as describing «value or kind» [when/while «condition»].
Understand «property» as referring to «value or kind» [when/while «condition»].
Understand «topic» as «adjective».

The “describing” form allows the adjective to be used alone to refer to the object, whereas “referring to” means it can only refer to the object if it appears alongside the object’s name.

And lastly:

Understand «topic» as a mistake [( «text» )] [when/while «condition»].


Text «name» with «script» [holding «thing» [ ( [ , ] and | , ) «thing» ] ] [in «room»].

The script is a quoted list of commands to be run, separated by forward slashes (/). Unlike everywhere else in the language, the forward slash here doesn’t separate words only – it functions more like a semicolon or period. I believe you can use [/] if you need a literal forward slash to be included in a command.


Include [version «version» of] «extension» by «author».
Include (- «Inform 6 code» -) [when defining «kind» | replacing «quoted I6 identifier»].


Use «option» [of at least/most «value»] (and «option» [of at least/most «value»])*.

I’m not going to cover the syntax of how to define use options, since it’s due to be overhauled in the next release.


Release along with «release instruction» (and «release instruction»)*.

Possible release instructions include:

file «text» called «quoted file or directory name»
cover art [( «quoted alt text» )]
introductory booklet/postcard
«quoted template name» website
«quoted interpreter name» interpreter
existing story file [called «quoted filename»]
[public/private] solution
[public/private] source text
[public/private] library card

Index map

Index map with «mapping instruction» (and «mapping instruction»)*.

Possible mapping instructions are:

«room» mapped «cardinal direction» of «room»
«direction» mapped as «cardinal direction»
EPS file
rubric «text» [size «number»] [font «text»] [color «text»] at «offset» [from «room»]
«setting» [of «part»] set to «value»

When adjusting settings, the optional part can be one of the following:

«description of rooms»
«description of regions»
first room
level «number»

The level number can be negative.

Setting values can be any of the following (depending on the setting in question):

«quoted text»

That last type is called an offset.

The possible settings are:


Basic phrases

General Flow Control

rule succeeds – the containing rule succeeds with no outcome
rule fails – the containing rule fails with no outcome
make no decision – the containing rule makes no decision and produces no outcome
rule succeeds with value – the containing rule succeeds with no outcome and the specified value
«rulebook outcome» – the containing rule succeeds, fails, or makes no decision, and produces the specified outcome
continue the action/activity – equivalent to “make no decision”
stop [the action] – generic “return nothing” statement for phrases
[decide ] yes/no – return true or false
decide on – return specified value
next – go to next loop iteration
break – exit loop
do nothing – the placeholder for when you have a block that needs a phrase but no phrase to put there; this phrase just does nothing.


A few core, built-in phrases introduce a block, which is a sequence of statements under the control of the introductory phrase. There are two ways to write a block, but you can’t mix the two ways in the same phrasebook.

The first way is to start with a colon (:) and then indent each subsidiary phrase one level deeper than the level of the controlling phrase. This is similar to how the Python programming language handles scoping.

The other form looks like this:

«first word of phrase» «rest of phrase» begin ; «sequence of subsidiary phrases» end «first word of phrase repeated»

I think it gets a bit more complicated than that in if statements, but at least that’s the basic idea.


if/unless «condition» , «single phrase»
[otherwise/else «single phrase»]

I’m pretty sure one-liners can only use the above form – there’s no “else if” equivalent.

if/unless «condition» : «sequence of phrases»
otherwise/else if/unless «condition» : «sequence of phrases»
otherwise/else : «sequence of phrases»

Note that otherwise and else are completely synonymous. On the other hand, if and unless are opposites – the latter negates the entire condition.

A switch statement has the following structure:

if «value» is : «block of phrases»
( -- «value» : «block of phrases»)*
[ -- otherwise : «block of phrases»]

Note that, unlike in regular conditional statements, we don’t have else as a synonym for otherwise here (which is weird), nor do we have the opion of using unless to negate the entire condition (which wouldn’t make sense in any case). Also note that a switch statement cannot be used in the begin/end style of blocks – if you want to use a switch statement you need to use indentation.


while «condition» :
repeat with «name» running from «arithmetic or enumerated value» to «value of same kind» :
repeat with «name» running through «description of values» :
repeat through «table name» [in [reverse] [«table column»] order] :

That last one is slightly imprecise – you need at least one of reverse and a table column. It’s not allowed to say in order.


The say phrase might be the most complicated phrase in the game. I think this is its most general form:

say «sayable thing» (, «sayable thing»)*

where a sayable thing is one of the following:

«text» [( «response letter» )]
«expression evaluating to sayable value»
«say phrase»

Saying a comma-separated list of things seems to be exactly equivalent to saying each of them in turn in separate say statements.

The first form of a sayable thing is by far the most common – any quoted text, with an optional response letter following it. However, it’s interesting to note that if the entire contents of your text is a bracket substitution, you can get the same effect by removing both the quotes and the brackets.

A response letter is only valid in named rules. In particular, it is not valid in named phrases (which seems a little strange to me, honestly). It must be a single uppercase letter, which means you’re limited to at most 26 responses in any given rule. (If you find yourself exceeding this, it’s probably a sign you should split the rule up anyway.) Using this form creates a value of kind response called “«name of the rule» response ( «response letter» )”. A response can be assigned to in assertions as though it’s a variable.


I’m not going to cover every imaginable phrase, as the Phrasebook section in the index is pretty extensive, but I’ll list a few more of the most basic ones here.

let «name» be «value or kind»

When specifying the kind, the «name» must not already exist. However, when specifying a value, the name can already exist, and must be a local variable. (You can’t use let to assign to global variables.) If you only declare the kind, the initial value is the default value of that kind.

now «condition»

As crazy as it seems, this statement takes almost any condition and immediately arranges things so that it’s true. To be more precise, it will only accept the same kinds of conditions that you can use as static assertions. For example, no past tense or calculated adjectives or relations. I’m not sure if there are any types of conditions that work statically but not in now or vice versa.

whether or not «condition» … truth state

This value phrase effectively casts a condition to a truth state value. Since conditions and values are two different things in Inform, this allows converting between them. Note that true and false are not valid conditions on their own, unlike in many programming languages. If you have a truth state variable, you need to test it with is like anything else.

If I’ve missed some basic, core phrase, please let me know.

It is strange that Inform supports unless as the opposite of if but does not support until as the opposite of while – probably an oversight? It would seem to be easy to fix that, but for some reason I can’t get this to work:

To until (c - condition) begin -- end loop:
	(- while ~{c}  -).

When play begins:
	until true is true:
		do nothing.

Problem. You wrote ‘until true is true’: but the punctuation here ‘:’ makes me think this should be a definition of a phrase and it doesn’t begin as it should, with either ‘To’ (e.g. ‘To flood the riverplain:’), ‘Definition:’, a name for a rule (e.g. ‘This is the devilishly cunning rule:’), ‘At’ plus a time (e.g. ‘At 11:12 PM:’ or ‘At the time when the clock chimes’) or the name of a rulebook, possibly followed by some description of the action or value to apply to (e.g. ‘Instead of taking something:’ or ‘Every turn:’).

The error seems to indicate that it’s not recognizing that the phrase should begin a block. I can’t get it to work with the begin…end form of blocks either, though that gives different error messages.

Nope, common misconception. “Stop” and “stop the action” are defined exactly alike (return true at the I6 level). “Continue the action” and “make no decision” are also equivalent (return false). These phrases stop the current rule but do not record a rulebook outcome.

“Rule succeeds” and “rule fails” return true after recording a rulebook outcome.

1 Like

This works:

lab is a room.

To repeat until (c - condition) begin -- end loop:
        (- while (~~{c})  -).

When play begins:
let i be 1;
repeat until i is 4 begin;
  say i;
  increment i;
end repeat;
1 Like

I edited the post since that’s actually an error (if I’d stopped to think about it, it would’ve been obvious that continue was the same as make no decision), but I’m not so sure it’s incorrect to say that stop the action is equivalent to rule fails. After all, it stops the rulebook from processing other rules, which is pretty much what people expect from rule fails.

I can see from the definition that it indeed just returns true without calling RulebookFails(). It’s used everywhere throughout the Standard Rules in various check rules and the like. It’s not entirely clear to me how it differs from rule fails, but if what you’re saying is accurate, it sounds like a mostly undocumented fourth way that a rule can end (apart from fails, succeeds, and no decision).

  • rule fails – sets the rule failed to true and the rule succeeded to false, and the rulebook stops processing
  • rule succeeds – sets the rule succeeded to true and the rule failed to false, and the rulebook stops processing
  • make no decision or continue the action/activity – leaves the rule succeeded and the rule failed both false, and the rulebook just continues processing.
  • stop the action – leaves the rule succeeded and the rule failed both false, and the rulebook stops processing

And if that’s really how it works, it seems wrong to be using it so extensively in check rules. You’d think you’d want the check rule to fail if the action is stopped, wouldn’t you? But maybe I’m misunderstanding something else too?

Also, does this mean that decide no and make no decision are completely synonymous?

So it just doesn’t like the first word being until for some reason? I don’t really get it… but in any case, that also works in indented form, so…

I don’t remember all the cases here. I think it only matters if you check “if rule succeeded” after the rulebook runs. Most rulebook calls in the Standard Library don’t check that.

Also, does this mean that decide no and make no decision are completely synonymous?

They behave the same. But “decide no” is tagged “in to decide if only”. So the compiler objects if you use that in a “to” phrase.

(It lets you use “decide no” in a rule; I’m not sure why.)

Looks like it insists on the first word being “repeat”.

See here for how & why this can make a difference- most commonly to subsequent conditions such as ‘if we have <verbed>’- and why ending Check rules with instead or stop the action usually (but sometimes not, in unusual cases) has the desired effect.

[a salient extract:]

Inform also provides

stop the action;
... instead;        (or, equivalently, instead...;)

(NB ‘instead…’ refers to a phrase such as ‘Before drinking the yoghurt: instead try eating the yoghurt.’ rather than an Instead rule starting with, for example, ‘Instead of eating…’)

‘stop the action’ and ‘…instead’ are both at first sight a little odd. Reading the documentation, you might easily go away with the impression that these both mean the same as rule fails, but that’s not the case. Both of these mean ‘stop the rulebook immediately, but with an outcome in keeping with the last decision a previous rule or rulebook made’. The outcome of that last decision could be any of ‘failure’, ‘success’ or ‘no outcome’. To understand this, consider that both of these phrases cause the current rule to immediately return true but, crucially, and unlike ‘rule succeeds’ and ‘rule fails’, don’t modify latest_rule_result before doing so. Consequently, the calling rulebook will also immediately terminate, with whatever result was previously stored in latest_rule_result. Often this result won’t be important, but in situations where it’s of significance whether a rulebook terminates with success, failure or no outcome this behaviour can either be helpful or lead to results the author did not anticipate.


That all seems to suggest that stop the action or instead generally shouldn’t be used in rulebooks. I suppose it’s probably fine in places like Report or even Check though, since the Standard Rules use it in Check.

I’ve just sworn a mighty oath to never write code that depends on whether an action succeeds or fails. The standard library doesn’t either. (That I recall.) Therefore, the difference doesn’t matter in action rulebooks.

Special-use rulebooks, like DTPM or activities, are different. If a rulebook has custom outcome phrases (like “it is very likely”), I always use those phrases.

1 Like

So it just doesn’t like the first word being until for some reason? I don’t really get it… but in any case, that also works in indented form, so…

This works, too.

To while until (c - condition) begin -- end loop
        (documented at ph_while):
        (- while (~~{c})  -).

When play begins:
let i be 1;
while until i is 4 begin;
  say i;
  increment i;
end while

Seems to be the case that you can’t use original initial words for things ending begin -- end [...] – the existing values seem to be special-cased in the compiler. But I haven’t tried tracking it down in the source to verify.

1 Like

If I’m not mistaken, those are defined in the Preform. I think it the <control-structure-phrase> production? (At least in 6L38.)

Actually, a lot of the syntax for which @Celtic_Minstrel is writing a reference here is actually not set in stone and is defined by the Preform, which language extension can modify to change the syntax of Inform.


I believe the Unsuccessful Attempt rulebook only runs if you give a command to an NPC and the action fails.


So in other words, some of it probably doesn’t apply if you use eg the French language extension, right?

But I bet a lot of it does still apply, even if the exact wordings are different. And the Preform isn’t the most readable quick reference. I’ve been able to glean a few things from it (like the structure of a table entry reference… which as it happens haven’t been covered here, so maybe I still have a few missing things to add), but I wouldn’t recommend it for someone asking “How do I X?”.

I’m planning to eventually convert all of the big posts I wrote in here into an HTML document which I can then post on my website, though I’m not sure how long that’ll take (days, weeks, months, even a year or two if I get distracted and wander off to something else). Whenever it’s ready for viewer consumption, I’ll probably edit it into the first post in addition to adding a link in a new post.