In this series I’m going to be talking about parser-based interactive fiction, and showing you how to develop it. There are a great number of different engines available, but I’ll be focusing on two – Tads 3, and Inform 7.
They’re very different in a structural sense. Inform 7 uses natural language to establish a series of rules for the game, while TADS is a more traditional object oriented language that lets you define the game world as a simulation. I encourage you to explore both and choose whichever one you feels works best with your own personal style.
I’ll cover game design next time. Today we’re going to cover the practical nececcities of an interactive fiction game in TADS 3 and Inform 7.
TADS 3
For this series I’ll be working with [TADS 3.1.3](https://tads.org/tads…
In this series I’m going to be talking about parser-based interactive fiction, and showing you how to develop it. There are a great number of different engines available, but I’ll be focusing on two – Tads 3, and Inform 7.
They’re very different in a structural sense. Inform 7 uses natural language to establish a series of rules for the game, while TADS is a more traditional object oriented language that lets you define the game world as a simulation. I encourage you to explore both and choose whichever one you feels works best with your own personal style.
I’ll cover game design next time. Today we’re going to cover the practical nececcities of an interactive fiction game in TADS 3 and Inform 7.
TADS 3
For this series I’ll be working with TADS 3.1.3 and the Adv3Lite library. It’s a streamed down version of the “full” TADS library that has been updated far more recently (within the last year or so, compared to over a decade ago.) The TADS Workbench is a perfectly fine IDE.
Getting the Lite library up and running isn’t difficult, and the “Learning Adv3Lite” PDF has a good guide to getting it done.
Inform 7
Inform 7 has its own IDE and is even easier to get set up. Just download the latest – 10.1.2 as of this writing – and you’re good to go.
A Simple Game
The simplest of possible games has two elements: a thing you need to do, and a place to do it in. Even the first part, the objective, is optional if you can provide the player with an interesting and engaging environment.
We’ll go into design in more detail later, but for illustrative purposes we’re going to make a game about finding your keys before you leave the apartment. Keys, phone, wallet, check. If you want to follow along, you can choose a different goal and setting; just keep it simple, something the player can accomplish by walking around and looking at things.
Start a new Project
First things first, we’re going to want to start a new project.
In TADS
Open the TADS Workbench and choose Create a New Project from the pop-up dialog, or from the File Menu if you’ve disabled it. For our project name we’re going to go with Keys – Wallet – Phone – Check. We’ll also pick a location for the project.

Next we’re given a whole list of project types. These are templates that give us various degrees of pre-filled game data; we’re going with the Adv3lite option.

Next we’re asked for some bibliological information for the Interactive Fiction Database and IF Archive; even if you don’t plan on uploading the game, it’s good practice to fill this out.

And that’s it. The Workbench IDE has created our files and necessary associations.
In Inform 7
Inform was last updated in 2022 so it has a much more modern interface. Open the launcher and create a new project from the option in the left column.

As in TADS you’ll be asked for a directory, project name, and your name.

Navigating the TADS Workbench

The TADS Workbench has a list of all the source files associated with the project over on the left pane of the screen. These include the library files that comprise the adv3Lite library, along with system files, readMe, license, any cover art, feelies, notes, and the actual project files for your specific game.
Double-clicking any of these brings up an editable text window. You can also set it up so that you use an external text editor – I’m partial to Sublime Text – using the menu under Tools>Options>External Editor.

(Note the command line is “%f” with quotations. This is necessary, or sublime text will treat spaces in your files’ names as separate files.)
If you do this, you can right click on a file in the pane and elect to open it in the external editor you’ve set.

Here’s a look at the Keyes – Wallet – Phone – Check.t source file created for us.

At the top we have #charset, telling the interpreter what character set we’re using. (ASCII.) Then we have #include statements telling the interpreter that we’re including the base tads.h resource file and the advlite.h library.
We can have multiple source files for our game data – we could have a file for each map, each major NPCs, new verbs, etc, but for our simple game here we can get away with using one.
Under that, we have our versionInfo object.

Breaking this down, versionInfo is the object’s identifier. This is what we’d use to refer to it in code. GameID is the object’s class; this is an object containing that bibliographic information we set earlier, and we can change it here as needed. This info is also used for our game’s title when someone plays it.
Everything after that to the semicolon at the end are the object’s properties. IFID is a random serial number assigned for the benefit of the Interactive Fiction Database. name is a string holding the name of our game. byline is our author byline. htmlByline is a version of our byline that can include hyperlinks. version is the game’s version – I personally change this to something less than 1 until a game’s full release, but you can version it however you want.
desc and htmlDesc are descriptions of the game.
versionInfo is one of two mandatory objects that all TADS games must have.
All objects in TADS – rooms, objects, verbs, etc – work this way. They are objects with one or more classes that contain properties. The source file contains a few more examples.

gameMain is the other mandatory object. It’s used when the game begins, to set which object represents the player character – here, assigning it to the object me (defined later). Optionally we can set other flags that alter how the game runs here, like usePastTense if we want to communicate to the player in past tense instead of present, or allVerbsAllowAll can be set to false if we want to restrict what verbs can be applied to everything at once.
This is also where we’d put the game’s parting message, if any, and where we’d set up an about box displayed when someone uses the Help>About menu option while playing.
More immediately, we can use it to give the player an introduction when the game starts. This is done by adding a showIntro() method.
Methods are like properties in that they belong to specific objects, but instead of holding a value they run a bit of code when called. Thus our intro can change the game-state in different ways, but we’re just going to give the player a heads-up regarding the context of the game. This is best used to give the player an initial goal so they’re not floundering so much, and to ground them in the setting to provide them with context.

Here we’ve edited gameMain to include a quick little intro that we’ll probably flesh out later. Note the formatting – the method name is followed by parenthesis, and the block that follows is encased in curly brackets. There’s only one line – printed text – and it ends in a semi-colon. Line breaks do not matter, so to create a new line we need to indicate that with \n, though we could also use HTML tags. The \b gives us a blank line, but we can talk about text formatting in a future post.
<<versionInfo.name>> and <<versionInfo.byline>> are references to those properties in the versionInfo object; referencing them in the angle brackets allows us to display their value.
Most of the time if code is throwing errors and you’re not sure why, it’s because you left off a semicolon somewhere or added one where it didn’t need to be.

Our next object is startroom, an object of the Room class. This is an object like the others, though you’ll note that it’s formatted differently. This is because, to save time, TADS lets you use templates to define common objects like rooms and things.
startroom: Room works like it did before – object name and class. However, with a Room, when there’s a single-quoted string on the same line, that line is the room’s name property. And if there’s a double-quoted string on the line after, that’s the room’s description – or desc property.
The way we see it here is identical to the more formal way of implementing it without the template:

Using the templates is faster, as you don’t need to explicitly state that you’re defining certain properties – you just use the correct pattern. But you never HAVE to use templates.
As far as locations go, the name is printed every time you enter a location, and the description is printed the first time you arrive – or every time, depending on settings.

The final object in our TADS source code is me, an object of class Player. This has a standard Thing template, if abbreviated – we define the object’s name as ‘you’ which makes sense for a 2nd person perspective game.
We need to have the player object defined, because we indicate that it’s me above in gameMain‘s initialPlayerChar property.
Note the + symbol next to me? That’s a shorthand for noting that this object is located inside the prior object. It’s the same as setting me‘s location property to the above object.
Now, if we compile and run the game in the Workshop (using Control + F5), we get:

Navigating Inform 7

Inform 7 has a much slicker design. On the left pane is your source code – currently nothing more than the game’s name and byline – and on the right you have the game’s documentation. Most of the boilerplate is kept behind the scenes so the implementer can focus on writing.
Unlike our TADS example above, Inform has not provided us with everything we need to start an empty game. We will need to create at least one location. We do this with natural language, simply by telling Inform that such a location exists.

We’ll duplicate the TADS example above for now and create a starting room called The Starting Location.
While Inform lets us use natural language, this can be a trap, as it does have its own specific syntax. We have to say The Starting Location is a room and not something like There's this place called The Starting Location because room is a specific keyword with a specific meaning, and a way of assigning value.
You’ll pick it up as you go, and the error messages are helpful when you forget.
We can add a description to the room in a similar manner as we did with the template in TADS, by adding a quoted string after the room description.

Since we only have one room, it is presumed to be the starting location. If we had several, the first defined room would be used as the starting location, unless we specified otherwise.
Adding an intro is a little trickier, because we’re no longer making statements that define the world, we’re adding a rule about what to do when the game runs. We can do this with the phrase When play begins:

To test the game we hit the Go button at the top of the screen. The Documentation pane on the right is replaced by our gameplay.

The Game Map
Our apartment is going to be a small one. Bedroom, bathroom, kitchenette/living room, and hall leading to the front door. Four rooms. In a more complex game we might map this out on graph paper.
We’re going to start with thinly sketched placeholders so we can get spatial relationships down.
In TADS
Each location is an object of the Room class.

Each follows the same template that startroom had. We write a placeholder description that focuses on telling us where the exits are, and then directional properties – north, south, west, east, northwest, southwest, northeast, southeast – that actually create those connections. We don’t use them in this game, but it’s also possible to use up and down or shipboard references like fore and aft.
The directions don’t have to be synchronous – we go northeast to the bathroom but west to return to entrance_hall – but we should strive for cohesive logic unless the point is to confuse the player.
We’re not including the front door because that won’t really be a Room – it’s more of a victory condition. Leaving the apartment with our keys, phone, and wallet wins us the game. We’ll be implementing it later.
We also move the me player object to the entrance_hall – where we want to start the game. Since they’ve moved, we can delete the default startroom.
In Inform
In Inform rooms are connected by pathways in a similar manner. We declare their relationship to one another.

This creates a problem as our room exits are meant to be asynchronous; the hall is meant to be west of our bathroom and bedroom, not northwest and southwest. We can clarify this by adding the following notes.

However, this creates another problem; now Hallway is to the southwest AND west of Bathroom, and to the northwest and west of bedroom. Telling the interpreter that Hallway is west does not invalidate the connections it wants to establish. We have to be explicit.

Now we have a layout equivalent to that which we created in TADS. We can double check this in the Index tab along the side of the right pane. That brings us to the following:

Here we can see summaries of all kinds of information. More than what we know what to do with! Of immediate interest is the bottom left option, the Map. Click it.

This gives us a map of our game’s rooms. Bathroom and Bedroom don’t quite connect on the map due to the asynchronous connections, but we can make out how they work, and that we’ve “sealed off” the connections we don’t want.
Finding Your Keys
Next let’s add the components that are absolutely necessary to win the game: your keys, and a functional front door. Remember, we’re keeping this simple for a first look at interactive fiction basics, so we’re going to try and restrict ourselves to basic gameplay elements like examining things and picking objects up.
Given the name of the game we’ll also be creating your wallet and phone. You’ll need all three to win.
In TADS
Let’s start with the wallet, and we can create it directly in the bedroom for now, using the + notation.

We’re giving it the object name of wallet and it is of class Thing. Unlike with rooms, however, the Thing template doesn’t provide a name property. Instead, we have a vocab property that gives us both the short name, and the words the player can use to refer to it in commands. The short name also defines how the object appears in room descriptions.
Here, the short name comes first. your wallet. A semicolon separates it from the first set of vocab words, adjectives the player might use to refer to the wallet based on its description: worn brown leather. They don’t need to use all the adjectives, or any of them, unless we have, say, a second velcro wallet and need to disambiguate which one we’re talking about. The third vocab set are synonyms… we can also call the wallet a billfold and be understood. Finally, we have pronouns. The wallet is an ‘it’.
Anticipating what words a player might use for our game objects is a big part of adventure design.
We run the game and…

Well, that’s not right. The game doesn’t understand grammar or why it shouldn’t use the indefinite article ‘a’ in the description. If our wallet’s short name was just ‘wallet’ instead of ‘your wallet,’ this would be perfectly fine.
However there’s a simple fix for this. Simply add parenthesis to the short name to tell the engine that it’s a qualified noun and won’t need the article.


Next we can add your keys to the living room.


This is a bit more involved as the player might want to refer to the keys, a single key, or even the key ring itself, and we want to direct all such inquiries to the same object. We could absolutely, in a more involved game, make separate sub-objects for each such part.
Finally we have our phone, the simplest object, and we’ll just put that in the bathroom.

Right now all three are simple MacGuffins that don’t do anything but exist for the sake of beating the game. If we have all three, we can open the door and leave.
So we need a Door.
Well, not really. A Door is a class in TADS that you can use to create pairs of objects in TADS that exist in two locations – one per side of the door. They open, close, lock, and exist in whatever state in pairs. You can pass through them as if they were direction properties.
That’s more than we need. Our Door only needs to do two things: win the game if we have our three objects and try to open it, or rebuff us if we don’t.
So instead of a Door, we’re going to create an ordinary Thing and set its isOpenable property to true. This is a property that exists in the Thing class, and every class that derives from Thing (which is most of them). It defaults to false, which means we can’t even try to open them. We’ll probably want to make wallet openable later.

Note that we have an empty pair of semicolons in front_door’s vocab? This is because we do not need a synonym for door. We simply leave it empty and move from adjective to pronoun.
We run the game to test it and…

The game lists the front door in the same way it did our wallet, keys, and phone. This is unnecessary, as the Hallway’s description already lets us know that a front door is present. It’s also, as a Thing, something we can lift up and carry around with us. That is not desirable behavior.
We can fix both these problems by changing the front_door‘s class from Thing to one of its subclasses.
Fixtureis used for objects that are obviously fixed in place.Heavyis used for objects that are too heavy to lift.Decorationis for objects that are mentioned as present, but not important enough to implement.Distantis used for objects that can be seen but are beyond your reach, like the moon or the horizon.Immovableis used for objects that can’t be picked up for other reasons.Unthingis used for objects that represent the absence of something.
Which one you choose depends on what kind of error messages you want the player to get. For the front door, Fixture is the one we want.


This behavior is more in line with what we’re looking for. Now we just need to alter the code so that it rebuffs us if we lack the three objects we need to leave, or wins the game if we have them.
Actions in TADS have to pass several checks before they occur. For an action that takes a direct object – like OPEN DOOR – we have two such steps, and they’re in the door in question’s dobjFor(Open) method.
When the player tries to open a door, the parser goes through the following steps:
- Verify. Does this action make logical sense? For objects descendant from the Thing class, Opening only works if the object’s isOpenable property is set to true. If not, we’re told that the object can’t be opened and the process aborts.
- Check. Have we added code to disallow an action that might otherwise be logical? For example, if we don’t want the player to steal a man’s hat. The hat can logically be taken; however, he won’t let you have it.
- Action. This is the actual processing of the action. The game state changes.
- Report. We report to the player that the action has been completed. This generally refers to automated parser responses, instead of specifically coded behavior for special cases.
For our door implementation, we want to disallow the opening if we have insufficient objects in the Check step, and win the game if we have our phone, keys, and wallet in the Action step.

Our check() method checks to see if the keys, wallet, or phone aren’t in the player object – aren’t in our inventory. If none of those conditions are met, we move on to the action() method, which gives us a victory message and then calls the finishGameMsg() function which – as you can guess from the name – finishes the game in victory.
In Inform
Creating objects in Inform works similarly to creating rooms. We declare where they exist. It’s important to place them first in the declaration – A wallet is in the bedroom instead of in the bedroom is a wallet.

As with the TADS implementation, we need to define the parts of speech by telling the parser to understand the words “worn,” “brown,” and “leather” as referring to the wallet. We also declare that the wallet’s indefinite article is “your.”
Note that we’re specifying that the description of the wallet is the string we want. If we try to provide a description as we did with rooms, that becomes the description seen when entering the room with the object present.

becomes

We can add the phone and keys the same way.

The door is trickier. First, if we don’t want it showing up in the room listing, we can declare it scenery. We’re not going to make it an actual door, because a door in Inform needs to be between two locations, and we’re not making anything on its other side.
We can alter what happens when we try to open it using rules that state what happens before we try, and instead of a normal opening operation.

The Before rule checks to see if we have each required action. If we lack anything, it aborts.
The Instead rule preempts the normal result – this isn’t a real door or a container so we’d get a message about how it couldn’t be opened. Instead, if we DO have all three items, we get the victory message and win the game.
Mechanically we’re complete now – we have to gather all three objects and leave. However, it’s not much of a game, or even an experience.
Hiding Things
One of the big strengths to parser interactive fiction is its ability to provide environmental storytelling. Even in a game as restricted as this, being able to examine and poke around at the scenery gives us the ability to tell a story alongside the story of someone looking for their keys. We can provide hints and clues towards a larger narrative, characterize the player, build atmosphere, and write cool prose.
To make finding our keys slightly more of a puzzle, we can hide them until the correct objects or scenery are discovered, and hide cool little details for the player to stumble across as they go. We just need to decide on the story-within-the-story.
In TADS
The easiest way to hide an object in TADS is to just stick it inside a container. We can do that with the wallet in the bedroom by adding a dresser. Giving it the class OpenableContainer lets us put things inside it that aren’t discovered until we try opening it.

Note that I’ve also made the wallet an OpenableContainer but overridden the behavior. Instead of displaying its contents (nothing, because we haven’t implemented any) we get a brief message describing our behavior.
For the keys, we’re going to do something a little trickier. First, we’re going to describe the living room as having an attached kitchenette.

We’re going to implement the kitchenette as a Fixture. When we look at it specifically, we’ll notice that our keys have fallen on the floor behind the counter.

We’ve broken away from the template to add the kitchenette’s desc property as a method, so we can check to see if the keys are still hidden. isHidden is a property you can set on any Thing object to reflect that they’re present but concealed until found… in this case, examining the kitchenette sets the keys’ isHidden flag to false.

The keys themselves have an initSpecialDesc, which is a special room description in effect until the keys are taken or moved. Instead of saying “You see your keys here,” it will provide the text string in initSpecialDesc.
In Inform
Implementing containers in Inform is simple – you just declare that something is a container. You’ll also need to specify if it’s openable, closed, and fixed in place. We can then decree that the wallet is in the dresser. This normally also implies that the dresser is a container, but we still have to explicitly state that it’s openable, currently closed, and fixed in place.

Hiding the keys in the kitchenette is a little trickier, as Inform lacks a “hidden” attribute and we’d need to define it. That’s outside the scope of this post, so we’ll do something simpler – we’ll implement the keys without a location in mind. This places them “off-stage” in the parlance of Inform 7.
We can then, after examining the kitchenette, move them into the living room as if they’d been discovered.

Filling it Out
I’ve gone ahead and come up with a backstory and filled out the apartment to hint at the bigger picture, in TADS. You can see what I’ve done using the techniques we’ve described here:
Let me know if you found this useful or helpful in any way, and I’ll continue the series with more lessons in both Inform and TADS, diving deeper into the engines and theory of creating parser-based interactive fiction.
If you’re feeling generous and want to throw a few dollars in the hat for an out of work writer and narrative designer, check out my patreon.