Inform 7 Programmer's Manual Ron Newcomb 6 November 2010 build 6F95 pscion@yahoo.com	Contents > In a Nutshell > Types, Variables, and Objects > Class And Prejudice > The Coding Imperative > Boolean Adjectives > Patterned Procedures > Functions Decide on a Value > Say Phrases > Sweet Relations > Rules of Thumb > Rulebooks: White-box Paradigm > Events are Actions > No Lights, No Camera, Just Action > Understanding Our Player, Our Parser > Time for a Scene > Arrays Have Been Tabled > Named Values Everywhere > T.E.X.T. > Precisely One Spoon-unit Of Sugar > Backstage Activities > Testing Commands > Indistinguishable Memory > Time, Turns, and Tenses > Grammar Gotchas > Paradigm Leaning > To Hack... or not... to Hack?

> Inform 7: In a Nutshell _

Inform 7 is a domain-specific language intended for authoring interactive fiction in the vein of Zork and Colossal Cave. Just as the videogame industry in general strives for better story in its products, Inform 7 strives to appeal to creators who are not programmers, and certainly do not have a collegiate background in computer programming with all of the vocabulary and metaphors that that entails. In this way, Inform 7 shares aims with BASIC: a language for the intelligent layperson.

Knowledge and processing power both have increased since the days of BASIC. No longer concerned about optimizing the compiler's speed at the expense of syntax, or ensuring scalability and security at the expense of complexity, Inform 7 incorporates design choices that seem extraordinarily unusual at first. But these choices are based on several years' worth of experience in creating interactive fiction, and since Inform 7 is not intended to be a generalized programming language, they are usually the right choices. The first two of these choices will be much on your mind while learning. The other two will eventually befriend you.

First: identifiers may have spaces. Avoiding the underscore-or-capitalize contention, in Inform 7 one could name a variable "the currently owned car". Likewise for all other constructs in the language, including functions: "mull over (idea - an object) in my (spot - a room)". Extraordinarily readable code results when constructs are named appropriately: objects and value-returning functions after noun phrases, actions and activities after participial phrases, non-value-returning functions after imperative sentences, etc. Articles a, an, and the are almost always ignored.

And second: rulebooks. Inform 7 is a rulebook-based language. A rulebook is a container for rules, but these are not the production rules from Prolog. Rather, they are unnamed imperative functions that self-invoke based on global variables, game-state, and most importantly, on whether the containing rulebook is executing. From the outside, a rulebook acts -- and is invoked -- like a function: give it a task and it will solve it. The difference is how it solves it. It may execute every applicable rule within itself, or may only execute the most specific applicable rule, your choice. The entirety of the Inform 7 system is a sequence of rulebooks in a proscribed order, with the oft-ignored background ones calling the numerous foreground rulebooks, and the foreground ones, initially empty, containing dozens of author-written rules.

Third are adjectives, especially as used by set-descriptions. An adjective is a boolean, but when combined with the class or construct to which they belong, they describe a set of instantiations. Consider this common loop construct, keywords being in bold: "repeat with antagonist running through unhappy resourceful people". The index variable will be "antagonist". Person is a class, while unhappy and resourceful are boolean values for two different properties or methods. The loop will set antagonist to each person in turn whose adjectives are set in the indicated way. Inform recognizes plural words as synonymous.

Finally are relations. Object-oriented programming is built on two asymmetric relations, is-a and has-a. Inform allows creation of binary relations between almost any two constructs in the language, including text strings. Like adjectives, relations are either-or: either the friendship relation holds between two person instantiations or it doesn't. Moreover, many constructs can check a relation, the repeat loop being the simplest: "repeat with ally running through resourceful people which are friends with the player".

Of all programming languages, Inform 7 currently most resembles natural language. Knuth's ideas of literate programming reinforce this, as evidenced by the official website, Inform7.org. Terminology useful in describing Inform 7 follow.

Domain-specific. It compiles to a virtual machine not used outside of the interactive fiction community, and rules are restricted to three parameters: the highest arity a verb of English may have.

Event-based. Events are called "actions" because the game player's commands trigger protagonist actions in the simulated, turn-based gameworld.

Object-based. Single-inheritance and polymorphism are supported, but abstraction, modularity, and namespaces are poor to absent. Inform 7 is a white-box development language by design. Scalability and security are of no concern.

Macro language. Technically, Inform 7 is a macro language for Inform 6, a weakly-typed multiple-inheritance traditional programming language. All Inform 7 code becomes Inform 6 code before Inform 6 compiles to the virtual machine's assembly. The dev team takes care to hide this complication from novice users, but inline Inform 6 code, as well as inline VM assembly, can be used to powerful effect.

Strongly typed. You'll swear you're in Pascal again, but the type system supports generic types and type variables. When all else fails, inline Inform 6 code will circumvent.

Statically allocated. Although extensions can be installed to circumvent this, and text modified at runtime skirts it, Inform's motto is "one pointer, one block". This greatly simplifies things for the target audience even if all the deep copying slows naïve code.

Pronounceable, Type-able. Perhaps voice-recognition input methods for coding will one day become the norm. Until then, you can transcribe Inform code over your friend's telephone. Additionally, the Dvorak keyboard layout optimizes the placement of letters, which Inform makes almost exclusive use of. Dvorak doesn't do much for punctuation, which traditional languages favor.

Eschews One True Construct. Some languages can say "everything is an object" or "everything is a list". Inform does not have One True Construct, though the powerful type system can bring objects, enums, rules, etc. under the same umbrella for the same effect as having a common parent class. Theoretically, the lack of a unifying construct eases learning as each construct can be learned independent of anything else, and constructs implement themselves however makes sense.

Easy To Read, Hard To Write. Empirically, Inform has proven to be easy to read but hard to write. The natural language appearance can be a will-o-wisp at times, luring the author from the path of clear grammar, as there are many phrasings that Inform "ought" to recognize, but does not. Conversely, creating uncommented code beautiful enough to be worth publishing is a viable sport. Such code can deliver its meaning even to those who aren't programmers.

Semantic Concision. Inform boasts some unique semantic conciseness on top of its extreme readability, which will hopefully be emulated in programming languages to come. For example, this is a single rule from a particular game.

Instead of a suspicious person (called the suspect) burning something which is evidence against the suspect when the number of people in the location is at least two, try the suspect going a random valid direction.

That rule breaks down like this.

"Instead" is the rulebook which owns the rule. The rulebook's name comes first, and there's precisely one of them.

"of" is one of the many ignored prepositions allowed in that place, for readability.

"a" is an article, and ignored.

"suspicious" is an adjective on class Person.

"person" is the class of the first parameter to the burning action.

"(called the suspect)" names the first parameter so we can reference it elsewhere in the rule.

"burning" is the action, the event, usually triggered by the player entering "BURN EVIDENCE". It takes two parameters, of types Person (the actor) and Thing.

"something" is synonymous with "a thing" just as "someone" is synonymous with "a person". It is class Thing.

"which" flags that we're using a relation to narrow down what Things may trigger the rule.

"is evidence against" is a many-to-many relation, thing-to-person. Contrast the number-to-number “is less than”.

"the suspect" is to what we're relating, which in this case is the first parameter.

"when" is synonymous with "if", but is used in rule preambles while "if" is used in imperative code blocks.

"the number of" is a function that will count the members in the following set-description.

"people" is, again, a name for class Person.

"in the location" is a shortcut phrase for a person-to-room relation wherein the person is always the player.

"is at least" means equal to or greater than. If the suspect is alone, our rule won't apply.

"two" can be written as 2, but Inform is unusual in that digits tend to stick out like sore thumbs.

"," the comma ends the rule preamble and begins the imperative code block. Frequently a colon must go here.

"try" will initiate a new action, and the whole sequence of rulebooks that that entails. In this case, the Going action will be called.

"the suspect" will apparently try a new tack in destroying the self-incriminating evidence he's holding, because he's not alone.

"going" takes two parameters, of types Person and Direction.

"a random" chooses one member out of a set-description. The following two words define this particular set of instantiations.

"valid" is an adjective on class Direction. It is rare the room that has exits in every direction!

"direction" is a class. The twelve standard instantiations are the eight compass points plus Up, In, Down, and Out.

"." the period ends the rule. So would a blank line.

Rule preamble constructs like someone hungry eating something edible are not action invocations -- that would be try Mario eating a mushroom -- and not action definitions -- multiple rulebooks do that -- but rather, they are very much like a regex, applied to the state of the whole work rather than to a piece of text.

Excepting the automatically included Title and Author line on the first line of the source, the Hello World program is this.

My apartment is a room. When play begins, say “Hello world.”

Every program must have at least one instantiation of class Room, which is where the virtual action takes place. (So the smallest program that will compile is: Foo is a room.) Comments belong in square brackets, and the IDE will color them green.

A final note: In this guide as well as in Inform's official documentation, "the parser" always refers to the runtime parser, our player's simplistic VERB NOUN PREPOSITION NOUN parser. It does not mean that part of the Inform 7 compiler itself.

> The Firehose _

“Information is gushing toward your brain like a firehose aimed at a teacup.”

– Scott Adams, cartoonist, on the complexities of modern life (1996)

Because Inform 7 source is not cryptic, I don't feel we need much exposition before showing source code. It is fairly easy to see what any natural language-inspired programming language is trying to accomplish simply by reading source. The difficulty with learning Inform 7, besides the whole rulebook thing, will be trying to see the grammar and types behind the pretty façade so you can actually write it. So in this chapter, The Firehose, we go on a whirlwind tour of the language reading code samples and mapping common constructs into Inform. For brevity, the very first automatically-added line of the source which has the work's title and author won't be shown in this guide.

The apartment is a room. "Behold Bob's apartment. That smell is coming from the pile of dishes in the sink."

The apartment complex's lobby is south of the apartment. "Rows of mailboxes are set into the lobby wall. Box 114 is Bob's."

Mr Bob Dobalena is a man in the apartment. "Bob sports a well-loved Transformers t-shirt with acid-washed jeans."

T-shirt, jeans, and a pair of shoes are wearable things. Bob is wearing the shoes, the T-shirt, and the jeans.

Instead of examining the player, say “You've come to visit your old college friend, Bob, and are standing in [the location].”

We have two Room instances (apartment and apartment complex's lobby), one Man instance, and three Thing instances (T-shirt, jeans, pair of shoes) with their boolean wearable property set to true. The quoted text that's just floating by itself out there becomes the initial appearance property of Thing and its subclasses, or for anything else, the description property (not to be confused with the set-description type.) There's a few relations in there as well. The mapping-south relation ties the two rooms together, and must exist for going events on the obvious direction instance. By default, the mapping-north relation is also sensibly set. The wearing relation is thrice asserted to hold between Bob and each article of clothing. Finally, the instead rule changes the behavior of the Examine event, our player's command EXAMINE ME, which typically prints “As good looking as ever.”

The source accomplishes a lot with little writing. One sentence instantiated three Things – the three pieces of clothing "are ... things" – and set a boolean property on them at the same time – all three pieces are "wearable things". The next sentence simultaneously set three relations, between Bob and each article of clothing. Object names can be abbreviated (Bob, shoes). The text that's printed in response to examining fills in the name of whichever room the player is standing in.

Next we'll show variable declarations of every major type. For now, know that is and are are perfectly synonymous and the articles a, an, and the are simply stripped from the source.

X is a number that varies. Y is a number variable.

Deadline is a time that varies.

An excuse is some text that varies.

My favorite toy is a thing that varies.

The current manager is a person that varies.

The ocean currents are a direction that varies.

The best spot is a room that varies.

The light switch's boolean is a truth state that varies.

The guru's answers are a table-name that varies.

My secret plans are a rulebook that varies.

What worked last time is a rule that varies.

My regex target is some indexed text that varies.

An abeyance is a stored action that varies.

And now some examples of supplying initial values. Usually is just ignored in this context, but when we come to creating new properties, usually defines a default value for all instantiations which can be overridden at design-time.

X is usually 2. Y is 5.

Deadline is usually 4:30 pm.

The excuse is usually "I don't know"

My favorite toy is usually the red Ferrari.

The current manager is Bob.

The light switch's boolean is usually true.

The guru's answers are usually the table of deep answers.

Learning to write rules for the various player-generated events (actions) and library events (activities) is core. The rule's preamble is much like a regex on the state of the game, while the rule body is simply imperative code. All rules belong to a rulebook, and the rulebooks a game author usually writes action rules for are, in order of execution, before, instead, check, carry out, after, report, and every turn. Some of the usual player actions are: looking, examining, taking, dropping, taking inventory, going, opening, closing, inserting it into, putting it on, removing it from, plus a few system-level (“out of world”) actions such as saving the game, restoring the game, and quitting the game. By default, an instead or after rule will cause execution to hop immediately to every turn, and a check rule is expected to do the same though by default it does not. Out of world actions only use the check, carry out, and report rules, and sometimes not even all of those. For example, once quitting the game is carried out, the software is no longer running to report anything.

It is easier to show all parts of a full rule preamble then explain each part in turn, rather than starting with simpler preambles and working one's way up. Ready your teacup.

A check rule for an actor inserting my favorite toy into the jeans when the time of day is before the deadline:

say “[The current manager] would fire [the actor] for stuffing [my favorite toy] down there!” instead.

Syntax requires the rulebook name first, excepting articles like a which are practically whitespace. Here we use check. Rulebook names can be one word or many, and tend to be or start with either an imperative verb (check, carry out, report) or a subordinating conjunction (before, after, instead). That isn't required, but it reads better because actions are always a present participle (the -ing form of a verb). Rulebooks which don't typically hinge on an action, such as every turn, are named to stand alone, or mesh well with when or while which usually follows their name.

Next can be some optional words: rule, for, of. They do nothing except improve the flow of reading. Here we used both rule and for only for the sake of an example. Instead almost always uses of, but normally, we would have begun Check an actor...

Anyway, after the rulebook name is, optionally, the performer. Here we used an actor so the rule applies to all characters, not just the player. Other options are 2) omit it entirely, so the rule only applies to the player; 3) a specific named character such as Bob, provided Bob is not the player; 4) a set-description, such as a resourceful person; or 5) someone, which means anyone except the player. The imperative rule body references what matched with the variable the actor.

Next is the action. The action's full name is inserting it into but only the part before the it goes here. So, inserting. For the before, instead, and after rulebooks our options also include doing something which means any action, or a list of actions such as looking, examining, or taking, or variations on doing something except looking, inserting, or examining. For the exception list, we can check the parameters as well, but the arity of the check must be equal: doing something except inserting or examining someone would be rejected. But doing something except inserting someone or examining someone would be fine, as they both check the same arity.

Next is the noun fed to the action, such as whatever is currently in my favorite toy. We can use a set-description here as well. The variable the noun holds what matched. Or, if the parameter is of a non-object type, one of the <type> understood variables is used, such as the topic understood, the time understood, the number understood, etc.

For actions with two parameters, a preposition follows. While the player doesn't always need to enter a preposition – consider GIVE BOB THE TOY – the programmer does. Since the action is named inserting it into, our preposition is into. (The it in the action name is a placeholder.)

The second noun follows, but we could have stuck the colon here to end the preamble. Instead, the jeans, or any variable or set-description. Something is synonymous with a thing, and is the usual catch-all. The variable the second noun, or the <type> understood, holds what matched.

But wait, there's more. The word when means if, and any valid condition can follow it. The time of day is a time variable in the library, automatically advanced one minute per understood player command. The “is before” means “is less than”.

Finally, the colon marks the end of the rule preamble – the regex-like part of the rule – and the start of the imperative code block. (One piece of syntactic sugar: a comma can be substituted for the colon if the imperative code block is a single line, and the rulebook begins with before, after, instead of, when, or every turn. Very pretty code can result.) Here our block consists of a single print statement. The trailing “instead” is another bit of syntactic sugar for appending the statement rule fails. Since the rule failed, the rulebook also fails, and execution skips ahead to the every turn phase of the turn. Since that skips the carry out rules, the action does nothing except print our denial message in the situation our preamble describes.

All rules in the language follow that pattern. As for rulebooks, they are simpler. Every rule ends in one of the statements rule fails, rule succeeds, or make no decision. If we don't specifically use one of those three statements at the end of the rule, the rulebook's default is automatically appended. Rule fails and rule succeeds both end the rulebook as well – whatever task was given to the rulebook has completed. Make no decision tells the rulebook to try the next applicable rule, and is the default for any rulebook that runs all its rules. Make no decision is the default for when play begins, before, check, carry out, report, every turn, and almost every other standard rulebook. Of course, instead defaults to rule fails. After and each activity's for default to rule succeeds.

So, some examples with actions. Square brackets outside a text string denote comments.

Report going when the current manager is in the location: say “See ya later, [the current manager].” instead.

Carry out examining the cell phone for the first time: [ once, twice, and for the Nth time can end a preamble ]

now the player worries about Jesse; [ worries about would be a relation ]

now the cell phone is fingerprinty. [ fingerprinty a boolean property ]

Some examples with other, background events.

When play begins, say “Once upon a time...”

After reading a command when the player's command includes “quickly/quietly/slowly”, say “I cannot understand adverbs in commands.” instead. [ slashes mean or ]

Before printing the name of Bob, say “Mr. ”

Within a rulebook, rules are sorted according to the specificness of the preamble. So, instead of examining someone suspicious will always be tried before instead of examining someone no matter their source code order. All the various restrictions must still be satisfied of course. This just determines what rules are tried first, and if multiple rules share the same specificness, they are considered in source code order. Although this setup sounds frighteningly like building atop shifting sands, empirically it has worked better than anticipated. This is likely because rules belong to rulebooks, and only one rulebook is operating at any one time, in much the same way that only one function operates at one time: the caller is “on hold”. And unlike Prolog's sea of rules, one rulebook is small enough to remember at once. But when in doubt, there is the Index.

Found in the IDE, the Index is the automatically-generated author's documentation. The Index button is labeled vertically along the right edges of both panes, and will be empty until the first successful compilation. The various tabs of the Index list all the constructs in the author's work as of the latest compile. It's possible to learn a lot just by reading it. The Actions tab lists all the actions the game knows, both built-in and author-written, and lists the player words that trigger each. Clicking the magnifying glass icon next to an action name will show a detail page listing all the rules that can apply to it. The Contents tab lists all variables and tables. The Kinds tab not only contains the object hierarchy including all instantiations, but also all other types and under what generic types they fall. The Phrasebook tab holds procedures, functions, and relations. The Rules tab holds only rules that do not apply to actions or scenes. The Scenes tab holds detail on scenes and scheduled events, while the World tab holds the room map.

Now that we've covered rules and the index that would be new to many programmers, we can speed up our tour. The only thing left to start creating games is how to give the player synonyms for objects and actions. Set-descriptions can be within the square brackets here, but generally it's better to allow much at this parsing stage, and use check rules to print better denial messages for attempts to wear doorknobs or eat Ferraris.

Understand “squint at [something]” as examining.

Understand “dash [direction]” as going.

Understand “stick [something carried by the player] down/into [something]” as inserting it into.

Understand “Robert” or “Rob” as Bob.

Understand “dude” as a man. [ narrows down the referent to objects of class Man ]

Conditions can be attached.

Understand “bastard” or “rat bastard” as Bob when the time of day is before the deadline.

Understand “fingerprinty” as a thing when the item described is fingerprinty.

The item described is the self or this variable used in other languages. For properties, a shortcut obeys the current state of the property.

Understand the fingerprinty property as describing a thing.

Understand “smudged” as fingerprinty.

Functions are called to-decide phrases. Because their return values cannot be thrown away, they will always appear within a larger statement, and so, are named after noun phrases. Below, bold type shows keywords in the definition before the colon. The colon is where the function body starts. Decide on is the return statement. The return value comes just before is. Slashes denote a choice of word (pick exactly one), or when combined with the – double-dash, the word is optional. Python indentation, or begin and end if/repeat/while, denote blocks, but begin-end and Python indentation cannot be mixed with each other in the same function.

To decide which number is (x – a number) smooshed with (y – a number): decide on x multiplied by y.

To decide what object is my toy: if the Ferarri is in the location, decide on the Ferarri; otherwise decide on nothing.

To decide which person is who wears/wear the pants around/in the/-- house/home of (p – an unhappy person):

if p is: [Python style is required to use the switch statement]

– Bob: decide on Edith;

– Jose: decide on Maria;

– otherwise: decide on the mother of p.

Boolean (truth state) functions use to decide if and are named after clauses. Yes and no are the phrase versions of values true and false, while whether or not typecasts between.

To decide if (p – a person) will be done by (deadline – a time):

if p is Bob, yes; otherwise decide on whether or not the time of day plus five hours is before the deadline.

Adjectives can be used as part of set-descriptions, which the above cannot. The pronoun it refers to the object in question here, but an explicit called parenthetical can name it. One-liners can use if rather than the colon. The antonym is defined by rather than but is optional.

Definition: a person is overloaded rather than good if the number of workorders expected of it is at least five.

Definition: a person (called the workerbee) is efficient rather than slow:

repeat with item running through every workorder expected of the workerbee:

if the completion time of the item is greater than one hour, decide no;

decide yes.

On the downside, parameters cannot sit right next to one another. A word must come between. But, the type of a parameter isn't just a type or class, but anything from a specific value to a full-on set-description. As with rules, Inform chooses the most specific applicable phrase, and in the case of a phrase calling itself, prefers not to recurse if possible. (This is mainly a safety feature for the lay target audience.) So for the following procedures – functions which return no value, and sometimes called to-phrases in Inform because to is the only keyword they have in common – if Jenny doesn't love the player, then invoking her name causes execution to ping-pong between both applicable phrases.

To tell (lover – a person) I love him/her/them recursively:

say “I love you, [lover].”;

tell the lover I love them recursively.

To tell (lover – a person which does not love the player) I love him/her/them recursively:

say “I secretly love you, [lover].”;

tell the lover I love them recursively.

To tell (lover – Bob) I love him/her/them recursively: say “Er, how's [abrupt subject change] coming along?”

Say-phrases are called from within text strings. If constructions are standard, but cannot nest: “[if Jenny loves Bob]What? Why?[otherwise if Bob loves Jenny]Welcome to the club.[otherwise]Won't she give me her number?[end if]”

To say abrupt subject change:

if the current weather conditions are not mostly sunny:

say “the weather”;

otherwise if Edith is not in the location:

say “you and Edith”;

otherwise:

say “the Chicago Cubs”.

To say looks like it's (w – a weather condition): if w is nasty, say “blowing up a storm”; otherwise say w.

A blank line, or a period substituted for a semicolon, ends a phrase.

Named values (known as enums in C) can do most anything objects can do, and needn't be all defined at once. A weather condition is a kind of value. Some weather conditions are rainy, partly cloudy, mostly sunny, about to snow, and nasty. A weather condition is a tornado warning. A metal is a kind of value. The metals are copper, tin, iron, aluminum, platinum, nickel, gold, and silver. One standard kind of value receives special attention: scenes. With a during preamble phrase and its own SCENES testing command, scenes are a powerful organizing principal in an interactive fiction.

The denouncement is a scene. The denouncement begins when the climax ends.

Instead of taking something during the denouncement, say “But the life of a kleptomaniac seems so empty now.”

Boolean properties. A person can be happy or unhappy. A person can be resourceful. A person is usually not resourceful. A weather condition can be later in the evening. A weather condition is usually not later in the evening.

Valued properties. A person has a person called its mother. A weather condition has a time called the predicted duration. The predicted duration of a weather condition is usually five hours. Bob's mother is Agnes.

Subclassing. A boy is a kind of man. A girl is a kind of woman. Statically-allocated means no constructors or destructors. Inform can insert new classes between existing classes. A conveyance is a kind of container. A vehicle is a kind of conveyance. This does not contradict the standard a vehicle is a kind of container.

Timed events are rules that self-invoke at a given time or in a given number of turns. They fire only once, but named ones can re-schedule themselves.

At 6:30 am: say “Your alarm clock screams you awake.”

At the time when an email arrives: say “You've got mail.”; an email arrives in seven turns from now.

At the time when the alarm clock screams:

say “Your alarm clock screams you awake.”;

the alarm clock screams at 6:30 am.

Activities are multi-rulebook events not generated by the player. They exist merely so the library (or authored extensions) may provide hooks for important events. The three phases of an activity are before, for, and after. Printing the name, supplying a missing noun, printing a parser error, and reading a command are the most useful. Other standard rulebooks which are not full-on activities are does the player mean, persuasion, and unsuccessful attempt by.

After printing the name of Bob: say “ Jr.”

After reading a command when the player's command includes “please/thanks”, cut the matched text.

After reading a command when the player's command matches “take nap”, replace the matched text with “sleep”.

For printing a parser error when the latest parser error is I beg your pardon: say “Please type something in.”

Does the player mean taking the train: it is very unlikely. [ “getting on” or “entering” the train, perhaps ]

Arrays currently have little support since who would want to read about a hundred perfectly identical things? Still, it's possible to instantiate numerous unnamed objects, but only if we specifically create a subclass for it. A coin is a kind of thing. Seven coins are in the sofa. A light is a kind of thing. There are four lights. While the player can TAKE THREE COINS, the programmer resorts to set-descriptions and a random, such as a random off-stage coin. (A random is a decide phrase, not an adjective. The a is required. Off-stage is when location is nothing.) Tables are 2D arrays, mostly, and can instantiate a slew of objects or named values at once. Tabs are required between columns. A – double-dash is a blank entry.

A workorder is a kind of value. Some workorders are defined by the table of tasks.

Table of tasks

workorder	employee

send invoices	Bob

check addresses	–

restock	Bob

And we close off the firehose with relations. Object-oriented programming is built on two object-to-object relations, is-a and has-a. Single inheritance is one-to-various, while multiple-inheritance is various-to-various. Object properties in general are each a various-to-one relation. Indeed, that's frequently how Inform implements them: the called parenthetical allows the noun of noun syntax of properties as an alternative to the noun verb noun syntax of relations. But called is restricted to the singular, so the reversed word may be needed. Finally, Inform already knows the singular (-s), plural (root), past (-ed), past participle (-en), and present participle (-ing) forms of be, so the large parenthetical is omitted for such.

Single inheritance relates one thing (called the parent) to various things.

The verb to be the superclass of implies the single inheritance relation.

The verb to inherit from (he inherits from, they inherit from, he inherited from, it is inherited, he is inheriting from) implies the reversed single inheritance relation.

now dog inherits from animal; [ These are synonymous, but note we're not using Inform's actual class hierarchy. ]

now the parent of dog is animal; [ The real class hierarchy is immutable at runtime. ]

now animal is the superclass of dog;

Assignment relates various workorders to one person (called the employee).

The verb to be expected of implies the assignment relation.

> Class And Prejudice _

Here's the built-in class hierarchy, a total of sixteen classes. (Also, where other languages say "class", Inform says "kind".) Inform purposely keeps its library lean.

object

direction

room

region

thing

door

container

vehicle

player's holdall

supporter

backdrop

device

person

man

woman

animal

A quick rundown: Room is a discrete location, a place; Region is a container for Rooms. The class Container means an in-game prop, such as a backpack or hamster cage. A Supporter is a chair, table, mantel, or other horizontal surface Bob can place things on top of. The player's holdall is usually a singleton, as it's a container without load limits. A instance of Door can explicitly connect Rooms, and can be open & closed if not also locked & unlocked. Direction does NOT connect rooms -- relations do that -- but is used in code to reference the same. Backdrop always has the boolean property scenery set, and is used for things like the sun in the sky, the faint but ever-present sound of a nearby creek, and other non-portable objects that need to remain in the parser's scope while the protagonist travels across several Rooms. Device is something that can be switched on/off. Animal is treated as a kind of person, just as pets are.

The positioning of Animal is our first hint that we're stepping out of a scientific worldview, and into a humanistic one. Likewise, the purpose of the language as a whole is to produce works of art, not software tools.

Making a subclass is straightforward:

An archway is a kind of door.

An archway has a number called the horizontal clearance. It is usually 6.

An archway is always open.

An archway can be magic or mundane. An archway is usually not magic.

This subclasses archway from door. It gives it a new numeric property call the horizontal clearance with an initial value that can be overridden by a particular instance. Then it permanently sets the pre-existing open/closed property to open so attempts to later code a closed archway will result in a compiler error. Finally, it gives it a new anonymous boolean property with named values magic and mundane (as opposed to a property called "magic" with values "true" and "false"). It initializes this to mundane. We could have just said an archway can be magic and it would still work, but naming the antonym usually improves readability.

One instance of person is always provided for us: yourself. The player is a person variable initialized to yourself unless defined otherwise. (Only the player refers to the avatar as ME.) One instance of Object (the root-level class) is always provided: nothing, the nil pointer. Occasionally synonyms nowhere, nobody, no-one, and no one may be used, but it's usually a special-case syntax.

The player is Bob. [the "yourself" object still exists, though unused]

[...]; change the player to Bob; [imperatively, at runtime]

> The Coding Imperative _

Here are examples of all the basic imperatives. Read the print statements within.

let Z be 5; [local variable declaration; type inferred]

now X is 5; [assignment]

if X > Y, say "A comma is synonymous for 'then'.";

otherwise say "'Otherwise' (or 'else') must be a one-liner if the 'if' was a one-liner. No punctuation follows the word.";

if X > Y begin;

say "'Begin' requires a semicolon of its own.";

otherwise;

say "As does the matching 'otherwise' and 'end'.";

end if;

if X > Y:

say "Python-esque style is OK as long as we don't mix the two styles in the same function.";

otherwise:

say "Posting code to internet forums usually corrupts the tabs, but tables require tabs anyway.";

if X is greater than Y begin;

say "This is a else-if chain. Also, notice that relational operators can be spelled out.";

otherwise if X is Y;

say "Only a semicolon is found for the trailing conditionals.";

otherwise;

say "The final otherwise is the same as usual.";

end if;

if X is greater than Y:

say "This is a else-if chain in Python style.";

otherwise if X = Y:

say "The punctuation here is more regular: always a colon, no matter what.";

otherwise:

say "The = is rarely seen by itself, in practice; 'is' is easier to type.";

unless X <= Y, say "'Unless' means 'if not'. Also, inequalities are written >= or <=, never => or =<.";

if X is:

-- 1: say "A switch statement masquerades as an if statement. 'Unless' cannot be used.";

-- 2: say "Python style only.";

-- otherwise: say "There is no fall-through between cases, and no goto to restore it.";

if my favorite toy is:

-- the red Ferrari:

say "Numbers and objects both can be used in switches.";

-- the jeans:

say "Also note the further indentation of the cases, and their subsequent lines.";

repeat with X running from 1 to 10:

say "'Repeat' is the usual loop construct. It has [X] forms. This enumerated one isn't used much.";

repeat with clothing running through every wearable thing:

say "The 'description' type describes a set of objects.";

if the clothing is the pair of shoes, say "Also, 'every', 'each', or 'all' aren't required here but may read better.";

repeat with target running through all limbs:

if the target is the head, say "We can repeat through named values, scenes, action names, etc. just as easily.";

repeat with programmer running through the men who are in a lighted room (called the mainframe's area):

say "[The programmer] in [the mainframe's area] says we can do some pretty complex stuff with 'descriptions'.";

next; [ 'next' starts the loop over at the next iteration. C calls this 'continue' ]

break; [ 'break' kills the loop immediately ]

repeat through the table of designs:

say "Tables are 2D arrays. We'll look at them in detail in their own section.";

while X is at least Y begin;

say "While loops are rarely seen in practice.";

end while;

Semicolons divide statements as usual, but the last semicolon should instead be a period. Alternately, the last statement should be followed by a blank line. This is how the end of a function is signified.

Inform calls the above imperatives, and other things like them, phrases. Functions are also called phrases, because they are invoked similarly. But rules are different; they invoke themselves based on game events and other worldsim situations. Here's some quick examples just so we'll have somewhere to try out our imperative code.

When play begins: say "Hello world!".

Every turn: say "La-dee-da."

Instead of taking yourself, say "You pull yourself up by your bootstraps and read on."

Remember to instantiate a room.

> Boolean Adjectives _

Adjectives, and the set-description type that invokes them, are Inform's big win over the COBOL and HyperTalk families of natural language programming languages. Typically used for objects, a description uses combinations of adjectives and/or relations with a class to define a set of instantiations. This is responsible for a great deal of Inform's conciseness over traditional programming languages. First we'll look at how to define the adjectives.

There are a few ways to define a boolean adjective. The first creates an anonymous boolean property with named values.

A thing can be spiffy.

A person can be grumpy or happy.

now the iPod is not spiffy;

if Mary is happy, now Bob is grumpy;

Inform of course understands not spiffy but it also understands not grumpy as synonymous with happy and vice-versa. Also, since person is subclassed from thing, a person can also be spiffy. Frequently in OOPLs, new properties and methods cannot be added to a pre-existing class because doing so would break pre-existing code that uses it. Subclassing is required to add such embellishments. But since Inform isn't designed for reusable code or team coding, it allows directly modifying classes, and those changes propagate down the hierarchy regardless whether they are built-in or not. The allowed modifications are additive only, however. (Though sectional replacement of source code alleviates even that.)

The second way to define an adjective works like adding a boolean-returning method to a class. It also has a one-liner version using "if" instead of a second colon:

Definition: a person is kinda dull: [...]; decide no.

Definition: a person is unlikable if it is kinda dull or it is grumpy.

Definition: a person (called the academic) is laconic rather than chatty if the academic is [...].

The pronoun it refers to the object on which the method is called, where traditional languages use "self" or "this" or some such. This can be customized with the called parenthetical. An antonym may be defined with the rather than phrase. Definition: adjectives aren't restricted to objects. Named values are also common here.

(The third way, using a plain to decide if boolean function, loses the flexibility of appearing in set-descriptions. But, being a function, it can take any number of arguments, and may use the powerful parameter-matching logic of same. We will see them soon.)

The adjectives are checked the same way regardless whether they are data or calculated, so changing an adjective from a variable implementation to a calculated implementation (or vice-versa) only requires adding or removing any lines that explicitly set the adjective's value. Client code that merely checks the value needn't change.

repeat with associate running through every chatty not grumpy spiffy person:

say "Hi [associate]."

> Patterned Procedures _

A procedure's “name” in Inform 7 is not an exact match of a single identifier, but a simple textual pattern. The word to starts the definition, and parenthesis enclose the local variable name, a hyphen, and the type. A colon ends the “name” and the imperative code block begins.

To plainly greet (friend - a person):

say "Hi [friend]."

The above is invoked readably.

plainly greet Dr. Muller;

The / forward slash can be used to allow synonyms for a word by acting as a high-precedence disjunction: choose exactly one. Its effect ends at the first space. The -- double-dash in a disjunction means the word is optional: choose at most one.

To ponder/mull over/-- (good point - a thing) for (awhile - a time) as (ponderer - a person):

say "[Ponderer] sits back for about [awhile]. 'Hm, [good point] is a very good point.'"

The following invocations are all equivalent.

ponder the best idea yet for 7 minutes as Dr. Muller;

ponder over the best idea yet for 7 minutes as Dr. Muller;

mull best idea yet for 7 minutes as Muller;

mull over the best idea yet for 7 minutes as Dr. Muller;

A parameter can immediately follow the to that begins the definition, but parameters cannot sit immediately side-by-side.

To (ponderer - a person) ponders (good point - a thing): [ok]

To ponder for (awhile - a time) (good point - a thing): [error!]

The types of the parameters needn't be a single type, or even a type at all. Set-descriptions and particular values both may narrow the scope of the input. Like actual rules, this is a handy feature for special cases.

To plainly greet (foo - people which are friends with the player):

To plainly greet (foo - a resourceful person):

To plainly greet (foo - nothing): say “Run-time error: called 'plainly greet' with nothing.”

While set-descriptions narrow the accepted range of input, generic types allow one phrase to cover many different types. The type of a parameter itself can be captured and used elsewhere in the definition and/or code block via the phrase value of kind K and similar variables L, M, etc. Sayable value, word value, pointer value, arithmetic value, enumerated value, and the most generic of them all, value, are the known generic types. They can be used with or without of kind K.

To debug-print the differences between (construct one – a sayable value of kind K) and (construct two – K):

Let creates a local variable. Let is also how we create flexibly-sized types like list and indexed text, since they cannot be statically allocated and the language does not allow dynamic allocation.

let X be 5;

let the typical exclamation be "That's cool!";

let the articles of clothing be the list of things worn by Bob;

let M be { the red Ferrari, the pair of shoes };

let the modifiable exclamation be indexed text; [ These work... ]

let the modifiable exclamation be "That's cool!"; [ ...as a pair. ]

Stop is the plain-jane return statement. It isn't used much, partly because of some other synonyms for return, and partly as fallout from the rules-based structure of the language.

A final natural-language feature cloaks a bitfield as a series of comma-separated sub-phrases.

To go hiking, into the woods or up the mountain:

if into the woods then say "Watch out for badgers.";

if up the mountain then say "Better take your compass.";

say "You go hiking."

Clever naming not only affords client code that is easy to read, but also creates library invocations that are easy to make a half-remembered guess at. The latter is, in practice, a wonderful time-saver. When we define functions, we should take client code readability into account. For example, we needn't add the articles in front of a parameter, because the parameter itself will eat it.

To ponder the/an/a/-- (nefarious plans - a rulebook): [ unnecessary ]

To ponder (nefarious plans - a rulebook): [ better ]

But we should explicitly add the articles if it occurs elsewhere, such as this example that pretends to understand an adjective in some cases.

To ponder the/an/a/-- foiled/new/-- (nefarious plans - a rulebook): [ necessary ]

To phrases tend not to be used too much, for the similar reason that methods in a OO language tend to reduce global function use. Instead, Inform 7 has rules, grouped into rulebooks, which we'll get to shortly. To-phrases do have a nicer invocation syntax and essentially unlimited arity to recommend them over rules, but they lack some of the flexibility of rulebooks, as we will soon see.

> Functions Decide on a Value _

Because strong-typing requires returned values to be used, functions will always be used in a larger statement. Hence their names tend to be noun phrases rather than sentences.

To decide which room is my favorite place: [...]; decide on My Bedroom.

To decide what person is the brother to/of (sibling - a person): [...]; decide sibling.

To decide which object is my fabulous doodad: decide on a random thing.

ponder the best idea in my favorite place;

if the brother to the noun is not the noun, say "[The noun] has a brother, [the brother of the noun].";

if my fabulous doodad is nothing, say "I'm fresh out of fabulous.";

To decide which, or synonymously, to decide what, begin the definition. The return value follows, and then is. The function's name is only that part between is and the colon. The return statement is decide on. Due to strong-typing and nothing being pronounced an instantiation of class object, we cannot decide on nothing except when the function's return value is type object.

Boolean functions must use the slightly different whether/if variation, and the name lies between the whether or if and the colon. Since they are invoked from if statements and rule headers, their names are usually clauses sans subordinating conjunction.

To decide whether (pants - a thing) is/are on fire:

decide on whether or not a random chance of 1 in 2 succeeds.

if the brother of the noun is on fire, say "That's gonna leave a mark."

The phrase whether or not typecasts an if-condition (such as if "a random chance of M in N succeeds") to a truth state (boolean), which can then be returned.

> Say Phrases _

It is so common to slightly vary some prose for a given situation that Inform specifically provides for procedures called from within a say statement's prose. Say-phrases are in a box separate from to-phrase procedures and to-decide functions, but otherwise work identically. They are invoked by square brackets within a text string.

Gendered pronouns are a common case, and most are built-in.

To say He-She for (P - a person):

if P is plural:

say "They";

otherwise:

if P is female, say "She";

otherwise say "He";

To say (P - a person) mulls/ponders --/over (idea - a thing):

[...]; say "[He-She for Chris] glances at you[Chris ponders tar-and-feathering].";

Putting a bare object or variable name within the square brackets prints the entity's name or variable's value, respectively. This works for nearly every type in the language, though can usually be overridden like so.

To say (code - a rule): abide by the code.

That would execute the rule or rulebook from within prose, rather than printing something.

say "Chris seems to make a decision.[the formulate plans rules] But you don't know what.";

Inform ships with a number of basic imperatives for say phrases. The docs have the full list, and the Extensions chapter has information on creating new multi-part To Say constructions.

say "He put on [if the jeans are stained]yesterday's[otherwise]his[end if] jeans.";

say "The weather was [one of]rainy[or]sunny[or]windy[at random].";

> Types of Types _

We know defining a class that implements a list of numbers is tedious, but not as tedious as doing it again for strings, objects, and any other type the language supports. Most languages nowadays provide for this problem, such as the templates of C++. Inform too offers generic types. Arithmetic value allows numbers and units. Pointer value includes indexed text, stored actions, and other variable-sized chunks of memory. Word value covers all non-pointer values, including objects. Sayable value is any type allowed in a print statement, which is almost anything. Enumerated value is named values, which includes scenes. And finally, value is all of them: just about anything that can be passed as a parameter. The Kinds Index in the IDE shows what types belong under which umbrellas. We can use them to define a phrase like this.

To place angle brackets around (foobar - a sayable value): say "<<[foobar]>>".

To print the elements of (stuff - a list of sayable values): say "The list contains [stuff]."

Kind variables tie two or more parameters to the same type. This is particularly useful when one parameter is an aggregate type, and the other is the type being put into, brought out of, or compared to an element of, that aggregate. Kind variables are always a single capitalized letter, and traditionally use K and L.

To decide which K is the initial contents of (stuff - a list of arithmetic values of kind K): ...

To we will ask if (col - a K valued table column) is (data - a word value of kind K): ....

The words value of kind must precede exactly one of the Ks. That parameter will be the one that declares what K holds, so the other parameter's input will be expected to match. For example, the following line means the second parameter decides what K is, so the compiler will search for a table column of that type.

To we will ask if (col - a K valued table column) is (data – a value of kind K): ....

While this means the first parameter's type sets K, and the second will be interpreted as the type in question.

To we will ask if (col - a value of kind K valued table column) is (data - K): ....

It makes a difference. A very few types are implicitly casted between each other, such as text and indexed text, and whether K is text or indexed text will likely matter in the body of the function. Other times, the compiler may have a choice of constructs with the same name but different types. Or, the same words of source text may have radically different interpretations depending on what type the compiler expects it to yield. And one final note: the return value cannot set the kind variable. It may use one, as the above example with initial contents, but cannot declare it.

The parameter name of kind of value is an interesting case because, rather than accepting a particular instantiation of a restricting type, it asks for the source code's name of a type, such as object or room or weather condition. K is set to the type, and then K is used in the body of the function in the same places and same ways as the word itself would have appeared. The feature is also very useful in typecasting, via Inform 6.

To rattle off all the (name of kind of value K):

repeat with x running through K:

say "[x], "

To decide which K is the (mystery - a value) as a (name of kind of value K): (- {mystery} -).

We can then write:

rattle off all the scenes;

rattle off all the tattoos;

rattle off all the rooms;

let whatsit be foobar as a tattoo;

let whosit be foobar as a person;

let howsit be foobar as a rule;

let whensit be foobar as a scene;

And so on. Most OO languages tend to treat everything as an instantiation of a class. In Inform, many constructs are not objects, but the type system allows us to use the same function on everything just the same. (Note that parameter types condition and action are still a special case. They can only be used in a phrase when the body is written in Inform 6. The later chapter on Inform 6 covers them.)

To-phrases and relations can be passed as parameters, but still strongly-typed. Examples of the type of a phrase would be:

a phrase (length, length) -> nothing

a phrase nothing -> number

a phrase (number, number) -> number

And for relations:

a one-to-various relation of people to cars [ asymmetric is always assumed ]

a symmetric one-to-one relation of people ["to people" is assumed]

an equivalence relation of people

One thing Inform cannot do is an indefinite number of parameters, such as the printf function in the C programming language. And because Inform is strongly typed, there must be a slew of phrases that apply a passed-in phrase to 1, 2, or 3 inputs, and returning a value or not. For phrases that return a value, use one of (phrase) applied, or (phrase) applied to (value), or (phrase) applied to (value1) and (value2), up to three parameters, just like rules. For phrases that do not return a value, apply (phrase), or apply (phrase) to (value1), etc.

In lieu of indefinite parameter counts, Inform can pass around lists of whatever, and has the higher-order functions. Map, as (phrase) applied to (list), takes a list, runs the passed-in phrase on each element in turn, and returns the new list. Filter, as filter to (description) of (list), returns a smaller list than the one passed in, having removed what elements don't fit the set-description. And reduce, as (phrase) reduction of (list), which returns a single value. However, these only emulate the syntax of functional programming. Without lazy evaluation or anonymous functions, this style of programming leaves much to be desired, and cannot at all deal with lists of infinite size in the common generator-consumer pattern.

> Sweet Relations _

In lieu of numerical relationships, qualitative either/or relationships frequent interactive fiction. Relations disguise 2D boolean arrays behind some of the best syntactic sugar in the language – namely, behind verbs. Relations are written with the infix form of English verbs. Asymmetric (X to Y) and symmetric (X to [one] another or X to each other) relations are possible, with one-to-one, one-to-various, various-to-one, and various-to-various flavors, plus the equivalence relation ([various] X to each other in groups). The called parenthetical, only on a singular side, allows property syntax as well.

Marriage relates one person to another (called the spouse). [ one-to-one symmetric ]

The verb to be married to implies the marriage relation.

Bob is married to Jane.

When play begins, if Jane is married to someone, say “Jane's husband is [the spouse of Jane].” [ prints Bob ]

Symmetric relations are always of type X to type X. So marriage cannot be “one man to one woman” nor can friends be anything but person to person.

Friendship relates people to each other. [various-to-various, symmetric]

The verb to be friends with implies the friendship relation.

if the brother of the noun is married to the second noun, now the noun is friends with the second noun;

repeat with pal running through every person who is friends with the brother of the noun:

When we define a verb like to be X, Inform can automatically conjugate it. But for to X we supply the other five forms in parenthesis. They are, in order, the singular (-s), plural (root), past (-ed), past participle (-en), and present participle (-ing). At least either the singular or plural must be supplied. He/she/it may be used interchangeably, but they has no synonym.

Like-minded relates various people to each other in groups. [ an equivalence relation ]

The verb to draw (he draws, they draw, it drew, he is drawn, she is drawing) implies the like-minded relation.

Asymmetric relations may find a reversed synonym useful in set-descriptions.

Teenage love relates various people to various people. [ tragically, an asymmetric relation ]

The verb to be in love with implies the teenage love relation.

The verb to be lusted after implies the reversed teenage love relation.

Additionally, we can define the verb as to be able to X, which means the relation is used like can X. The parenthetical has only the past participle (-en) form, and is required.

Memorability relates various people to various things.

The verb to be able to remember (he is remembered) implies the memorability relation.

Bob is a man. The time he spent in jail is a thing.

Bob can remember the time he spent in jail.

The to be able to... relations (only) can be stated in the passive voice as well. So Bob can remember jailtime may be stated jailtime can be remembered by Bob. Effectively, the reversed version is provided automatically. The phrasebook part of the Index shows the available wordings.

Though only an asymmetric various-to-various relation actually needs a whole 2D array, the other kinds of relations are some sort of subset of one. Any relation with a singular is frequently implemented as a property, as are equivalence relations. Relations on very large (text) or infinite (numbers) domains will use sparse array implementations, such as properties whose type is a list of some sort.

Much like boolean adjectives, relations can be implemented as calculation rather than storage.

Siblinghood relates a person (called X) to a person (called Y) when X is the brother of Y or X is the sister of Y.

The verb to be a sibling of implies the siblinghood relation.

The syntax to check whether a relation holds between two things is the same regardless the implementation, so swapping between them only requires fixing up wherever the relation was explicitly set between things. It is worth nothing that the relativistic relations of math are implemented this way ("The verb to be greater than implies the...") as well as almost all spatial relations (under, on, in, northeast of, etc.)

Relations can be put into lists, or passed into functions.

To decide whether (relationship – a symmetric various-to-various relation of people to people) is a good reason for trusting (P – a person): decide on whether or not relationship relates P to the player.

Asymmetric is assumed, so only symmetric is defined. The one-to-various and flavors obviously cannot be used with equivalence. Finally, empty describes the default condition. The phrase relates...to... can be used in if and now statements. In an if, types and negation can be used: if Bob does not relate to someone by the love relation.

Note that the above phrases and the following phrases are indeed phrases, not a set-description (which the following resemble) nor a three-way relation (which the former resemble, assuming Inform could even do multi-way relations).

Various functions provide lookup. These are especially handy when dealing with domains as large as text or numbers. Unfortunately, the compiler cannot check them at compile-time. Runtime type errors result if arguments are swapped.

a Y which X relates to by R [ for various-to-one or one-to-one ]

a X which relates to Y by R [ for one-to-various or one-to-one ]

list of Ys which X relates to by R [ for various and equivalence ]

list of Xs which relate to Y by R [ for various and equivalence ]

[ Warning: the above two are new and very buggy. ]

list of Xs which R relates [ for finding everything on the left hand side of relation R ]

list of Ys which R relates to [ for finding everything on the right hand side of relation R ]

Pathfinding uses relations.

let X be the number of steps via the acts with relation from Kevin Bacon to Jodie Foster;

let S be the next step via the acts with relation from Christopher Walken to Kevin Bacon;

And of course, relations are integral to set-descriptions. Since set-descriptions can be parameter types in functions, procedures, rules, and understand tokens, and be a domain description in repeat loops and now every assignment statements, as well as passed-in and used in their own right to phrases like filter, they are the secret sauce which COBOL and Applescript lack.

repeat with countrymen running through every resourceful not antagonistic person who trusts the player who is friends with a person (called the shill) who owns a thing (called riches):

say "Hi [countrymen]. [Shill] said you'd lend me your [riches]."

In the above description, each subordinate phrase applies to the main noun -- person, in this case -- not to the nouns listed in other subordinate phrases -- such as player, thing, or the second person. (Asking "who is friends with a person" is a way of asking who has friends.) We cannot insert commas or conjunctions ("and").

> Rules of Thumb _

Because interactive fictions are single-author artworks rather than team-designed workhorses, novelty and ease of modification trump safety and scalability. As a result, a partially rule-based paradigm was chosen. Where the procedural paradigm triggers imperative code blocks by invoking that code's given name (the name-plus-code construction is called a procedure or function), the rule-based paradigm triggers imperative code blocks by attaching situational information to it. The situational condition is called the preamble, and the preamble-plus-code construction is called a rule.

In other words, a rule encapsulates when its code executes. For a procedure, the information about when it executes is spread diffusely over the source code: wherever its name appears. Rules typically don't need names because rules already know when they execute. They needn't be told so by other code.

A carry out rule for someone playful (called the prankster) which is friends with the player inserting a favorite something into something worn when the time of day is before the deadline during the opening scene (this is the my fairly long rule):

now the prankster annoys the player.

We have already dissected two rules so far in this guide, one in the nutshell chapter and one in the firehose chapter, so let's move a little faster through this one. Carry out would be the rulebook name, except that check, carry out, and report are actually each multiple rulebooks, one set for each action. So the rulebook in use here might be named carry out inserting it into. A and rule for are just syntactic sugar, and ignored by the compiler. The first parameter, the performer, must match the set-description someone playful which is friends with the player, and if so, the variable prankster captures. The noun will hold what matched a favorite thing while the second noun will hold what matched something worn. The when condition must be satisfied and a scene, the opening scene, must be currently in progress. We also name this rule my fairly long rule, so further work may be done on this rule, such as temporarily ignoring it at run-time via an extension, or placing constraints about its placement in its rulebook vis-a-vis the other rules in it. The colon begins the imperative code block, and the period ends the imperative code block. In short, the rule defines in what situation that the player will be annoyed by someone.

In Prolog the rule would be written the other way around: The prankster annoys the player if-and-only-if the action is the inserting it into action, and the actor is a person, and the actor is playful, and the actor is friends with the player, and the noun is a thing, and the noun is a favorite, and... and so on, in its verbose, obtuse, punctuation-filled way. Neither COBOL nor Applescript are even that sophisticated. Indeed, one of the better analogs for Inform's rules are the rules of Perl 6, even though Perl's rules are intended primarily for text strings and grammar.

A few short examples of rule preambles follow. The latter three have the imperative block included as well.

A persuasion rule:

Persuasion: [ an identical preamble to the above ]

Every turn:

Every turn during the collapsing bridge scene:

Report someone burning something:

Instead of burning something held (this is the safety first rule): say "No, you might burn yourself!"

Carry out an actor helping someone: now the noun is friends with the actor.

Report tattooing: say "You go to work on [the second noun]'s [the limb understood]."

Unlike Prolog's never-ending sea of rules, Inform groups its rules into rulebooks. When a rulebook is invoked, only that rulebook's rules are considered. The only required part of a rule's header is the rulebook to which it belongs, though additional clauses are frequently attached using during (for scenes), when / while (for if conditions), and a sole action description (such as someone cutting something) immediately following the rulebook name. This allows rulebooks to encapsulate smart, mutable behavior, similar to objects, but behavior here is paramount, not a data instantiation. It could be said that objects implement nouns while rulebooks implement verbs.

In source code, a rulebook's rules are rarely found together or in any particular order. They can be scattered all over the source code, sprinkled throughout extensions, etc. An author is free to group his rules however he wishes, such as by the narrative scene or geographical area in which they're used, or by the rulebook to which they belong, or, yes, by the object(s) to which they apply.

There are a few cases where naming a rule is useful, but these are usually in addition to the header, not in spite of it. One is in debugging output: the RULES and RULES ALL testing commands list the names of rules as they execute, or are considering execution, respectively. Two is the ability to put the rule into a rule variable or passing the rule to a phrase. Three, rarely, is imperatively invoking a particular rule. Four, especially for extension authors, is so other rules may be listed before, after, or instead of the named rule at compile time. Finally is the sake of documentation, primarily the index.

My magic hand rule is listed instead of the can't take distant objects rule in the check taking rulebook.

The landlubbers can't walk right rule is listed first in the check going rules.

The block sleeping rule is not listed in any rulebook.

This is the my foobar rule: say “Someone please invoke me imperatively or list me instead of another rule!”

Strictly speaking, a rule accepts only one parameter, as defined by its rulebook, while all else in the rule's preamble comes from global variables – the world-state. (Even more strictly: at the Inform 6 level, the parameter itself is actually in the global variable parameter_object and rules become functions taking zero parameters.) However, the default type of a rulebook is a description of actions, which itself accepts at most three noun parameters, each of which could be a set-description. Since most of the commonest rulebooks do this, rules seem to have a higher arity than they really do. Furthermore, a rule can optionally return one value, via rule succeeds with result, the type of which is defined by its rulebook. All of the standard rulebooks produce nothing, which further muddies the true nature of rules: as a kind of codec, filter, or transformation which accepts the world-state in a particular state, possibly prints something, and possibly changes the world-state as it finishes.

So to make a long story short: when a rulebook is K based, then rules belonging to it are written rulebook-name instance-of-K, and even then the instance is optional.

Snark is a text based rulebook.

Snark “your mother was a hamster”: [...]

Snark “silly English k-nigget” during the siege of the French castle: [...]

Last snark: […]

The last snark rule: [..]

Spell out is a number based rulebook.

Spell out 15: [..]

Spell out:

Spell out 2 during relationship counseling: […]

Juggle is an object based rulebook.

Juggle the hamster: […]

Juggle an animal when PETA is not in the location: […]

The first juggle something (called the whatsit) when the player does not carry the whatsit: [...]

Ms Manners approves is a rulebook. [ basis is missing, so a description of actions it shall be ]

Ms Manners approves someone nice wearing something nice: […]

Ms Manners approves someone nice inserting something nice into someone nice: [...]

Ms Manners approves (this is the pessimist or optimist rule): [...]

So let's examine rulebooks now, as they drive what a rule can, should, and cannot do, including defining the apparent syntax even if the grammar is identical in all cases.

> Rulebooks: White-box Paradigm _

Like a function, a rulebook solves what task is given it. Unlike a function, a rulebook picks and chooses which rules within itself to execute. It will execute its rules until one of them produces a success or failure result, distinct from any (optional) returned value. In lieu of a return statement, rules use one of the rule succeeds [with result X], rule fails, or make no decision imperatives, the last of which tells the 'book to try the next rule for a result. If a rule ends without one of these three imperatives, the default imperative -- usually make no decision -- is invisibly added at the end of every rule. That default is set by the rulebook.

The pick a plan rules are a rulebook.

The pick a plan rules have default outcome success. [ Or failure, or no outcome ]

A pick a plan rule: say "I always fail, regardless the rulebook's default."; rule fails.

A pick a plan rule: say "I can never make up my mind so one of my peers will now execute."; make no decision.

A pick a plan rule: say "I exhibit the default behavior for the rulebook."

A pick a plan rule: say "I'm always a winner."; rule succeeds.

A rulebook can take up to one parameter (including one whole action-description) and produce one return value. A rulebook is invoked in one of several ways, mainly depending on whether it takes a parameter and whether it produces a value. These phrases are 1) follow (rulebook); 2) follow (rulebook) for (value); 3) the (value) produced by (rulebook); and 4) the (value) produced by (rulebook) for (value).

A snarky one-liner is a rule based rulebook producing text. [rulebook by itself is action based producing nothing]

When play ends, say the text produced by snarky one-liner for the reason the action failed.

Snarky one-liner for the shouldn't touch electrical wires rule:

rule succeeds with result “You ignored the No Trespassing sign? I'm... shocked.”

Snarky one-liner for the shouldn't descend deep dark wells rule:

rule succeeds with result “Good news! You have a choice: drowning or landing.”

The remaining ways all substitute follow for either abide by or anonymously abide by. Both of these return immediately after their called rulebook returns. The only difference is the latter not setting the rule variable the reason the action failed to itself, becoming a silent middle-man. Finally, rule succeeded and rule failed, the past tense versions of rule succeeds and rule fails, are used in if statements to see if their present tense counterparts ended the recently called rulebook. This information is stored just above the current stack pointer, so calling any functions – including things which become functions in Inform 6, such as set-descriptions – will clobber them.

Check planning:

follow the pick a plan rules;

if the rule succeeded:

say "Rulebook succeeded.";

otherwise if the rule failed:

say "I've no plans because of [the reason the action failed]." instead;

otherwise:

say “Not a single applicable rule could make up its mind.”

Check planning (this is the choose-a-plan rule):

abide by the pick a plan rules;

say "This only prints if the pick a plan rule make no decision. But if it did succeed or fail, abide by returns, setting the reason the action failed to this choose-a-plan rule."

Check planning (this is the choose-a-plan rule):

anonymously abide by the pick a plan rules;

say "As above, but the reason the action failed will still be set to a rule in the pick a plan rulebook even upon success and failure. This choose-a-plan rule is a silent middle-man."

Rulebooks may also have named outcomes. Named outcomes are much like named values. Specifically, they are both a set of imperative phrases and a set of named values, which work in concert. The outcome identifier by itself is the imperative, which is syntactic sugar for rule succeeds with result <outcome>. Their named value versions all have the word outcome appended, except when printing them out, and fill-in the variable the outcome of the rulebook. Success and failure can be attached to named outcomes to save typing when they stand alone as a statement.

The audible rules have outcomes silent (failure), whispered (success), voiced (success - the default), and deafening.

[...]; whispered. [ synonymous with rule succeeds with result the whispered outcome ]

follow the audible rules;

if the outcome of the rulebook is not the silent outcome, say “You heard something [outcome of the rulebook].”

Rulebooks may also have local variables. Unlike let variables which end with the code block, these remain in scope over all the rules of the 'book. Though we don't have a specific way of initializing them like let does, we can use the rule ordinal first to put a particular rule at the start of a rulebook. (Only first and last exist this way, and in cases of multiple rules using them, only the final first or last rule actually is so, superseding the preferences of earlier rules that use them.) Last rules are useful for providing a fallback.

The pick a plan rulebook has a rule called the best plan.

The first pick a plan rule (this is the initialize plan rule): now the best plan is the little-used do nothing rule.

The last pick a plan rule (this is the no idea rule): rule fails.

Note that a rule variable can hold a rule and/or rulebook, but a rulebook variable can only hold a rulebook.

> Events are Actions _

In interactive fiction, the player controls the protagonist, and typed commands translate into actions within the fictional universe. Protagonist actions like looking, examining, or burning have rulebooks to deal with those events. Specifically, three rulebooks comprise an action: its check rulebook ensures the action can proceed; its carry out rulebook updates game state; and its report rulebook narrates the result. The other rulebooks that hinge on an action, such as instead, these three are created anew for each action in the game. There isn't one check rulebook; there are many, one for each action. This is done partly for performance reasons, and partly for sanity reasons: to avoid a “sea of rules”.

Check taking something held: say "You already have that." instead.

Carry out an actor taking something: now the actor carries the noun.

Report taking: say "Taken." instead.

Much of Inform programming is writing report rules for actions, though some game events like every turn, printing the name, and when play begins are also popular. (Game events usually comprise a single rulebook apiece unless they are activities, which we will see shortly.)

Defining a new action is similar to a function prototype. Note that is an action is required wording here. Are, the, and a are all disallowed. Furthermore, at least one “parameter” must be given: whining is an action is disallowed without some more information. However, Inform doesn't much care what that information is: supplying a past participle is just as good as the applying arity and type specification. Applying to nothing is assumed if it is dropped.

Donating is an action applying to one thing.

Discussing is an action applying to one topic.

Accusing it of is an action applying to one object and one visible object.

Tabulating is an action applying to one number and requiring light.

Scheduling is an action applying to one time.

Temporarily waiting is an action applying to one time.

Whining is an action applying to nothing.

Teleporting to is an action applying to one object. [room, to be specific]

Debugging some stuff is an action out of world applying to nothing.

Tattooing it of is an action applying to one limb and one thing, requiring light.

Weaving is an action with past participle woven, applying to one thing.

These each create the three rulebooks that will hold the implementation details. Because actions implement an English verb that our player-character (or an NPC) will perform, verbs have a maximum arity of three and a minimum arity of one. The subject, called the actor (or, as a global, the person asked), is required so no mention is made. In the implementation, the direct and indirect objects of a sentence are called the noun and then the second noun – but only if they are objects. Otherwise, the variable is the number understood, the time understood, the topic understood, etc.

The syntax for declaring actions is very special-case. The phrase requiring light refers to a worldsim precondition. The adjective visible places every object (such as intangible ideas and rumors) in scope, and is completely unrelated to requiring light. The word thing (or things) actually means any objects – we can't be more specific with person, for example. (However, it does accept object as a synonym, oddly enough.) The phrase out of world is for system-level actions, which skips a great deal of the worldsim's calculations. With past participle X tells Inform to use that word in source code for the past participle (has woven for example) instead of replacing the -ing suffix with an -ed suffix automatically. And finally, other types such as topic, time, time period, number, and various units may each only be used once in an action.

After an action is created, the action must be implemented with rules, and then the parser must be pointed to it via Understand statements. If the parser is not pointed at it, an action can still be invoked from the code, via try, try silently, and silently try. When tried silently, the report rules are skipped entirely.

try Bob donating the jeans;

silently try donating the red Ferrari;

try Bob accusing the player of theft;

try teleporting to the tattoo parlor; [subject can be dropped when "the player" performs the action]

try silently the current manager tattooing the back of the player;

For actions with two objects, at least one word (such as a preposition) is needed between the parameters, and the word it is a placeholder for the first parameter. It tells Inform where the first parameter goes, because actions with multi-part names like teleporting to it by way of have too many choices otherwise.

Finally, an action invocation can be put into a variable of type stored action and invoked at a later time. The phrase the action of must precede the invocation in order to capture it.

An abeyance is a stored action that varies.

[...]; now the abeyance is the action of Bob examining the player;

[...]; try the abeyance;

[...]; now abeyance is the action of the current manager firing the noun;

Stored actions are easy to work with when only its nouns are toggled: just use person variables like the current manager. But they are difficult to deal with when it is the action itself that we want to vary. Extensions have been written to compensate. A built-in to decide function, the current action, returns the currently-executing action as a stored action.

A final note: very occasionally, the compiler will have difficulty parsing an invocation that has a NPC as a subject. In these cases, add the word trying before the action: Bob trying examining the player.

> No Lights, No Camera, Just Action _

Processing a character's action is a multi-step process, not including parsing. Each step is its own rulebook. In order, and indenting the NPC-only rulebooks, those rulebooks are listed now.

Setting Action Variables

Before

Persuasion [ NPCs only ]

Instead [ default outcome is failure, so only one rule will typically execute before jumping to the end ]

Check <action>

Unsuccessful Attempt By [ only when Instead or Check fails ] [ NPCs only ]

Carry out <action>

After [ default outcome is success, so only one rule will typically execute before jumping to the end ]

Report <action> [ skipped if the action was invoked with try silently ]

Just to be clear, every action has its own check, carry out, and report rulebook. The others are shared among all actions.

Each rulebook has its task.

Check rulebooks catch situations which should prevent an action from occurring. It enforces preconditions, essentially. If the Check rules prevent the player from doing something, it is responsible for narrating that result.

Carry out rulebooks simulate the action, updating any data and running any code necessary. It should not print anything lest try silently won't live up to its name.

Report rulebooks then narrate the result.

Persuasion decides, upon a player command like BOB, TAKE ROCK, whether Bob will do as you ask him to. The default persuasion rule, written in Inform 6 and so omitted from the Actions index, denies with “Bob has better things to do.”

Unsuccessful attempt by runs if Bob agreed to what was asked of him, but a check or instead rule stopped him. It exists so the author may narrate failure better than the default, “Bob is unable to do that.” Again, the default rule is written in Inform 6, so is omitted from the Actions index.

Before happens between parsing and game reaction. It can also trigger on groups of actions.

Instead is useful for blocking groups of actions.

After, when adorned with a condition or three, is useful for triggering cutscenes.

Setting action variables can initializing variables that are local to an action, as opposed to variables local to an individual rulebook. This rulebook should do as little as possible, and is rarely needed.

Instead of Tiny jumping: say "Tiny is too overweight to jump. You all must find another way to help him across."

Carry out an actor jumping: now the actor is on the nearby platform. ["an actor" applies to everyone]

Report someone jumping: say "You see [the actor] jump over." ["someone" applies to any NPC]

Report jumping: say "You jump over." [subject-less means the player]

(Games with multiple PCs should note that rules specific to one character (such as "Tiny jumping") will not fire if that person is the PC. Only the subject-less rules will fire.)

The "setting action variables" rulebook initializes its action's local variables by pulling values from global variables and object properties, including the parameters "the actor", "the noun" and "the second noun". (It is NOT a way to pass additional parameters to a rule.) The "matched as" parenthetical is optional, but it allows rules in the rest of the gauntlet to test those variables similarly to how it tests on the actual parameters. The standard Going <direction%gt; action uses this to provide rule hooks like Going To <a room%gt;, Going Through <a door%gt;, Going By <a vehicle%gt;, etc.

Report going from the monkey village to the lost city's entrance by the hoverboard: say "You sail into the clearing easily this time, bypassing all those nasty monkeys that like to drop on top of you."

The jumping action has an object called the obstacle (matched as "over"). [must be a single word!]

Setting action variables for jumping:

now the obstacle is the current blockage of the location. [pulls data from the "current blockage" property of a room; specifically, the room the PC is in at that moment]

Instead of Stevie Burns jumping: say "Even little Stevie hops over [the obstacle]." [ Jumping takes no parameters beyond the performing actor ]

Instead of Stevie Burns jumping over a fiery fallen beam: say "'Help!' says Stevie. You suddenly recall him telling you about the time his house burned down." [ we can now test on the local variable with an "over" phrase ]

Because the Before, After, and Instead rulebooks are shared among all actions, they may apply to entire categories of actions. A named group of actions is called a "kind of action", and they have no special declaration syntax beyond the word "is" sitting between the action's name and the kind-of-action's name. This encourages all manner of nouns, adjectives, and adverbs to name a kind-of-action, but some read better than others when used in rule headers. In all cases, an action must be defined before attempting to classify it.

Whining is pointless behavior.

Temporarily waiting is pointless behavior.

Discussing is conversation.

Accusing it of is conversation.

Accusing it of is drama.

Teleporting to is drama.

Tabulating is acting like a frickin' accountant.

Scheduling is acting like a frickin' accountant.

Kinds of actions can then be used in rule headers. (In the following examples, remember than "when" and "during" begin additional clauses that check global variables and whatnot.)

After pointless behavior: say "But you still feel unfulfilled."

Before conversation when the current interlocutor is not in the location: now the current interlocutor is a random person in the location.

Instead of drama, say "(Now is the time to lay low!)"

Instead of acting like a frickin' accountant during the collapsing bridge scene, say "You calculate (correctly) that you're about to become a victim of natural selection."

Any rulebook that can accept a kind-of-action can accept an explicit list of actions as well. Let's then call this list Feature #1, because of the many variations on it. There is a special kind-of-action, the noun phrase "doing something/anything", that matches all actions. (Feature #2). Optionally, it may [#3] be followed by an "except" / "other than" clause that lists actions. Then, optionally, we may [4] tack on an object Description to further constrain the rule. (The Description can [5] be preceded with "with/to" if we wish; it frequently improves readability.) And of course, we may [6] always add other conditions with "when" and "during", such as the "in the presence of Person" boolean function.

Before an actor discussing [4] a spiffy thing [6] when in the presence of Mr Blackheart: [...].

Instead of [2] doing anything [3] except waiting [6] when the player is paralyzed, say "(Uhh... can't... move...)"

Instead of someone [2] doing anything [3] except taking, dropping, or burning [5] with [4] something incriminating, say "[The actor] says, 'No, I must get rid of [the noun]!'"

After [1] examining, looking under, or searching [4] anything owned by Mr Blackheart [6] during a scene needing tension: say "Suddenly, Blackheart re-enters the room. 'What are you doing.' It wasn't a question."

Just to be clear, "doing something" is a single identifier. "Doing" is not an action, and its following "something" is not a parameter Description. But "something" is a parameter Description elsewhere, as in "examining something" or "accusing something of something".

Six caveats: One, when using "doing something", we must remember that the Looking action is what primarily prints text when we enter a place -- or re-prints it when we load the game, etc. -- so we frequently will want to allow it. Two, when using "doing something to/with/-- something", actions of low arity like Sleeping and Waiting won't be caught by it, because they never apply "to/with something". Three, the docs don't cover any syntax for constraints on "the second noun", but a "when" clause can be appended. Four, when explicitly listing several actions together, they must check the same arity. (So we can't combine "sleeping" with "examining something", but we can combine "sleeping" and "examining". The arity of the check, not of the action, is important.) Five, but we can combine them using a kind of action (see immediately below). And six: in all cases, the subject of the actions is kept completely separate from the actions' description; consider it already processed by the time the action group's description starts.

Examining something is acting like a klutz. [not "an actor examining something"]

Dropping someone is acting like a klutz. [notice the "someone"]

Looking is acting like a klutz. [arity of the check is lesser than the other two]

Before someone acting like a klutz: [...]. [works for any NPC examining a Thing, dropping a Person, or Looking]

> Understanding Our Player, Our Parser _

The player's parser is a fairly simplistic one, little changed over a decade of use, but it makes heavy use of callbacks for some surprising extensibility. These parser callbacks are called topics (meaning, they are of type Topic). Topics are simplistic regexes in the shape of a boolean function, and if they match, they "return" what object, unit, action, or value they find by setting global variables. A given topic must "return" only one particular type; more on that in a moment. We use Understand sentences to add these topics to the pre-existing list of other topics that the parser runs down. Here are some examples of using Understand to connect topics with actions:

Understand "whine" as whining.

Understand "donate [something]" as donating.

Understand "give away [something]" as donating. [we're making a synonym here]

Understand "discuss [text]" or "talk about [text]" as discussing. [ditto, but as one topic not two]

Understand "tabulate [a number]" as tabulating.

Understand "answer [truth state]" as answering.

Understand "schedule [a time]" as scheduling.

Understand "wait for [a time period]" as temporarily waiting.

Understand "teleport to/-- [any room]" as teleporting to. [the altercation slash can't be used on the first word]

Understand "accuse [someone] of committing/-- [any thing]" as accusing it of.

Understand "[any thing] committed by/via [someone]" as accusing it of (with nouns reversed).

Understand "wear [something preferably held]" as wearing.

Understand "put [other things] in/inside/into [something]" as inserting it into.

Understand "deposit [something] in/into [an open container]" as inserting it into.

Understand "go to [any adjacent visited room]" as going by name.

Understand "tattoo [limb] of [someone]" or "tattoo [specific limb] of [someone]" as tattooing it of.

The whole text between "Understand" and "As" is a topic, and the text in the square brackets is yet another topic called by the larger topic. The called topics start their parsing where the calling topic left off, trying to decide if the words that follow match itself.

The topic "any thing" -- as opposed to "thing" or "something" -- ignores the limitations of scope, and will match any valid object found in the whole game. The word "any" in general works like this, and must be echoed in the action definition by the word "visible". You can then guess what "any room" means. Other topics are intended for a particular type -- Time, Number, Units, named values (like Limb), undigested text (which the actions reference by "applying to one topic"), etc. One of the types, Description, is quite powerful: "an open container", "any adjacent visited room", and "something related by reversed containment" are examples of descriptions.

Understand can also expose other parts of our games to our players: property adjectives, synonyms for object names, and even other topics:

Understand "dog" as Rover.

Understand "birds" and "ruddy ducks" as the plural of duck.

Understand "upper [limb]" or "lower [limb]" as "[specific limb]". [this won't capture the words Upper or Lower, but allows the player to use them ]

Understand "beneath/under/by/near/beside/alongside/against" or "next to" or "in front of" as "[nearby]". [this is a convenience for the programmer only]

Any single topic can only return one specific type of something

Understand "colour [a colour]" or "[something]" as "[tint]". [error: is this Topic's return type a Color or Thing?]

A pot is a kind of thing. A pot can be broken or unbroken.

Understand the unbroken property as referring to the pot. [or, "...the broken property..."]

Understand "shattered" or "cracked" or "smashed" as broken.

Understand "pristine" as unbroken.

Understand the broken property as describing a flowerpot. [describing disallows "take broken"; player must provide the noun: "taken broken pot"]

Understand "bottle of [something related by containment]" as a bottle.

Understand "machine" as a device. [device is a class, so "machine" will narrow down the choices if the parser must make a guess]

Finally, if-conditions can be attached to any of these Understand statements, so the parser will ignore the line if its condition isn't met.

Understand "rouge" as red when the make-up set is visible.

Understand "Rover" as Rover The Dog when the player knows-about Rover.

Understand "your" as a thing when the item described is held by the person asked.

But remember that this happens during parsing of the player's command, so the condition can't always refer to information within the command itself, such as "the noun" or "the second noun". In the case of "the person asked", it works for FRODO, GIVE ME YOUR RING because Frodo has been parsed already; but it may not work if "Your" is the very first word of the command.

If we just want a simple reply with no processing, there's a shorthand.

Understand "xyzzy" as a mistake ("The machine doesn't seem to have a button with that label on it.") when in the teleportation chamber.

Understand "xyzzy" as a mistake ("Ah, I see you're an old hand at this.").

Mistakes can use the [text] token but little else. They can use To Say functions in what they print, so it is possible to do some simple codework from them. Mistake lines are parsed before non-mistake lines, because they're intended to cover exceptions to grammar or one-off, out-of-game remarks by the player, rather than entire categories of input.

> Time for a Scene _

The Room class divides space into discrete places. Scenes divide an interactive fiction into durations of time. Each scene is implemented as a boolean variable that is automatically set & cleared by a condition. Scenes may happen again unless declared "non-recurring".

A lightsaber duel is a [non-recurring?] scene.

A lightsaber duel begins when the location of Luke is the location of Darth.

A lightsaber duel ends when Luke is too injured to continue or Darth is too injured to continue.

A person can be too injured to continue. A person is rarely too injured to continue.

Rule headers and imperative code both can check to see if a scene is happening.

Every turn during a lightsaber duel: say "BWWAAUUAAAHH".

[...]; if a lightsaber duel is happening, [...]

Each scene provides two rules that execute when the scene begins and ends. These are just hooks we may use or ignore.

When a lightsaber duel begins: change the command prompt to the battle command prompt.

When a lightsaber duel ends: change the command prompt to the normal command prompt.

Scenes are not objects, but we can add boolean properties to them in the same way.

A scene can be thrilling or dull. Train Stop is dull.

A scene has a text called cue speech. The cue speech of Train Stop is "All aboard!".

Every turn during a dull scene: [...].

[...]; if a thrilling scene is happening, [...]

> Arrays Have Been Tabled _

Inform is not a language of computation. It is a language designed to hold secrets for the player to discover. So its two-dimensional arrays -- tables -- are primarily intended for a single, occasional lookup. Tables are statically-allocated like everything else, and the words "row" and "column" are used a lot in lieu of (x,y) coordinates.

Here's an example table from the docs:

Table 2.1 - Selected Elements
Element (some text)	Symbol (some text)	Atomic number (a number)	Atomic weight (a number)
"Hydrogen"	"H"	1	1
"Iron"	"Fe"	26	56
"Zinc"	"Zn"	30	65
"Uranium"	"U"	92	238

Or, alternately:

Table of Selected Elements
Element	Symbol	Atomic number	Atomic weight
text	text	number	number
"Hydrogen"	"H"	1	1
"Iron"	"Fe"	26	56

A blank line and the keyword "Table" begin the whole affair. At least one tab character is required to end a column and start the next. Multiple tabs and spaces are OK; the first tab character Inform comes across melds together all whitespace surrounding it. Type information can either be left off -- Inform will deduce it mostly correctly -- or can be given in the two styles shown. Both styles have problems. The first, "inline" style only allows "object" for objects, not a particular class (like "person"). The in-row style allows specific class names, but introduces a bug -- row #1 will be a blank row that doesn't correctly flag itself as blank. This is because we can:

Table of Energy Proponents
Proponent	Fuel	Danger
Bob	Hydrogen	a number
Phoebe	Wind	--
--	Geothermal	--
Jean	Nuclear	10
with 4 blank rows.

..only put the type in-row when it would be blank otherwise (and defeat the inference). A blank entry is denoted by the -- double-dash. The last line ("with X blank rows") statically allocates some extra space. A character's responses to the player's inquiries on various topics has special syntax, a column entitled "topic" whose type will also be Topic. Remember that topics are (simplistic) regexes, so they can't be printed.

Table of NPC Responses
topic	answer
"hi/hello"	"He says, 'Well hello there!'"
"bye/goodbye"	"'Take care,' he answers."

There's several phrases to work with tables, but it's still one of the more cumbersome parts of the language. This is because we must "choose" a particular row and then work with each "(column name) entry" as if they were each a standalone variable. We can't pass a chosen row to another function. We can't choose two rows simultaneously, either in the same table or in different tables. We can't copy rows to other rows. We can't look up a row based on multiple criteria except by a laborious explicit loop with O(n) running time and hard-coded queries. Finally, we can't create N-dimensional arrays except by creating a column of type "table-name" and the creation of a lot of statically-allocated sub-tables by hand!

Rather than explaining every detail of the procedures and functions related to tables, I'll list most of the examples from the docs (Chapter 15), and capitalize the names of the parameters. Their operation should be relatively obvious. The following are all imperative.

if Wind is a Fuel listed in The Table Of Energy Proponents ...

blank out the whole row;

choose row My Favorite Number in The Table Of Energy Proponents;

if there is no Proponent entry ...

choose row with Danger of 10 in The Table Of Energy Proponents;

if there is a Proponent corresponding to a Fuel of Geothermal in The Table Of Energy Proponents ...

choose a blank row in Table 2.1;

change Element entry to "Fluorine";

change Atomic Number entry to 9;

if there is an Atomic Number in row 2 of The Table Of Standard Elements ...

sort The Table Of Energy Proponents in reverse Danger order;

sort The Table Of Energy Proponents in random order;

These are value-returning functions:

... the number of blank rows in Table 2.1 ...

... the number of filled rows in Table 2.1 ...

... the Proponent corresponding to a Fuel of Hydrogen in The Table Of Energy Proponents ...

... Symbol in row 3 of The Table Of Selected Elements ..

And these are examples of putting a table lookup in a rule header; the table-specific part begins with a column name, followed by "listed in", and then a table name:

after taking An Item listed in The Table Of Treasures: [...].

after asking The Guru about A Topic listed in The Table Of NPC Responses: [...].

One concession to ease of use is that its sort routine is stable: if multiple rows have the same value in the column we sort on, then their order vis-a-vis each other will not change.

> Named Values Everywhere _

Inform uses named values everywhere; it is usually properties that remain anonymous. We can explicitly create a new named value:

A limb is a kind of value. The limbs are left leg, left arm, right leg, right arm, the neck, and the back.

Tattoos are a kind of value. The tattoos are mom, barbed wire, wings, a kanji, a pseudo-photograph, and some obscure symbol.

Named values can have spaces in their names, but they cannot have their names abbreviated like objects can. Inform generally allows almost any word to be part of a named value, but be warned, if you put words like "when" or "is" in a named value, it may create compilation problems when used in other, particular places.

Named values are a type, similar to Time or Number but finite in length, that can be used in many places.

change X to the limb after the left leg;

change X to the limb before the back;

Definition: a limb is hurt if [...].

Tattooing is an action applying to one limb and one thing.

Understand "tattoo [limb] of [someone]" as tattooing.

Exposition relates various people to various tattoos. The verb to be tattooed with implies the exposition relation.

Bob is tattooed with some obscure symbol.

[...]; repeat with X running through each limb begin;

In the above, the action "tattooing", the relation "is/are tattooed with", and the named value "tattoos" are all distinct from one another.

Named values can also be given properties, as an object can.

Named values can be defined by a table. Since tables can be continued and amended by client code at compile-time, this is a handy way to leave our named values "open".

Tattoos are a kind of value. Some tattoos are defined by the Table of Designs.

Table of Designs

tattoo

barbed wire

wings

Table of Designs (continued)

tattoo

Jean-Pierre 4-ever

Inform automatically creates some named values that correspond to other parts of the language. For example, the containment relation is an example of the relations named value, which corresponds to a built-in relation. This named value is passed into phrases such as the pathfinding and lookup functions mentioned in the relations chapter. New relations would be treated similarly: the teenage love relation. Likewise, action name is the named value counterparts for actions: the looking action, the inserting it into action, etc. Other times, another part of the language is little more than a named value. Scenes, for instance.

Causality relates an action-name (called the cause) to an action-name (called the effect) when [...].

SecondOrderRelation relates an abstract-relation (called the scaffold) to an action-name (called the side effect) when [...].

> T.E.X.T. _

Though it's probably obvious by now, text is put between double quotes; within, text in square brackets is a To Say phrase (a procedure call). Where other languages use the word print, Inform uses the word say. Punctuation note: the ' apostrophe expands to a double quote, except for standard verb contractions like don't or can't. Otherwise, substitutions are frequently required for certain punctuation. So to print:

Rene Descartes said, "I think not!" and promptly disappeared.

So don't ever say that, 'k?

Use:

say "Rene Descartes said, 'I think not!' and promptly disappeared.[line break]So don't ever say that, [']k?";

Variables and objects can be put in the square brackets to print their current value and their name, respectively. (The outputted name of an object can be overridden by a rule in the Printing The Name Of Something activity; more on activities later.) Line breaks are automatically appended if the last character is a period, question mark, or exclamation mark.

Inform was originally designed to make games with a very small memory footprint, so a game's output text is compressed, and language support for regexes is poor. The Text datatype is this compressed text. Indexed Text -- a later and still optional addition to the language -- isn't compressed, so regex operations will work on it. Typecasting between the two is mostly automatic and is one of the very few (if not only) cases of implicit casting. Also, both text types used the double quotes identically, so constructions like the following are needed to avoid creating a plain Text type by accident:

let T be indexed text;

let T be "Hello World";

Typically, access to input text isn't direct. Modification is mediated through the Snippet type, the Topic type, and a couple of phrases. A snippet is a pair of numbers, joined together like fixed-point notation, that represent a range of words. "The 3 words starting at word #2" would be the snippet 203. There are only three built-in snippet variables, "the player's command", "the matched text", and the confusingly-named "the topic understood".

if the player's command does not include "please/thanks", say "How rude!";

if the player's command includes "please/thanks", cut the matched text;

if the player's command includes "hi", replace the matched text with "hello";

if the player's command matches "hello world", say "You're a programmer, aren't you?";

if the player's command does not match "hello world", say "To code... perchance, to write?";

Topics are simple textual patterns, a poor man's regex, that attempt to match input text. They are also written simply with double-quotes, and their only operator is the / slash as high-precedence altercation. In the above example, "please/thanks" is a topic (the type was inferred from the "include/includes" function). Topics are frequently used in a game's conversation system, where implementing as objects everything that's interesting to ask about would eat memory. Topics are also why the object hierarchy does not have an Idea or Concept class, since variables can track any information gained that isn't implicit in the owning of a physical object. We'll see more of Topics, and the peculiar snippet "the topic understood", when we examine tables.

Indexed text is a late addition to Inform, and is cumbersome to deal with because the language tries to remain statically-allocated. As a result, our string-manipulation type has a lot of restrictions on where and how it can appear. But it is finally possible to gain direct access to the player's input by typecasting the snippet to indexed text:

let N be indexed text;

let N be the player's command;

[...];

change the text of the player's command to N;

Know that the last line is a very special one-off syntax designed to blend in with the rest of the language -- even the word "the" is required. Snippets do not have properties, other snippets cannot be used in that line, and there's only one parameter there -- N, in this case -- not two. We won't cover the regex engine here -- see Chapter 19 "Advanced Text" -- except to say it executes very slowly.

> Precisely One Spoon-unit Of Sugar _

Units are user-defined numeric types with some nifty syntactic sugar that extends even to our player. Generally in programming, numbers are numbers: the programmer must remember one variable measures in pixels while another measures in picos, and to mix the two makes bad medicine. But Inform allows us to define dimensional numbers called units. They work as they do in physics and carpentry: each unit is a type (to use the computer science word), and only the same type may be added or subtracted. Multiplication and division produce different types, such as a length in meters times another length in meters equals an area in square meters. Inform allows us to define the syntax of how units are written, again producing some very readable code. The punctuation marks or identifiers are called the preamble to a part while the individual numbers (parts) can be named.

Money is a kind of value. $99.99 specifies some money with parts dollars (without leading zeros) and cents (optional, preamble optional).

The numbers used in the syntax definition are the largest numbers allowed in that place. For example, time would be declared 12:59 because the hour increases at 60, the minutes rolling over to zero. Here we stay just shy of a hundred bucks. The property preamble optional means, if there are no cents, the preamble for cents – the period – is also optional.

My wallet is some money that varies. My wallet is usually $20.75.

A thing has some money called the price. The price of a thing is usually $5.

The price of the red Ferrari is $34.99. [ the toy Ferrari, of course ]

say "[the dollars part of the price of Bob]";

Add and subtract units with the same unit. And by default, we can only multiply by a dimensionless number and divide by the , or by itself if the resulting unit is nothing (i.e., a plain, dimensionless number).

say “I got [$20.00 divided by $1 in words] dollars.” [ prints “twenty” instead of “$20.00” ]

To allow multiplication and division, we must specify what new unit is created. We can always multiply and divide a unit by a plain number. Multiplying and dividing by one is how we explicitly typecast between units and numbers. Note the re-use of the specifies verb.

A length is a kind of value. 10 m specifies a length.

An area is a kind of value. 10 sq m specifies an area.

A length times a length specifies an area.

Definitions for metric and most scientific units is already provided in the included extension Metric Units, we just use this as an example.

Inform automatically creates a new Understand token from units. The player writes the unit the same way(s) as the programmer.

Understand "donate [money]" as donating. Donating is an action applying to some money.

Finally, we can re-use the "implies" statement from defining relations for an extra dose of sugar.

The verb to cost (it costs, they cost, it is costing) implies the price property.

The jeans cost $19.95.

Note that we didn't define a relation there, though it may look like it. But we could:

Fanciness relates a thing (called X) to some money (called Y) when the price of X > Y. The verb to be fancier than implies the fanciness relation.

let L be the list of things fancier than $2.50;

let B be the list of things fancier than the price of jeans;

The built-in type time is not a unit, but pretends to be. Time's parts -- hours and minutes -- are calculated from a 4 AM minute-count, not stored as separate numbers as units are done. This makes math with times much easier.

Equations. Mathematics is the ultimate declarative language: it doesn't compile to assembly.

Slope is a number that varies.

Y-intercept is a number that varies. The y-intercept is usually 12.

Equation - Slope-Intercept Formula

y=mx+b

where y is a number, x is a number, m is the slope, and b is the y-intercept.

When play begins:

let m be given by the Slope-Intercept Formula where x is 7, y is 0, and b is 3;

say "[m]; [slope]."

integers only, but, fixed point by scaling?

Though you can type odd characters like π into the IDE, the compiler rarely likes them.

Equation - Area of a Circle

A=pir^2

where A is a number, pi is 3, and r is a number.

When play begins:

let A be given by the Area of a Circle where r is 4;

say "[A]."

> Backstage Activities _

Actions are player-generated events. Activities are library-generated events. Activities provide hooks (in the form of allowing rules to be written) that modify the behavior of the library. One of the primary purposes is overriding some prose. For example, the author may wish to display the name of a character or tool differently depending on circumstance and history. For example, if possessing a particular object is required to complete the story, then we might want to 'color' the name as a hint in a particular circumstance.

Rule for printing the name of your backpack when your backpack is not carried: say “your abandoned backpack”.

The initial word rule is syntactic sugar, as is the following preposition of, and may be dropped.

Rules and phrases can ask if they're being used in the context of an activity.

Before printing the name of the rope while listing contents of your backpack: say “hopelessly tangled ”.

[...]; if the listing contents activity is going on,

A synopsis of the built-in activities follow. What is interesting about the activities is, being library events worth customizing, they say a lot about the priorities and evolution of the library, and by extension, the field of interactive fiction as a whole.

Prose generation. This might be a heavy label for what are fairly straightforward events, but they are the most important.

Printing the name of something. The commonest activity overrides the printed name property, though frequently it's more efficient to insert [if.. ] say-phrases into the printed name. No need asking if in rule headers if it's considering some other object entirely. Still, there are instances where using the full power of the rule decision machinery is helpful, such as changing or amending the names of an entire set-description all at once.

Printing the plural name of something. Overrides the printed plural name property likewise.

Printing a number of something.

Listing contents of something. Printing a list of things is an extremely handy piece of library code. Pretty-prints a list of objects "held" by the sole object passed to it. Used by taking inventory, and looking during the you-can-also-see line.

Grouping together something. Used by the above to offer some control on the order.

Parsing Input. Since interactive fiction is about entering text to get back more text, these activities are collectively the next most useful. While Inform supports regular expressions, they operate slowly

Reading a command. While most activities are usually useful because they allow changing the default behavior (a for rule) or provide a hook for additional programming (before and after rules), the reading a command activity is useful in multiple ways. Before reading a command is useful for re-initializing global variables, since it's the “last” thing to happen in a turn. After reading a command is useful for pre-parsing work via the phrases if the player's command includes, if the player's command matches, cut the matched text, and replace the matched text with. (Although we can use regexes on the text, the regex engine is slow.) Finally, for reading a command prints the command prompt and waits until the enter key is pressed, so creating a new rule there allows us to completely rewrite or manufacture input.

Printing a parser error. This allows customizing the standard nineteen different parser errors, most of which by themselves are not terribly informative about how the player should re-factor their input.

Rule for printing a parser error when the latest parser error is I beg your pardon: try looking instead.

Clarifying the parser's choice of something. When the parser takes a guess at what the player meant, it prints a parenthetical like “(taking the small one)” to clarify. But, for bleedingly obvious selections, it may be best to print nothing at all.

Clarifying the parser's choice of your coat: do nothing.

Asking which do you mean. When the parser cannot guess, it asks you, "Which X did you mean?"

Supplying a missing noun. When the author takes a guess at what the player meant. For this activity to even be considered, the understand lines need to understand a command with fewer parameters than the full amount. This activity is not satisfied until the noun is no longer nothing.

Supplying a missing second noun. When the previous activity has nearly the same name, take a guess.

Deciding whether all includes. Upon TAKE ALL, what is included? The drapes? The kitchen sink? The sun? While rearranging the world like a play's stagehand has promise, typically ALL doesn't mean everything. By default, it means everything except other people (rude!), scenery (i.e., the kitchen sink), or anything fixed in place (i.e., nailed down).

For deciding whether all includes her earrings: it does not.

Deciding the scope of something. For when it's not in the room but needs to be referred to anyway.

Deciding the concealed possessions of something. Similar to scope, but not so heavy-handed. Rarely needed.

System level.

Constructing the status line. This is like printing the name of for the status line at the top of the reading area. The status line has a left half and a right half, and extensions can do more with it, including full windowing capabilities. By default, the status line holds the location name, and the score.

Printing the banner text. This prints the title, subtitle, author, and “copyright” information that begins a game. Messing with the banner is a fast way to make your game look amateurish. Occasionally, printing something just after it is tasteful.

Printing the player's obituary. In text adventures of old, you died a lot. No, really, I'm not kidding. You died so much, so often, this activity was specifically created to await the hundreds of rules that will narrate your myriad methods of shuffling off, leaping, falling, breaking, splitting in two, burning, freezing, misplacing, forgetting, and generally becoming thoroughly divorced from this mortal coil. Nowadays, the story may still end abruptly, but it's frequently because the player has failed to roleplay rather than having succumbed to a videogame's peculiar eagerness to murder. Still, the activity's name remains.

Amusing a victorious player. Once a story has completed in the fullest sense of the word, it is customary to AMUSE the reader with outtakes or did-you-try-this suggestions.

Starting the virtual machine. Multimedia may need this hook to initialize some things, but generally the rest of us may ignore it.

Taking. As interactive fiction has progressed, many of the meticulously simulated elements have fallen into disfavor, as they required meticulous inputs from the player to enact what should be common sense. For example, picking up a key before using it, or picking up a cupcake before eating it. Others would be opening a door before going through it, perhaps even unlocking it first. But refusals when the necessary object is near at hand have been nitpicking players long enough that GET, one of the commonest inputted player commands, can be done automatically (implicitly), to the relief of cupcake eaters everywhere.

Implicitly taking something.

Looking. This action is surprisingly heavyweight, because in text adventures of old it was the main delivery mechanism of information: the setting, the current state of interactive props, segue through props important enough to have their own paragraphs, etc. As the field progresses, the conventions, usages, and shape of “room descriptions” evolves, which has led to a profusion of activities covering every minor aspect of LOOK. Since interactive fiction in the vein of Colossal Cave

Printing room description details of something. Or are we in Darkness? If so, skip down.

Printing the locale description of something. Of the room, then of the cage we're in, etc.

Choosing notable locale objects for something. What's in here? What's important and needs describing?

Printing a locale paragraph about. Doesn't actually print anything, just demotes or promotes things.

Writing a paragraph about. Prints a thing's description property.

Listing nondescript items of something. Items lacking the description property are listed at the end, via listing contents.

Darkness. Darkness is a holdover from text adventure's earliest caving days when it served as a locked door and/or tension-builder. It's been implemented as a room all its own, “thedark”, whose name, description, and attempts at hosting actions are handled by special case. Nowadays, most of dealing with darkness or related encompassing conditions, such as being tied to a chair, are best done with instead rules, so the following activities, each of which only prints a sentence, can be ignored.

Printing the announcement of darkness. “It is now pitch dark in here.”

Printing the name of a dark room. This prints a room heading, “Darkness”.

Printing the description of a dark room. This prints the room description of the dark.

Printing a refusal to act in the dark. This narrates an instead of doing something requiring light when in darkness rule.

Printing the announcement of light. And this brings our brief little fright full circle.

> Testing Commands _

We have one testing command in the language itself:

Test me with " look / test foobar / wave ".

Test foobar with " look / take me / jump ".

This will execute the slash-separated list of runtime commands when the TEST runtime command is issued. Me is the usual name for the top-level test script.

We have several run-time testing commands at our disposal.

SHOWME an object: Will list the current values of all the properties of that object, including any relations it's involved in.

RULES: Will list the name of a rule before it executes.

RULES ALL: Will list the name of a rule before it considers execution.

RULES OFF: Turns off the mode.

ACTIONS / ACTIONS OFF: Will list when actions begin and end.

RELATIONS: Lists the current state of all relations.

SCENES / SCENES OFF: Lists the scenes currently happening, and will update us when one begins or end.

TREE: Shows all instantiations, indented according to the containment relation.

TEST a test script: Runs the list of commands.

PURLOIN an object: Immediately places the object in the player's inventory, no questions asked.

ABSTRACT object TO object: Similar to purloin, but gives the first object to the second object, which is likely to be a container or some such.

GONEAR an object: Moves the player to the room which has the object.

RANDOM: Random number generator now predictable.

SHOWVERB: Shows I6-level information about a verb: synonyms, arguments, whether the arguments are reversed for a particular line.

SCOPE: Show all objects currently in scope.

SCOPE object: Show the scope from the particular object.

TRACE a number: Shows very low-level parsing information. The number ranges from 1 (the default) to 6 (the most detailed).

The IDE has the skein -- which is a tree of commands of every playthrough we've done in the IDE -- and the transcript -- which is a detail view of one path in the skein. It has the output text from those commands. The transcript also has the bless button, so automated re-testing of changes is possible.

> Indistinguishable Instances _

Inform does not (currently) support arrays, but it does have a way of creating up to a hundred indistinguishable instantiations of things. A subclass is required for this, but that is easy enough to arrange.

A coin is a kind of thing. 55 coins are in the couch. Three coins are carried by the player. There are seven [more] coins.

That last definition creates objects but leaves them off-stage. The commented-out word “more” is only placed there for clarification. It is especially useful in cases like: There are seven coins. Three coins are in the couch. Those sentences imply there are a total of seven coins in the world, rather than ten, seven off-stage and three on-stage.

There's a few things to know about unnamed instances. We must subclass before instantiating or else we'll have a single object called "55 coins". We can't reference “the thirty-second coin” like we could with an array, but instead must use set-descriptions with a random to grab one: try taking a random tarnished coin which is not carried by the player. And it's up to us to verify such an instance exists. We can't specify a quantity of them as in now the player carries three coins or try taking three coins because Inform won't know which three coins, but we can manipulate all of them as in now the player carries every coin. So, instantiate away, but as far as Inform 7 is concerned, there's only zero, one, or infinite coins.

Our player can TAKE THREE COINS if the action's understand line applies to [things], plural, as taking and dropping already do. Furthermore, we can expose the various properties (adjectives) of our new subclass to the player's parser, giving the player the ability to differentiate with TAKE THREE TARNISHED COPPERS. As referring to exposes it as a pure adjective, while as describing exposes it as both adjective and noun.

A coin can be pristine or tarnished.

A metal is a kind of value. The metals are copper, silver, and gold. A coin has a metal.

Understand “coppers” as copper. Understand “silvers” as silver. Understand “golds” as gold.

Understand the tarnished property as referring to a coin. [ tarnished or pristine by itself won't grab a coin ]

Understand the metal property as describing a coin. [ but copper, silver, or gold will ]

Though we wouldn't normally expect the player's parser to be more expressive than the programmer's, in the case of taking three coins, the runtime always has the option of interactively asking for details ("Which did you mean?") while we do not.

> Time, Turns, and Tenses _

Time comes in at least two flavors, instants and durations. Three and a half hours would be a duration, while 3:30 pm is an instant, a specific point on the timeline. Internally, both are stored as the number of elapsed minutes since 4 am, and only understand assertions distinguish between the two, time being an instant and time period a duration. Math is straightforward: adding or subtracting a duration produces whichever it's being combined with, while subtracting two instants produces a duration. But adding two instants is nonsense: what could 9:38 pm plus 4:47 am possibly be?

We can count how many times a condition is true, and how many turns in a row they stay true.

Before taking the candle once: say "Hey, it's a candle."

Before taking the candle twice: say "You guess you'll need that candle again after all."

Before taking the candle for the third time: say "Your life seems tied to this candle."

Before taking the candle for at least 4 times: say "Sigh."

Every turn when the player does not carry the sprite for at least 3 turns: say "The sprite sings a lonely song."

and durations can be expressed in turns as well as minutes. (The time datatype is firmly in minutes, but the turn count relates to the time of day by the ratio one turn per one minute, adjustable via extensions.)

We can adorn rule preambles like when the turn count is one to pinpoint the very first turn of a new game, or for at least four turns which is true after the rule has fired for the fourth time in row, and remains true as long as the rest of the condition holds. We can query the number of times some condition has held true with once, twice, the third time, N times. The preposition for may precede if it increases readability. Note that at least means equal to or greater than.

It is fairly safe to amend a relation's condition, as any particular occurrence can be a duration of many, many turns. But verbs of action have a caveat: these amendments lump successful and unsuccessful actions together. This means the times and turns amendments should be confined to rules that are guaranteed for consideration every turn: before and every turn, and early in persuasion and instead. Any later than that and we must take precaution that the rule isn't pre-empted, missing the chance to even see the Xth attempt or the Nth tick.

After taking the candle twice: say "If a check rule blocks the second attempt, this after rule never fires."

The narrative use of these amendments is for varying the narration of repetition. Interactive fiction differs from video games in that a first success is worth reading about, and the second only to ensure that you've learned the skill, but after that why tell the reader again. It's old news. Of course, repetitive failure is not much fun either, but it at least has a narrative role as struggle. And so, Inform's for the Xth time hooks us into multiple attempts, not multiple successes.

Check burning when the candle is unlit once: say “You'll need to light the candle first.” instead.

Check burning when the candle is unlit twice: say “Again, your source of fire needs be lit first.” instead.

Check burning when the candle is unlit for at least the third time: say “The candle is out again.” instead.

While minutes and turns both precisely measure time, tense is a relative measure expressed in English via verb inflections.

A few of these inflections Inform gives a meaning to. The perfect tenses mean “have ever been true”. So an action in the present-perfect, if we have taken the candle, begins the game false, becomes true on the first successful TAKE, and never again changes value. Relations, like if Bob has carried the candle work similarly, but the implementation differs. Each object has a hidden bit array property holding the answers to if we have queries, so questions of the form if we have taken the noun work fine. Relations are case-by-case: an implicitly-created variable BobHasCarriedCandle holds this answer. So actions accept variables like the noun but no subject – the we are is literal, required, and has no synonyms – while relations accept a subject like Bob but no variables – BobHasCarriedNoun just won't work right.

if Bob has ever remembered the time he spent in jail, [ present is can remember – can becomes ever ]

The intended usage of the perfect tenses is narrative: stories are about irrevocable developments. While the condition if Grognar carries the Sword of Smiting is correct when we're checking to see if he can swing the sword, it isn't correct if an character asks him to describe the sword. Sure, if he has never encountered the mythical blade he has no first-hand knowledge of it, and if he does carry it then he certainly can describe it. But if the sword is temporarily separated from him, asking him under the simple present tense produces a false negative. Grognar has learned what the blade looks like, and that is as irrevocable as discovering the villain is his own father. This then is where the perfect tenses come in: knowledge and plot points.

Before moving on, a quick detail about testing the present for the sake of syntax consistency: when testing whether or not a particular action is currently going on that turn, we are is accepted in front of the action, but is optional. This mirrors the we have of the present-perfect.

Every turn: if taking something unique, [ perfectly synonymous ]

Every turn: if we are taking something unique,

Relations also support the past and past-perfect tenses. If you've ever implemented a linked list, you likely know how useful a "previous" node pointer is in addition to the "current" node pointer, especially for updating those very node linkages. Similarly, when the condition of an if-statement is asked in simple past tense, it queries the previous turn's game state, not the current one. For example, when phrased in present tense the follow lines of code would be broken: the candle would always be lit afterward regardless its state beforehand. But written in past tense, the lines indeed toggle the lit property.

if the candle was lit, now the candle is unlit;

if the candle was unlit, now the candle is lit;

(Properties use the verb relation is/was. Again, properties are a special case of relations.) Remember that by itself the simple past tense only asks a question of the immediately previous state, not necessarily what changed since the previous turn. So the following wouldn't do what was intended.

if Bob managed the player, say “So long, Mr. Picky!”

When Bob was the manager on the previous turn, most likely it is because he is the manager now, too. Try this instead.

if Bob managed the player and Bob does not manage the player, say “So long, Mr. Picky!”

We recognize change by bracketing it with two world-states, the present one and the previous turn's (past) one. And should the player again come under the tyranny of Bob, the message will be re-printed when he yet again leaves Bob. Now we can greet our new manager.

if Joan did not manage the player and Joan manages the player, say “Hello, Joan.”

The past-perfect (if X had been Y or if Bob had managed Dave) relates to the present-perfect as the simple past relates to the simple present: the past-perfect remembers the previous turn's present-perfect value. Because the present becomes the past at the end of a turn, during the update chronological records rule found in the turn sequence rulebook, and because the perfect tenses do not change once set, the only time throughout the entire game when the past-perfect isn't equal to its present-perfect twin is during the end of the one turn that changes the present-perfect.

To continue Joan's example, replacing the past and present with the past-perfect and present-perfect still recognizes the change via bracketing, except this time the rule will fire at most once throughout the entire game.

Every turn, if Joan had not managed the player and Joan has managed the player, say “Pleased to meet you.”

The condition must appear in every turn or as a scene begin/end point because that is the only time during a turn that past-perfect differs from its present-perfect twin. But, we cannot do the following.

Every turn, if Bob had managed the player and Bob has not managed the player, say “So long forever!”

The not moved, but that rule never fires. For that rule to fire, the perfect tense would need to transition from false to true, which perfect tenses don't do, by definition. Had is always what has used to be. So in the first condition had is saying that has used to be true, while the second condition says that has is false right now. It's a contradiction.

Even when used alone, negating the perfect tenses can be counterintuitive. Constructions like if we have not trusted do not mean “if there was a time when we did not trust”, but rather, “if we have yet to trust”. It is true at the start of the game and becomes permanently false the first time we trust, as opposed to being false at the start of the game and becoming true the first time distrusting happens. (For that effect, a distrusting action really is needed, and likely a relation the twin actions set and unset so it is possible to tell which action happened the most recently.)

If this still isn't clear, I can only recommend circuit timing diagrams. Suffice to say, the perfect tenses are good for knowledge and plot points, the past tenses are good for recognizing world-state changes by bracketing, and when put together we can recognize additions to knowledge.

Combining tenses with occurrences. By these rules, it seems that if we have taken the candle twice would never fire, because we have taken, once becoming true, stays true for the rest of the game. Since it doesn't become false again, it cannot become true again, so twice is never satisfied. However, this is special-cased to work as it looks like it should.

Every turn when we have eaten the slow-acting poison for 5 turns: say "You start to feel ill."

Every turn when we have eaten the slow-acting poison for at least 6 turns: say "You still feel ill."

Initial State.

The Future is Scheduled. We can schedule a rule to fire in the future, either by hard-coding the rule to the in-game clock:

At 12:00 PM: say "The lunch bell rings!"

Or by imperatively providing a time with "at":

Carry out setting the watch to: the watch will beep at the time understood.

At the time when the watch will beep: say "Your Casio beeps at you urgently."

Or by imperatively providing a countdown, in either turns or minutes, with "in . . . from now":

Carry out pushing the watch: the watch will beep in six minutes from now.

Carry out pushing the watch: the watch will beep in six turns from now.

At the time when the watch will beep: say "Your Casio beeps at you urgently."

In the above example, "the watch will beep" is an implicitly created rule in an opaque pseudo-rulebook called "at" or "at the time when".

Out of world actions do not affect time.

boo It's possible to define the same verb as both action and relation. The closest to ambiguity that can be reached is the ungrammatical if Bob watching Junior, which means the same as if Bob is watching Junior, which is clearly a relation. Without the relation, the former will not even compile. NPC actions in if statements require trying: if Bob trying watching Junior. Likewise changing the subject to the player, which will always be a relation test, or we are/have, which will always be an action test. Since the purpose of almost all actions is to set or unset a relation, using the same verb for both the relation and the action which sets it reduces our cognitive load.

> Grammar Gotchas _

The articles "the", "an", and "a" are almost always optional. We can think of them as a peculiar kind of whitespace. But there are a few exceptions where articles are either significant or required. First, "the" (not "a" or "an") is required when defining a rule's name.

[..] (this is the my favorite rule): [...]

Second, "a" (not "the" or "an") is required in front of the word "random".

let N be a random number from 1 to 5;

Third, "an" (not "the" or "a") is required in front of the word "actor" when in the subject of a rule header. Though the others will compile, they will compile as reading the current value of the variable "actor" and comparing it to itself, rather than skipping the condition altogether as it should. This almost works, except when the player is performing an action, the variable "actor" is set to nothing (NULL). This also means that Descriptions in the subject won't match the player.

Report an actor jumping: [...]. [OK; catches everyone]

Report actor jumping: [...]. [won't catch the player]

Report a laconic person examining: [...]. [won't catch the player]

Finally, articles in an action's or activity's name are captured, so will remain required. This is because actions and activities are intended to begin with a verb or participle, such as "printing" or "asking". So as a general rule, do not begin an action's or activity's name with an article, nor name them after nouns or noun phrases.

The speech engine is an activity. [ "the" appears, so will always be required ]

Before speech engine: [error: unknown rulebook, action, or activity]

Before the speech engine: [correct]

Speech engine is an activity. [ this definition allows both of the above rules ]

The last is a common error with activities because their invocation begs for a "the":	carry out the speaking engine activity;

Object names can unfortunately occlude one another. If we have an object "car", and then an object "car key", it frequently happens that the car cannot be referred to. Inform supplies objects with a property, "privately-named", which will not automatically export an object's source code name to the player's parser; an explicit Understand As line will be required.

The words "rules" and "rulebook" are exactly synonymous in source code. Though programmers know that a list of items isn't the same as the items themselves -- an empty list is still a space-using construct, even when no items exist to use space -- non-programmers would call it a distinction without a difference. ("A grocery list without items isn't a grocery list; it's blank paper.") So "rules" is synonymous with "rulebook" in source code.

Relatedly, because rules compose rulebooks, and rulebooks compose actions, the terms are sometimes used seemingly interchangeably. Know that this is an allowance to the non-programmer, who is interested in "the reason the action failed", even though "the rule that caused the action's rulebook to fail" is more correct in most instances, and "the non-anonymous rule that most recently returned failure" is completely correct. Likewise for "if the rule succeeded" and its many cousins; it may be worth noting that the middleman here, "rulebook", is almost never explicitly mentioned where either the base-level "rule" or the top-level "action" could instead be used. Hence, "stop the action" means "rule fails", and "continue the action" means "make no decision". The sole exception, "the outcome of the rulebook" (synonymous with "the result of the rule") makes sense since the outcome/result of a protagonist action would be a permanent change in world-state.

Finally, know that a rule variable can hold either a rule or a rulebook, but a rulebook variable can only hold a rulebook -- not a rule.

My favorite rule is a rule that varies.

My favorite book is a rulebook that varies.

change my favorite rule to the can't walk through closed doors rule; [OK]

change my favorite rule to the every turn rulebook; [OK]

change my favorite book to the every turn rulebook; [OK]

change my favorite book to the can't walk through closed doors rule; [type mismatch error!]

This may be counter-intuitive to those of us who love our polymorphism, which states the more general type can accept itself as well as its subclasses. One way of viewing this is that polymorphism works on the is-a relation, while rulebooks & rules associate through the has-a relation. Alternately, anything that can be done to a item can be done to a collection by doing it to every item in that collection, but doing something specific to a collection -- like ignoring its third part -- makes no sense when applied directly to a single item.

And a final note about actual whitespace. First, even if we don't use the Python style of code block demarcation, tabs are required between table columns. (One tab will absorb all other whitespace touching it, however, so we can manually format tables to look well.) Secondly, a blank line is significant: it will end an imperative flow (assuming we didn't end it properly with a period), and one is required both before & after a table or a section heading.

Very occasionally, the compiler will have difficulty parsing an invocation that has a NPC as a subject. In these cases, add the word "trying" before the action: "Bob trying examining the player". It frequently happens in Tables with a Stored Action column.

A verb ending in -ed may be acting as an adjective. Observe the given example in chapter 9.13 of the manual, which gives this example for the simple past tense.

if the lantern was switched on, change the lantern to switched off;

if the lantern was switched off, change the lantern to switched on;

This example can be misleading due to the identical forms of passive voice and participial adjectives in English. In other words, we can parse that as either "if (the lantern) (was switched) (on)" or "if (the lantern) (was) (switched on)". After all, there is both a property called "switched on / switched off" as well as two actions that set the relation either way, "switching on" and "switching off", with the past participles "switched on" and "switched off". So are we referring to the properties or to the actions up there?

The answer is: the properties. Verbs of change -- Actions -- are never in any form of past tense. They are either present continuous tense "[we are] switching" or present-perfect tense "we have switched", never in simple past tense 'we switched' or in past-perfect tense 'we had switched'. Furthermore, actions require "we have" when using its tensed variation. Long story short: a word ending in -ed does not guarantee past tense. It could be the present-perfect.

There is a difference between the following valid lines of Inform:

if the lantern was switched on,

if we have switched on the lantern,

Categorizing tense properly is essential, because the used tense determines the implementation and limitations. The first line is in simple past tense, which holds the previous turn's world-state. This means that past tenses change every turn. The second line is in present-perfect tense, which holds a truth about the present: once we have done an action to a thing, it always, for the rest of the game, remains true that we have done it. Even if it was later undone, the fact that we once did it remains true. This means the two lines act quite differently, the first being an echo of the previous turn's "if the lantern is (switched on)", and the latter asking if the switching on action had ever been used on the lantern.

> Paradigm Leaning _

Given its hybrid nature, we must watch ourselves when we code algorithms. Sometimes Inform's declarative features are more elegant than doing the same work imperatively, but other times, its domain-specific nature frequently prevents higher-order programming algorithms. Here are a few examples that, like GOTO, probably signal a "wrong way" to do something.

Rules aren't Functions.

This is the foobar rule:

[...];

[...].

The named but non-headered rule implies we are thinking too procedurally. Whatever invokes that rule is itself invoked at a particular time under particular circumstances, so those circumstances should be put in the header. Even if the rule is invoked from multiple places, at least one place can use the header. A possible exception would be:

The foobar rule is listed instead of the X rule in the Y rulebook.

...in which case the foobar rule will steal the replaced rule's header.

Callbacks in the Rulebook Paradigm.

The callback rules are a rulebook. [usually empty]

To foobar:

ponder foo;

consider the callback rulebook;

mull over bar.

This implies we're halfway between the procedural and rule-based paradigms. The fix here is usually to put the two pieces of imperative code into rules of their own, and the whole To phrase becomes a rulebook itself.

The foobar rules are a rulebook.

Foobar rule (this is the pre-callback work rule): ponder foo.

Foobar rule (this is the post-callback work rule): mull over bar.

Now client code may insert code in a variety of places, and even replace the imperative sections as well, if desired.

Declarative Lists... Sometimes. Building a list is one of the more onerous things to do imperatively: declare an empty list, loop through some items evaluating and possibly adding some of them to the list, pass the list to where it's needed (always elsewhere, because if it were right here we'd simply loop & use immediately), use the list via another loop, and remember to deallocate the list at the right time & place to avoid memory leaks. If we're building a list of objects in Inform, the proper way is to use a collection of adjectives on the loop that would use the list:

repeat with associate running through every chatty not grumpy spiffy person in the location who is not the player:

say "Hi [associate]."

Or, at the very least, and probably using a global variable:

let L be a list of every chatty not grumpy spiffy person in the location who is not the player;

change my friends list to the list of every chatty not grumpy spiffy person in the location who is not the player;

> Replacing Sections of Inform 7 Source Code _

Inform has several ways that deeper changes can be effected into the language.

The first is the various activities, as previously seen. Most activities are a single function dressed up with hooks and such so code can easily be inserted to preempt the default behavior.

Second is replacing named sections of preexisting extensions, including the Standard Rules.

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

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

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

Though we'll have to be careful of causing compiler errors and such, a good extension writer will break up the extension into names sections in order to facilitate replace-ability. Also, all the most basic information on the class hierarchy, the built-in actions, variables, etc., of Inform 7 is found in an automatically included extension, the Standard Rules. In there, we find definitions like:

Section SR1/3 - Things

A thing can be privately-named or publically-named. A thing is usually publically-named.

A thing can be plural-named or singular-named. A thing is usually singular-named.

A thing can be proper-named or improper-named. A thing is usually improper-named.

A thing can be described or undescribed. A thing is usually described.

A thing has a text called an indefinite article.

A thing has a text called a description.

A thing has a text called an initial appearance.

A thing has a text called printed name.

A thing has a text called a printed plural name.

That's only a small excerpt from the definition of the Thing class, but you get the idea. The standard rules can be changed just like any other extension:

Section 8 - My thing class (in place of Section SR1/3 - Things in the Standard Rules by Graham Nelson)

Avoiding compiler errors by changing so much of the most basic assumptions of the code library is difficult, but the option is open to us.

> Facing Inform 6 _

All of an Inform 7 project compiles to Inform 6 source code before compiling again to assembly. This means all of Inform 7's constructs are implemented in Inform 6 somehow. For example, a rule is a boolean function that takes no passed-in parameters -- action variables like "the noun" and "the second noun" are global, while local variables are on the stack -- so a rulebook is an array of function pointers. Larger structures such as actions and activities are composed of several rulebooks. Object instantiations are connected together by linked-list pointers, so a set-description may loop through them. Each set-description compiles to a unique function containing a loop header, and like generator functions in functional programming, they return the first applicable value that passes muster. (The calling code, which has the loop body, is responsible for informing the set-description where it left off so it can find the next applicable value.) Meanwhile, scenes, which can have properties just like objects, are implemented as several different arrays, one per property. So a scene name is just a named value, an index into those arrays. And because a single table column's entries all have the same type, a table column is an array plus a few header bytes, while a table is an array pointing to those columns. And so on and so forth.

The implementation for all these constructs is found in the template files within the Inform application. These text files, which have the extension i6t, we can modify from our Inform 7 source similar to section headings. We can replace parts of them, or insert additional bits between them.

Include (- ... blah blah blah... -) before "Relations.i6t".

Include (- ... blah blah blah... -) instead of "Relations.i6t".

Include (- ... blah blah blah... -) after "Symmetric One To One Relations" in "Relations.i6t".

Usually we just need to pull out a bit of useful information or add in a useful line in the generated source. The commonest way is by creating a to-phrase or to-decide function whose entire body is Inform 6 code between the (- and -) markers. This inserts the exact text into the compiled Inform 6. So, generally, to-phrases must end in a semicolon, while to-decide functions, which are frequently if-conditions or r-values, must not.

To decide what number is the chosen table row: (- ct_1 -).

To decide what number is the first misunderstood parser word: (- (wn - 1) -)

To decide which number is (x - a number) ORed with (y - a number): (- ({x} | {y}) -).

To really clear the screen: (- VM_ClearScreen(0); statuswin_cursize = 0; -)

Parameters go between curly braces. There's two parameter types useable here unavailable to pure Inform 7. Condition is something appropriate to follow an if. Action compiles to an invocation of TryAction(). Inline assembly may be included amongst the Inform 6 like any other statement. Assembly opcodes always begin with a @ sign.

To do this: (- do { -). [ not ending with a semicolon here, obviously ]

To until (C - a condition): (- } until {C}; -).

To push (x - a word value) onto the stack: (- @push {x}; -).

To pull (x - a word value) from the stack: (- @pull {x}; -).

Other Inform7 variables may be accessed by placing the name between (+ and +) markers. Rules may be invoked by following the markers with empty parenthesis, since rules never take a parameter. Named to-phrases expand, not to the function, but to an array of metadata about the function. Index 1 holds the function pointer, so the syntax would resemble ((+ my I7 phrase +)-->1)( ... any parameters ... ) while indexes 0 and 2 hold the type and printable name, respectively.

An extended example: the author wants to save actions for later display or execution from a hint system or CYOA menu. One goal is as always a nice Inform 7 syntax, preferably without using the action of keywords that herald a stored action. So he reaches for the action parameter type, which requires an Inform 6 inclusion, then reflects the Inform 6 right back into an Inform 7 to-phrase, which has all five parameters of the TryAction() invocation, plus two new parameters: a description of people, and whichever rule is currently held in his extra behavior variable.

The first line here shows the resulting syntax within a Before rule.

Before an actor opening something locked, a strong person in the location could try attacking the noun.

The extra behavior is a rule that varies.

To (P - a description of people) could try (invocation - action):

(- Could{invocation}{-backspace}{-backspace}, {P}, 0 ); -).

To (P - a description of people) could not try (invocation - action):

(- Could{invocation}{-backspace}{-backspace}, {P}, (+ extra behavior +) ); -).

Include (-

[ CouldTryAction req actr act n sn desc exbehvr;

((+ remembering for later +)-->1)(req, actr, act, n, sn, desc, exbehvr);

];

-).

To (requested - truth state) intention by (dont-use-this - a person) considering (possible-action - an action name) via (possible-noun - an object) & (possible-second-noun - an object) by any able-bodied (faction - a description of people) with (behavior - a rule) (this is remembering for later):

[ .. and so on ... ]

After Inform 7 expands the parameter {invocation} to TryAction(v,w,x,y,z); the pair of {-backspace} macros erase the semicolon and closing parenthesis so additional parameters could be added. Furthermore, we simply prepend the word "Could" in front of the function name to form a different function name altogether, CouldTryAction(), which we instructed to call the complicated to-phrase.

The last use of the (- and -) markers is to create a compile-time assertion, which Inform 7 calls "use options". To use the following we'd just assert it like any other use option: Use the American dialect, RULES ALL at start, and no scoring.

Use RULES ALL at start translates as (- Global debug_rules=2; -).

The line will be included if the source includes the use option, otherwise not.

The other way of tinkering with Inform 6 is to expose a pre-existing variable, function, etc. by naming it with an Inform 7 name. Unlike the methods above, this allows us to assign to variables directly.

Out-of-world is a truth state that varies.

The out-of-world variable translates to I6 as "meta".

The currently-executing action is an action name that varies.

The currently-executing action variable translates into I6 as "action".

Properties, rules, understand tokens, Definition: adjectives, instantiations, and classes may be translated similarly. Translating is necessary because the generated I6 names differ from their I7 counterparts to prevent any unfortunate name clashes. But because I6 implements much of I7, tinkering requires communication between the layers. One example is new tokens for use in understand assertions, which inform the parser, written solely in Inform 6.

The understand token subordinating conjunction translates into I6 as "SUB_CONJ_TOKEN".

Include (-

[ SUB_CONJ_TOKEN;

return ((+ parsing the sub conj +)-->1)();

];

-).

To decide which number is parse succeeds: (- GPR_PREPOSITION -).

To decide which number is parse fails: (- GPR_FAIL -).

To decide which number is parse the sub conj (this is parsing the sub conj):

repeat through the table of subordinating conjunctions:

if the unmatched word matches the topic entry:

now the sub conj is the output entry;

decide on parse succeeds;

decide on parse fails.

We can declare global I6 variables from Inform 7, and not expose them to Inform 7 if we wish.

Include (-

Global save_debug_rules;

-).

When Inform 7 is creating Inform 6 code, it recognizes a few macros beside just {-backspace}. Although innocuous enough, these facilities open up whole new categories of things phrases can do. Counters are the first. Each time a phrase uses {-advance-counter:FOOBAR}, the current value of the number variable FOOBAR replaces it as a constant literal, and FOOBAR is then post-incremented. The variable is inside the Inform 7 compiler, not in our source code (either I7 or I6). One example of its use is debugging. Let's say we have a complicated I6 inclusion that crashes with a runtime error, but only sometimes. We use the phrase in three different places in our code, and know not which is causing the problem. We could define it like so.

To do complicated thing:

(-	print "invocation #", {-advance-counter:BigThing}, "^";

! blah blah blah

-).

When play begins, do complicated thing.

Every turn, do complicated thing.

Each place that "do complicated thing" appears in the source has its own number, starting from zero. We can also put the macro next to a variable name, like myvar{-advance-counter:MyVarCount}, so the resulting Inform 6 code references variables myvar0, myvar1, etc.

Related are {-zero-counter:FOOBAR} which sets the counter back to zero, and {-counter:FOOBAR} which becomes the number without increasing the number afterward. Just to be clear, {-advance-counter:FOOBAR} post-increments, and in case that causes a problem, it can be placed in an Inform 6 comment, where its expansion is ignored.

Finally in this series on counters is {-allocate-storage:FOOBAR}. The above counters only existed in our resulting Inform 6 source as constants, but this instruction creates actual storage space in our Inform 6 source, an array called I7_ST_FOOBAR, which has at least the number of elements as the FOOBAR counter. The counter is how each I7 phrase invocation knows which array element belongs to it, so I7_ST_FOOBAR-->{-advance-counter:FOOBAR} appears in our definition precisely once. Should we need to reference storage multiple times in the same definition, it appears last (because it post-increments) and one or more I7_ST_FOOBAR-->{-counter:FOOBAR} appear. For example, if our phrase defines a new kind of loop, and we want the loops to be able to nest, this construction solves our problem.

To repeat with (R - nonexisting rule variable) running through future events begin -- end:

(-

{-allocate-storage:LoopingThruEvents} ! expands to nothing, and no further effect for multiple appearances

for ( I7_ST_LoopingThruEvents-->{-counter:LoopingThruEvents} = 1

: I7_ST_LoopingThruEvents-->{-counter:LoopingThruEvents} <= TimedEventsTable-->0

: (I7_ST_LoopingThruEvents-->{-counter:LoopingThruEvents})++ )

if (({R} = TimedEventsTable-->(I7_ST_LoopingThruEvents-->{-advance-counter:LoopingThruEvents})) ~= 0)

-). [ that's an assignment inside the condition ]

And finally, almost as an afterthought: occasionally we write phrases for tables. Tables require some local variables, such as ct_1. The macro {-require-ctvs} tells Inform to create said variables.

This is only most of Inform 7. It is a large language with many nooks and crannies to explore. Finding them is frequently a game in itself. I hope you find it as enjoyable as I have.

READY.

> _