The Rules of Inform 7

In this post, I’ll continue on the exploration of Inform 7 that I started in the introductory post. Here I’ll continue to add to the game source text started in that post, putting emphasis on rules. Rules are one of the keys aspects — the other being actions — of how Inform 7 allows authors to interact with their game players.

Creating a work of textual IF requires you to understand that you are creating a model world. You probably saw the movie The Matrix, right? In that film, there was a simulated world that people wandered through and did things in; this was a world that was created by “The Architect.” Well, that’s sort of what you’re doing: you, as the author/architect are creating a simulated world that you will populate with various objects and characters. There is one such character (provided to you by Inform) that the player is going to control. In gaming terms this would be called the player character. In fiction terms this would be called the protagonist.

The model world you create will have an initial state. The initial state is what you assert, as an author, in your source text. You write statements that say what locations exist, what things exist in those locations, and how those things are situated relative to each other. This is what you saw in the introductory post.

However, once you introduce characters and events and start the game going, your model world will evolve from its initial state. This most noticeably occurs when the player starts interacting with your world as the player character. The player will pick things up, move around to different locations, open doors, light things on fire, inexplicably fight a dragon with only their fists, and so on. Thus will your model world have to evolve with player actions. You’ll handle how the world evolves the same way you handled the initial state: by writing source text. The difference is that your source text will now focus on creating rules that will be used based on certain circumstances occurring in the world model, including the actions of the player.

Rules are fundamental to Inform and yet most guides on the system take their time getting around to discussing them in a systematic way. I’ve found this often makes people wary of rules, thinking they are more complicated than they are. The official Inform 7 manual (called Writing with Inform) gives many examples of rule usage but does so in the context of mini-games, thus sometimes losing the trees in an attempt to present the forest. So here I’m going to buck the trend and start off with rules just to expose you to them.

Welcome to a World …

Let’s start off with a slightly modified source text from which you ended the last post:

The Learning Lab is a room.

The Office is a room.
The Office is east of the Learning Lab.

A shredder is in the Office.

… With Rules

Now let’s add some rules. At the bottom of your source text, put the following:

A when play begins rule: say "Rule for when play begins."
An every turn rule: say "Rule for every turn."

Test me with "wait / wait".

The “test me” statement is a really cool feature. With this, what you can do is start the game and then type the command test me. What this will do is run the commands provided to the “test me with” statement. So my test above simulates a player typing wait twice. I’ll use this ‘test me’ feature a lot to showcase different aspects of Inform. Try it out now: start the game and then type test me.

As a reminder, to start the game you can press the “Go” toolbar button, press F5 (if on Windows) or Command+R (if on Mac).

With this example, consider the resulting game output (with a few bits highlighted to call them out):

Rule for when play begins.

Learning Lab
An Interactive Fiction by Jeff Nyman
Release 1 / Serial number 140612 / Inform 7 build 6L02 (I6/v6.33 lib 6/12N) SD

Learning Lab

>test me
(Testing.)

>[1] wait
Time passes.

Rule for every turn.

>[2] wait
Time passes.

Rule for every turn.

>

Here two rules have been specified. One is a rule that applies just once (“when play begins”) and another is a rule that applies repeatedly (“every turn”). Just to be clear, the “passage of time” in most text games is broken up into a succession of turns. Each turn is comprised of the player entering an action to the game and the game giving a response as a the result of that action.

The structure of a rule is essentially a circumstance and then a set of phrases or statements that should be carried out if that circumstance occurs. A colon separates the circumstance from the statements. The circumstances of my above rules are “when play begins” and “every turn”. The surrounding text of “A/an … rule” exists simply to clarify what is being described. I’ll come back to that later. In my case, I only have one statement that applies in each circumstance. Both rules simply use the built-in say statement to produce some text. (If you come from a programming background, ‘say’ is like puts in Ruby, print in Python or System.out.println in Java.)

Inform Tip! A rule always starts with a circumstance or situation for which that rule applies to (“when play begins”, “every turn”), and then follows that with one or more phrases that say what to do when that situation or circumstance occurs in the game.

You can see, from the highlights in the above example, where the rules are firing in the course of play. When a game written in Inform 7 is playing, it is essentially being run through a very large rules engine. At one point, the Writing with Inform manual says:

Inform is built on a mass of several hundred rules, some quite complex, and it could even be said that Inform is that mass of rules.

It also says:

When we open the casing and look inside the machinery of Inform, what we see are rules and rulebooks.

Rules and Rulebooks

So, taking what the manual says and going back to our source text, understand that there is a “when play begins” rulebook. The rules in this rulebook are checked only at the start of a game. There is also an “every turn” rulebook. The rules in this rulebook are checked every turn, meaning after the player has typed a command and a response has been generated for that command.

Something might strike you as odd. I just said that “when play begins” and “every turn” are rulebooks but you can also see that in the source text I talked about a “when play begins” rule and an “every turn” rule. So are those rules or rulebooks? Well, both, in a way. The “when play begins” rulebook is filled with rules called, perhaps not surprisingly, “when play begins”. Likewise, the “every turn” rulebook is filled with “every turn” rules.

To play around with this concept a bit, replace your existing rules with these:

A when play begins rule: say "First rule for when play begins."
A when play begins rule: say "Second rule for when play begins."

An every turn rule: say "First rule for every turn."
An every turn rule: say "Second rule for every turn."

Here I’ve simply declared two of each type of rule and changed the ‘say’ text a bit so I can see what’s happening. You can run this again but I’ll show you another nice trick here while learning.

Instead of pressing “Go” (or F5 / Command+R) you can press the “Replay” icon (two swirly arrows). The shortcut for this is F9 (on Windows) or Option+Command+R (on Mac). What this does is start the game and replay it with the last commands you played with, which if you’ve been following along was test me. So if you are experimenting like this and always use a ‘test me’ statement, you can just keep making changes and hit the reply shortcut key, which will replay your test. From a programming point of view, you could think of ‘test me’ as sort of like running unit tests for each build of your game. It’s actually more like integration or even acceptance tests, but we don’t need to get hung up on that here.

Here’s the output you should see:

First rule for when play begins.

Second rule for when play begins.

Learning Lab
An Interactive Fiction by Jeff Nyman
Release 1 / Serial number 140612 / Inform 7 build 6L02 (I6/v6.33 lib 6/12N) SD

Learning Lab

>test me
(Testing.)

>[1] wait
Time passes.

First rule for every turn.

Second rule for every turn.

>[2] wait
Time passes.

First rule for every turn.

Second rule for every turn.

>

Each rule is fired off as the output clearly shows.

Okay, but how does Inform determine the order to fire those rules off in, given that they are identically worded? Without any information to the contrary, Inform will use the ordering that it finds in the source text. You can test this simply by changing the order of the statements. Put the “second” statement before the “first” and replay again to see what happens.

Now, I said “without any information to the contrary.” So what would contrary information be? To understand that, first understand that you can give rules specific names. Let’s try that out with our source text. Change the rule statements to this:

A when play begins rule (this is the first starting rule): say "First rule for when play begins."
A when play begins rule (this is the second starting rule): say "Second rule for when play begins."

An every turn rule (this is the first turn rule): say "First rule for every turn."
An every turn rule (this is the second turn rule): say "Second rule for every turn."

Here I simply named the rules something specific but this has no immediate impact on the output or how the rules are fired. Replay the ‘test me’ to see that for yourself.

So if this has no effect, why did I bother doing it? Giving a rule a name allows you to refer to it. And if you can refer to a rule, you can determine some aspects about how it is placed in a rulebook. For example, add the following:

A when play begins rule (this is the first starting rule): say "First rule for when play begins."
A when play begins rule (this is the second starting rule): say "Second rule for when play begins."

An every turn rule (this is the first turn rule): say "First rule for every turn."
An every turn rule (this is the second turn rule): say "Second rule for every turn."

The second starting rule is listed first in the when play begins rules.
The second turn rule is listed first in the every turn rules.

Test me with "wait / wait".

Now if you replay the game, you’ll get this output:

Second rule for when play begins.

First rule for when play begins.

Learning Lab
An Interactive Fiction by Jeff Nyman
Release 1 / Serial number 140612 / Inform 7 build 6L02 (I6/v6.33 lib 6/12N) SD

Learning Lab

>test me
(Testing.)

>[1] wait
Time passes.

Second rule for every turn.

First rule for every turn.

>[2] wait
Time passes.

Second rule for every turn.

First rule for every turn.

>

Notice here that I controlled how the rules are being fired but I didn’t rely on any source text positioning.

Inform gives you a visual representation of the rulebook as well. To see this, in the right pane of the interface, click the Index tab. Then click the Rules button. If you look Rules added to the sequence of play you’ll see the every turn and when play begins rulebooks with a visual like this:

Now take out the last two statements I just had you add regarding where the rules are listed. And here I’ll show you another way to compile: if you click F7, you can do what’s called “refreshing the index.” What this does is basically recompile the game but does not play it. If you do that and then check the same area of Index/Rules again, you’ll see the representation is now:

Notice how the rules are now back to their original order. The overall “Index” that Inform maintains provides you a lot of information about how Inform is structuring your game. Feel free to look at the various areas under the Index tab to get familiar with what Inform provides. I’ll cover various aspects if and when it seems relevant but I won’t be doing a systematic exploration of the Inform index.

Inform Tip! This ability to name rules and determine where they fit in a given rulebook is a critical aspect of Inform 7. Admittedly, right now you are getting just the smallest possible view into that but what I’m trying to do here is remove any of the mystery or fear that sometimes springs up around rules. They really are very easy things to create and use.

Okay, so let’s step back a bit. First of all, let’s clean up and just go back to this source text:

The Learning Lab is a room.

The Office is a room.
The Office is east of the Learning Lab.

A shredder is in the office.

A when play begins rule: say "Rule for when play begins."
An every turn rule: say "Rule for every turn."

Test me with "wait / wait".

We’re back to using nameless rules here. That’s actually okay for these kinds of rules because, unless you are doing something where you have to situate the rules specifically in a rulebook, you don’t need to give them names. The above nameless rules are identified in such a way that Inform knows to tuck the first one into the “when play begins” rulebook and the other in the “every turn” rulebook. Due to being able to figure this out, Inform lets you shorten the phrasing a bit. Earlier I had said that the surrounding text of “A/an … rule” exists to clarify what is being described with the statement. That text is optional, however, and to see that, replace the rules with these:

When play begins: say "Rule for when play begins."
Every turn: say "Rule for every turn."

Feel free to replay the game and make sure everything is working as it should. (See how handy that “test me” command is?)

Clauses on Rules

You can apply conditions to rules by attaching clauses to them. This lets you further conditionalize the situation that the rule will fire under. You will start clauses by attaching a conditional word and then a description. The conditional word will be one of the following: in, when, while, during. I’ll take a look at each here.

Add the following rule to the source text and update the test statement:

Every turn when the player is in the Learning Lab: say "Every turn rule that applies only to the Learning Lab."

Test me with "wait / wait / east / wait".

Here is the output you would see (starting from execution of the “test me” command):

>test me
(Testing.)

>[1] wait
Time passes.

Every turn rule that applies only to the Learning Lab.

Rule for every turn.

>[2] wait
Time passes.

Every turn rule that applies only to the Learning Lab.

Rule for every turn.

>[3] east

Office
You can see a shredder here.

Rule for every turn.

>[4] wait
Time passes.

Rule for every turn.

>

With that output you can see that certain rules only fire when certain conditions are met, such as the player being in a specific location (“when the player is in the Learning Lab”). In fact, when using an “in” clause like this, Inform assumes that the subject is the player, so the above rule could be shortened to:

Every turn in the Learning Lab: say "Every turn rule that applies only to the Learning Lab."

Take out the rule you just added and replace it with this one:

Every turn while the player can see the shredder: say "Every turn rule that applies only when the player can see the shredder."

Here is the output you would see (starting from execution of the “test me” command):

>test me
(Testing.)

>[1] wait
Time passes.

Rule for every turn.

>[2] wait
Time passes.

Rule for every turn.

>[3] east

Office
You can see a shredder here.

Every turn rule that applies only when the player can see the shredder.

Rule for every turn.

>[4] wait
Time passes.

Every turn rule that applies only when the player can see the shredder.

Rule for every turn.

>

Here again we can see that certain rules only fire when certain conditions are met, such as while the player can see a specific item (“while the player can see the shredder”). Incidentally, the “while” and “when” could have been interchanged in both of the rules we just looked at. Or both could have used “when” or both could have used “while”. Generally you do what you feel reads better. The “while the player can see the shredder” clause can be shortened a bit as well, as such:

Every turn while the shredder is visible: say "Every turn rule that applies only when the player can see the shredder."

Again, Inform makes the assumption that without any information to the contrary the statement applies to the player. (Or, rather, player character. But you get the idea.) Remove the last rule you just added so we can look at the next part, which is the “during” clause.

Conditionalizing a rule with a “during” clause is a bit more interesting. This will require introducing you to the concept of a scene. For now, I’m not going to worry about how scenes work so, don’t worry too much about that. Just add the following to your source text:

Getting to work is a scene.
Getting to work begins when the player is in the Learning Lab for the second time.

Now add the following rule along with the updated test me:

Every turn during getting to work: say "Every turn rule that applies only during the getting to work scene."

Test me with "wait / wait / east / wait / west / wait".

Here’s the relevant part of the output that you should observe:

>[5] west

Learning Lab
Every turn rule that applies only during the getting to work scene.

Rule for every turn.

>[6] wait
Time passes.

Every turn rule that applies only during the getting to work scene.

Rule for every turn.

>

Note that, in your source text, the scene indicates when it begins, which is only when the player goes to the Learning Lab for the second time. So when the game starts out, the rule is not applicable. The player is in the Learning Lab for the first time. But when the player goes east and then west, they are now in the Learning Lab for the second time. Now the newly added rule is fired because the clause that conditionalizes the rule is true, which is what the above output shows.

Incidentally, the same effect could have been achieved without using scenes simply by doing this:

Every turn when in the Learning Lab for the second time: say "Every turn rule that applies only to the Learning Lab for the second time."

However, that uses “when” to conditionalize the rule. If you want to use “during” that means you have to say “during what context” and, to Inform, the “what context” means a scene.

Inform Tip! Along with the above ideas of naming rules and placing them within rulebooks, conditionalizing rules with clauses so that those rules only apply in very specific circumstances is key to understanding how Inform works.

Pause and Absorb

This is a good stopping point for now. You have the basis for how rules work. I would recommend making sure you understand the above, not just conceptually but also in terms of why things worked as they did. I can’t stress enough that spending some up-front time learning what appears to be some simple basics will pay off if you continue to explore Inform.

What I’ve covered here really just scratches the surface of what you can do with Inform and perhaps the last bit with the scene gives you an idea of how expressive you can be. The good news is that you now have the entire basis for how rules work. Everything else about rules follows on from what you learned here. The above was the foundation.

So far the actions of my examples have been somewhat passive in terms of how rules are being used. All rules have fired automatically based upon a condition that was not dictated overly much by the player actions. In the next post I’ll get into more specific actions that the player can take and how rules allow you to create a dynamic experience for the player by reacting to what they do in different ways.

Oh, And For You Testers and Developers …

As a side note to testers and developers, I would encourage you to think about what a testing tool would be like that was rules-based like this. Would that be useful? Imagine a system like Cucumber or SpecFlow and how they might work if they didn’t use a simple structuring language like Gherkin but rather utilized a rules-based approach to stating conditions that a system could be in and what particular types of tests should be run if those conditions occur. Consider if a natural language system like Inform could have applicability wherein English statements aren’t just matched, as they are in BDD tools, but where the statements themselves are the code.

About Jeff Nyman

Anything I put here is an approximation of the truth. You're getting a particular view of myself ... and it's the view I'm choosing to present to you. If you've never met me before in person, please realize I'm not the same in person as I am in writing. That's because I can only put part of myself down into words. If you have met me before in person then I'd ask you to consider that the view you've formed that way and the view you come to by reading what I say here may, in fact, both be true. I'd advise that you not automatically discard either viewpoint when they conflict or accept either as truth when they agree.
This entry was posted in Inform 7. Bookmark the permalink.

3 Responses to The Rules of Inform 7

  1. Joris says:

    Hi Jeff, I really enjoyed this post and the previous one about Inform 7, and the fascinating possibility of using a similar system for defining and executing testcases.

    I have been thinking on and off about a similar though different use, namely using something like Inform 7 to define software requirements. Not only would that ensure requirements are expressed more formally, it would also open up the possibility to run automated tests against the requirements themselves, using something like the Inform 7 testing support.

    Type-safe, strictly structured testable requirements sounds quite heavenly…

    • Jeff Nyman says:

      I agree. In fact, for me testing is a design activity, and thus the elaborated requirements are the tests. Thus if I can write the tests in a tool like this, I’m essentially writing the requirements at the same time. Perhaps interestingly, I did try this once with a test solution I called TestNLP. You can see the (admittedly embarrassing) example of this here: http://testerstories.com/portfolio/assets/docs/AUTO_TestNLP_Examples.pdf. It’s heavily annotated with comments; you’ll see it’s very similar in structure to Inform 7 but you’ll also see its much more in line with the technical specification rather than the BDD-type requirements-as-tests that are common now with Cucumber, SpecFlow, and related tools.

  2. Mark Anderson says:

    Jeff,

    Please revisit these Inform 7 tutorials.  Your presentation and teaching style are perfect.  Sometimes the examples that come with Inform are confusing.

Leave a Reply

Your email address will not be published. Required fields are marked *