How to Program IF

Introduction

I've written a couple essays in the past about how to design IF games, but I haven't talked about how to program them. If you've ever said "I want to put a telephone in my game" or "How do I make a puppy that follows the PC around?" then this is the one to read (if you're asking "Should I put a telephone in my game?", then read the other essays first).

Identifying the Problem

The job of an IF programmer has a lot in common with a stage designer for a play. When the director says "Hey, we need a church for Act 3", the stage designer doesn't start by asking moving companies for quotes on the Sistine Chapel. Instead, they talk to the director and ask some questions: "What kind of a church do you want?" "What's the role of the church in the play?" and — most importantly — "What are the actors going to do with the church?" There's a big difference for the stage director if the church is just one of a bunch of buildings forming the backdrop for a Western scene, or if it's the setting for the big tussle-at-the-altar scene at the climax.

Similarly, when you decide you want to add something to your game, the first thing to do is make a list of the features of this thing that your game will need. These features should include ways that the player will interact with the object, ways the object will interact with the rest of the world, and things the object will do on its own. Some examples:

A telephone: The main role of this telephone in the game is to ring at 9am, at which point the PC will answer it and receive a message. I don't want to support actual conversations over the phone, nor do I want to support dialing numbers.

An anvil: The main role of the anvil in the game is to be brought to the blacksmith at which point the PC will get a reward. To make this more complicated, I've decided the anvil will be extremely heavy and the PC will be forced to drop it after three turns (since this essay isn't about good game design, just about implementing a given design, I can include this kind of thing). I don't want to support any kind of smithing by the player, or the anvil rusting.

A puppy: The main role of the puppy in the game is to accompany the player around being cute. I have decided on a few cute behaviors for it to have: the puppy will follow the player around, it will print a message about it doing something cute every few turns, and it will respond to the player throwing a stick or petting it. I'm not going to support the player telling the puppy to do tricks or otherwise communicating with it.

Note that there are a number of other features that are common to almost every object that I've left out, but as a programmer I'll need to implement. For instance, the puppy needs to respond to the vocabulary 'puppy' and 'dog', and has to have responses to basic verbs like >EXAMINE. I'm not going to focus on those in this article, but don't forget to keep them in mind.

Classifying the Features

Now you have a list of the features of this object. The next step is to decide what this means to the program. A feature can be represented in the program as one of two kinds of things: a reaction to the PC directly interacting with the object, or an event the object does on its own.

Reactions to the player are things like the phone having a response to >ANSWER PHONE or the puppy having a response to >PET PUPPY. The standard library has a lot of these reactions built in already: every existing verb can be used on an object and gets some kind of response, even if it's just some standard message ("That doesn't appear appetizing" if you try to >EAT ANVIL). In some cases, to add a reaction you'll need to add a new verb to the game. Perhaps >ANSWER doesn't exist yet; in that case, you'll have to plan to add it, and to add a default reaction for the player typing >ANSWER THING for anything except the phone, along with the reaction for >ANSWER PHONE.

Events (sometimes called daemons, fuses, timers, or each-turn rules) are things the object does on its own. This covers everything from the phone ringing at 9am to dropping the anvil after carrying it for a few turns. There aren't a lot of events in the standard library. Arguably things like the turn number increasing each turn are events, and the player getting hungry or sleepy definitely counts (for libraries that include those by default).

Sometimes it's difficult to decide whether something should be an event or a reaction, like the puppy following the player around. In many cases, you could code it either way: "In reaction to the player going north, move the puppy north" or "If the puppy isn't in the same room as the player, move the puppy into the player's room". A good rule of thumb in these cases is, if you're not sure, do it as an event.

Events can be a little more complicated to write, but they're much more powerful and much more complete. For instance, what if the player is moved to another room but not by typing >NORTH? Say, they enter a house or suddenly fall through a trap door. If you want the puppy to follow them in those circumstances, the event will do it automatically. If there's no event, you'd have to write additional reactions for each of those player actions. And sometimes it's just impossible to cover all the cases — if the player is moved by another event, there's no player command to react to.

Another way to think about the distinction is that events happen when a condition is true (the player is carrying the anvil, it's 9am, the player is in a different room from the puppy), and reactions happen when the player's typed something (>PET PUPPY). Sometimes these both occur in a feature: the anvil is so heavy the player has to put it down, three turns after they pick it up. This feature translates into two separate parts. There's an event that happens that says that the anvil is heavy and makes the player drop it. But to start that event, we need a reaction to >TAKE ANVIL, because the event is supposed to go off three turns after it's taken.

Filling in the Gaps

We're doing pretty well at this point. We have a telephone object that reacts to >ANSWER PHONE and has an associated event to make it ring. But while our feature list for the phone covered all the things it needed to have to be a part of the game, there are plenty of other things the player might try with the phone: they might examine it, they might try to call people on it, they might pick it up and throw it out the window.

As the author, we know none of those things are necessary to the game. But the player doesn't know that, and it's the player's ideas we're concerned about — just like the set designer draws extra decorations on the backdrop to make it look more realistic, we want to fill in the implementation gaps for the object. So along with our list of features we want the object to have, we make a list of things the player might try to do to the object. Of course this can't be exhaustive unless we can read the player's mind, and not every player will try everything on the list. But it's good to try to think of some of the basic things.

Once you have the list, you can decide what to do with each item on it. In some cases, you'll just ignore the item. The player might type >EAT PHONE, yeah, but I don't care enough about that to handle it specially, so I'll just let the default reaction occur. In other cases, you'll want to code a reasonable response: >EXAMINE PHONE probably deserves a message even though it's not important to winning the game, and >DIAL PHONE should get a response too, because it's something a lot of people will probably try.

That doesn't mean that you have to code an over-the-phone conversation system! It just means that >DIAL PHONE should acknowledge that this is a reasonable command and let the player know that it's not important or not implemented ("You start to dial a number, but realize you don't have anyone to call.").

Finally, you might want to redirect items on this list to items that are important. There's no good reason in the game for someone to take the phone, so maybe typing >TAKE PHONE should just give an error ("There's no reason to take the phone"). On the other hand, picking up the receiver is a lot like answering the phone; if we make >TAKE PHONE map to >ANSWER PHONE, then people will get the message that taking the phone isn't necessary but answering it is.

Wrapping Up

The most important idea from this article should be the one that dates all the way back to Colossal Cave:

Somewhere nearby is Colossal Cave, where others have found fortunes in treasure and gold, though it is rumored that some who enter are never seen again. Magic is said to work in the cave. I will be your eyes and hands.
"I will be your eyes and hands," the game says. Anything the player sees is something the game chooses to show them. Anything the player does is something the game chooses to allow. Like an efficient scene designer, you only need to paint things on the side that will be seen by the audience. By identifying the features you want the objects to have, and then breaking down how to implement them, you'll be able to provide a beautiful set of props for the player to interact with. And hey, if it's all nails and unpainted wood backstage, who's gonna know?


If you'd like to see more IF-related things from me, you should look at my main IF page.