The loop-de-loop.
How do I hold all of these things.
Hello, fellow beginners!
Sometimes, we need to do something to a number of things or objects all at once. Maybe we’d like to check and see how many things have a property. We might want a list of the location of every thing in the game. Or in a region. We might want to change a value or number that multiple things or objects currently have applied.
This always happens during action processing rules. Let’s have a look at something that we can talk through.
lab is a room.
an apple is in lab.
a ball is in lab.
a hat is in lab.
this is the examination check rule:
repeat with T running through things:
say "[t]: [if we have examined t]examined[otherwise if we have not examined t]unexamined[end if].";
say line break;
after looking when we have not looked:
follow the examination check rule;
continue the action;
every turn:
follow the examination check rule;
We start with a room, “lab.” Lab is a popular choice for programs like this. It’s usually accurate, for one thing. At three characters, it is also a lot easier to type than “laboratory.”
Next, we declare that some things are in the lab: an apple, a ball, a hat. Unmentioned but present is the player, who is also a thing in the lab (a person is a kind of thing in Inform terms).
You’re with me so far, right? Let’s have a look at some substantial (and possibly new for some of us) code.
I chose to declare a rule instead of making a specific action-processing rule. That’s because I want to run the code in multiple places. There’s no special trick to it. All we have to do is say
this is the examination check rule:
I could have called the rule anything I wished. “This is the apple pie rule” or “This is the post-examination rule”. It’s up to you! Choose something readable, because you’ll see the rule name if you are using the “Rules” dubug command.
Next, we start our loop. In this construction, we need something to check as well as a nickname we can use for the objects we check. In the construction
Repeat with T running through things:
In this construction, we are checking all things in the game, one at a time. I’m using “T” to refer to the specific thing that Inform is checking as it works through its list. You don’t have to call it “T.” In fact, the name is largely up to you, though you should avoid words that Inform is already using, like “Door” or “Vehicle.” These can fail outright or cause strange behavior, so avoid this pitfall! One popular construction is “repeat with item running through things.” Do whatever works for you: readable code is good code.
While Inform is working, one at a time, through all things in the game, we have a chance to intervene. We can check a property or value. We can move the things from one place to another. Generally speaking, we can do anything the syntax will permit (which is largely the same as typical action processing rules). In this example, I’m writing a text for each thing in the game. This text is conditional, checking to see if the player has “examined” the thing before.
say "[t]: [if we have examined t]examined[otherwise if we have not examined t]unexamined[end if].";
We are referring to the specific Item that Inform is evaluating as “T”.
I’m using the the extremely helpful “if we have…” construction. Inform is smart enough associate many (most) verbs, even made up ones, with their action names. So here, Inform knows whether we have examined a thing or not. We can use that information to print our output. If the player has examined T, say “examined.” If the player has not examined t, say “unexamined.” (Edit: you could just as easily say “otherwise rather than “if we have not examined t.” Whatever reads better for you!)
Alright! We have a rule that can list every item in the game, declaring whether it has been examined or not. This kind of thing can be useful for debugging. Right now, we don’t have the rule doing anything; it just exists. Let’s hook it up!
To get this rule to fire, we need to get it into the turn sequence someplace. Every turn rules are often good for this sort of thing.
every turn:
follow the examination check rule;
That’s all there is to it! Maybe. Every turn rules only happen after we do something. What if we want our rule to print when the game begins? We have a couple options there:
When play begins:
This is fine, but it prints before, well, play begins, which means that our output will print before the banner and room description. It’s probably cleaner if we print our output after all of that. That’s not too tricky.
after looking when we have not looked:
follow the examination check rule;
continue the action;
A game starts with a looking action, which prints the room description for the first time. If we want to latch onto that, we can use “looking when we have not looked,” our rule will only fire after printing the room description for the first time. Note the use of “continue the action.” After rules typical stop action and prevent Report rules from running. We have no specific need for that right now, so I’ve added “continue the action” to keep things moving.
Here’s a sample transcript:
Welcome
An Interactive Fiction
Release 1 / Serial number 250825 / Inform 7 v10.1.2 / D
lab
You can see an apple, a ball and a hat here.
yourself: unexamined.
apple: unexamined.
ball: unexamined.
hat: unexamined.
>examine ball
You see nothing special about the ball.
yourself: unexamined.
apple: unexamined.
ball: examined.
hat: unexamined.
>examine hat
You see nothing special about the hat.
yourself: unexamined.
apple: unexamined.
ball: examined.
hat: examined.
This is a simple, straightforward example, but we can do a lot more. Perhaps we want to narrow our search a bit. Imagine the we have an either/or property:
a thing can be cooked or uncooked.
We might want to find those things and move them to a refrigerator. In this pretend example, we have an action called “cleaning”
carry out cleaning the kitchen (this is the kitchen clean-up rule):
repeat with C running through uncooked things:
move C to the refrigerator;
We might have timers on some explosives set at various points in a building, all counting down at the same time.
an explosive is a kind of thing.
an explosive has a number called countdown.
the countdown is usually 10.
every turn:
repeat with E running through explosives:
decrement the countdown of E;
In a game, of course, we’d want to have things explode when the countdown of E reaches zero. That’s a good thing to experiment with! Timers are fairly common in parser games.
We’ve talked about this before, but did you know you can assign properties to a scene? Sometimes, it can be hard to troubleshoot scenes. Here’s a simple debug command that checks the properties of scenes and gives feedback.
a scene can be long or short.
a scene is usually short.
the entire game is long.
scene-checking is an action out of world applying to nothing.
understand "scenes" as scene-checking;
carry out scene-checking:
repeat with act running through scenes:
if act is long and act is happening:
say "[act] (long) is happening.";
if act is short and act is happening:
say "[act] (short) is happening.";
Perhaps a house fire occurs, and we’d like to assign everything in the house a property. In this example, “house” is a region made up of multiple rooms.
a thing can be burned or unburned.
a thing is usually unburned.
house is a region.
after burning down the house:
repeat with B running through things in house:
now B is burned;
We could go further and update the printed names of these things. We can add this:
let p be the printed name of b;
now the printed name of B is "[p] (burned)";
As one last thing, and this is more or less straight from the documentation. Let’s say we need to list the exits in a room. This one is kind of rich. Stay with me!
exits is a list of directions that varies.
this is the exit listing rule:
truncate exits to zero entries;
repeat with way running through directions:
if the room way of the location is a room:
add way to exits;
if number of entries in exits is zero:
say run paragraph on;
otherwise:
say "Available exit[if number of entries in exits is greater than one]s[end if]: [exits].";
say line break;
after looking:
follow the exit listing rule;
continue the action;
This is the first time we’ve used a list. There’s a lot of things we can do with them—some if them quite complex—but at essence they are just what the name implies: lists. We can list all kinds of things. Values, things, objects. The only real requirement is that they have to be constant. We can’t add “a number that varies” to a list, for instance. In this case, we are building a list of directions. Let’s walk through it.
First, we declare our list. We can state the initial contents of it, or just say that it exists. We’re doing the latter, as we’ll let our code fill it in.
exits is a list of directions that varies.
We name a rule, first of all.
this is the exit listing rule:
Next, we’ll clear out whatever is in our list of exits so that we have up-to-date information there.
truncate exits to zero entries;
Next, we can start repeating through directions.
repeat with way running through directions:
if the room way of the location is a room:
add way to exits;
This construction probably looks a bit odd. The thing to bear in mind is that “directions” are always parsed, whether there is an exit or not. We can actually bypass “you can’t go that way” messages with Before stage rules. So we need to check for rooms associated with directions, if that makes sense. “If the room way of the location is a room” checks this.
If there is a room in the direction checked (way), we add that direction to our “exits” list.
If there are no exits, we don’t need to print anything.
if number of entries in exits is zero:
say run paragraph on;
If we do have entries in our exits list, we can just print the list.
otherwise:
say "Available exit[if number of entries in exits is greater than one]s[end if]: [exits].";
say line break;
Note the check: we ask inform to add an “s” to “exit” if there is more than one exit.
Where to fire it? I decided to add it as an After looking rule. Though if we want to make sure it’s the last thing that prints we could go with “last report looking”.
after looking:
follow the exit listing rule;
continue the action;
OK! Here’s some output.
Welcome
An Interactive Fiction
Release 1 / Serial number 250825 / Inform 7 v10.1.2 / D
lab
You can see an apple, a ball and a hat here.
Available exits: south, east and down.
This is only scratching the surface! Repeating through is a powerful tool. I use it all the time! Time learning about them is time well spent.
It’s possible to loop through lists, number counters, and tables, but I think we’ve seen enough for today. We can pick that up next time.
