IF Design: In Practice

I've been involved in the design and implementation of several text adventure games. The game development process presented here reflects my experiences with those projects. Needless to say, everyone has a different working style, so what works for me might not work for you. Hopefully you'll at least find my perspective interesting, even if my ideas about process don't turn out to be right for you.

The first step of writing a game is designing it. A system like TADS 3 makes it so easy to get started with a game that you might be tempted to jump right in and start programming, before you've even thought past the first few scenes of your scenario, but my advice is to restrain this impulse. Turn off your computer and get out a pad of paper. (Or, if you prefer, leave the computer on, but bring up your word processor rather than your TADS editor.)

If you've done any serious programming before, you probably know how important it is to think out your program before you start writing the code. Alternatively, if you've written any "conventional" fiction, you've probably been admonished to write an outline, a first draft, and a second draft before you start on the real thing. Well, IF is a combination of programming and fiction writing. It'd be nice if the need for planning in programming and the need for planning in regular writing somehow canceled each other out, but if anything, the need for planning is horribly compounded. The reason is fairly easy to see: if you find that a decision you made early on isn't working out, you have to go back and change all the programming work you did, and you have to make the change fit in with all the story work you've implemented.

My opinions on the importance of planning are informed by first-hand experience with what can happen when you don't have an adequate plan. Quite a while back, I co-wrote (with Steve McAdams) a TADS 2 game called Deep Space Drifter. After formulating the basic plot of the game, and mapping out the first half or so of the game's physical locations, we dove right in on implementation. We had a general idea of where we were going with the second half of the game, but nothing very specific - to give you an idea, the map of that part was just a big blob labeled "the planet."

Implementation went well for a while, but as we got further along, we started to run into details in the first half of the game that were dependent upon details from the undesigned second half. We improvised some details, and left others for later. As we did this, a strange thing happened: we started to realize that there were holes in the plot, and weird little inconsistencies that hadn't occurred to us until we needed to think about details. As a result, we started to change our basic ideas about the second half, which led to even more inconsistencies and plot holes. It was like digging in sand, and before long we decided to throw out the entire original plan for the second half and start over.

However, we had so much time and effort invested in the space station that we didn't want to throw it away. Instead, we tried to design a new second half that fit in with the existing first half. From this point on, we just kept making matters worse. We went through a series of essentially unrelated plots for the game, trying to fit each new plot to an even larger set of existing implementation. We'd plan a little, implement it, then discover that the plan wasn't working and would have to go - but the programming work we did would have to stay. The swamp, the cave maze, and the shuttle represented so much work that we couldn't contemplate throwing them away, so whatever we came up with had to include them somehow; for a brief time, we were actually going to make the swamp a "Swamp Simulator" (a HoloSwamp?) because it was the only way to make it fit.

In the end, we became rather tired of writing Deep Space Drifter, but our of sheer obstinence refused to let the project die before it was complete. I think this attitude shows through in the second half of the game; for instance, there's a room on the planet whose description is something like, "This room is very boring; you can leave to the north." The entire game seems to reflect its history: the space station is full of things to do, it has some nice running jokes, and it's stylistically consistent. The planet, on the other hand, has an empty, barren feel; it's spread out and there's not much to do. The only parts that are interesting are essentially unrelated to each other and to the story in general, a reflection of having been forced into the game whether they belonged or not.

I'm not saying that Deep Space Drifter is a bad game - I like the space station a lot, and the puzzles on the planet are very elaborate and elegant. But the game has some serious flaws, most of which I attribute to the long, chaotic process of design and implementation. (That, and a horribly misguided enchantment with Big Mazes. No, Big isn't the word; Huge, Vast, Galactic Mazes. The puzzles on the planet would have been great if they had just ended as soon as you got the trick. Instead they go on for about 10x too long apiece. I should have gotten the idea when I was observing one of our beta testers going through the cave maze, and he kept having to start over with his map because he kept going off the edge of the page. He'd draw it with smaller and smaller "room" squares on each attempt, until finally he insisted I just tell him how small to make the damned squares already. He practically fell off his chair when I showed him the page of centimeter graph paper neatly filled in with dots and lines.)

Other games I've worked on with somewhat more advanced planning. Ditch Day Drifter went through a much shorter and smoother design and implementation process, and I think a better game resulted. Admittedly, Ditch is a much smaller game than Deep, but it's clear to me that the same design process could have been applied to Deep, and that doing so would have resulted in a much better game.

Before any programming work started on Ditch, I had a complete map of the game and descriptions of all the objects and characters in the game, including the key elements of their behavior. This made implementation very smooth and easy, because I could simply go through the lists of rooms and objects and implement each. I didn't have to make any design decisions during implementation, which eliminated the desire to change design decisions that had already been made. The game took only a few weeks to implement, and came out fairly well.

My later games, such as Perdition's Flames, The Plant, and Return to Ditch Day, were somewhat in between the two extremes of doing it all on the fly and planning it all in advance. In each of these games, I worked from an outline, rather than from a detailed plan. I worked out all of the key plot points in advance, so I knew where the story would end up and how it would get there; and I had a coarse map, not showing every room but showing the main clusters of locations. As I implemented, I filled in the details of the part I was working on.

This hybrid approach - of creating an outline up front, and then filling in the details as I implement - seems to work out well for me. The fun part is in seeing your creation come to life, so the temptation to start in on the programming too early is always strong. But the risk of failure is awfully high if you don't have any sort of overall plan. Working from an outline is a good compromise, because it lets you get to the fun part fairly quickly, but still gives you a decent backbone from which to hang the parts as you implement them.

The danger of the "outlining" approach is that it leaves so much wiggle room. You might be picturing the outline as an index card with three bullet items, and out of that comes an 800-page novel; or you might be picturing a huge spreadsheet with every detail carefully color-coded and hierarchically indented. You might think I'm giving you license to do practically no planning, or you might think I'm demanding a tedious, endless exercise in self-discipline. The reality is that there's no ANSI standard for outlining; you just have to find the right level of detail that works for you. I have a pretty good idea of what works for me, but it's hard to quantify, and anyway it might not be the right level for you. I think trial and error is the only way to find out. The key is that when you start implementing, you should find that your outline answers most of the questions that come up. You should find that as you build out areas of the game, the outline continues to make sense.

Elements of an IF design

Let's look at what exactly goes into the design of a work of IF. Now, I just said that you don't necessarily need the complete design for the game in every detail before you start; a reasonably thorough outline is good enough. But whatever level of planning you have up front, you'll definitely have all the ingredients of the design by the time you're done, simply by virtue of having implemented all the details.

An IF design is essentially a list of all of the locations, objects, and characters in the game. For each one of these, the design includes a description of the item, its key behaviors, and its key interactions with other game elements.

The design also includes a "minimal path" through the game - that is, a set of commands that solves all of the puzzles (if the game even has puzzles) and moves the player all the way through to the game's successful conclusion. This don't mean that you have to apply optimization theory to find the shortest possible path through the game; by "minimal" we just mean that it omits any clearly unnecessary side tracks.

The minimal path isn't necessarily something you have to write down; to some extent it's implicit in the rest of the design, because it's just the path that happens to win the game as laid out in the objects and interactions. However, this is an extremely useful thing to actually work out and write down. Not only does it make it easier to do early test runs as you work on the implementation, but it also serves as a good "sanity check" of the design. Sometimes, working out the path will expose a story design flaw, because it'll make you realize that it's impossible to be in a certain place at a certain time, or it's impossible to do things in a particular order, etc.

If you're planning to implement from an outline rather than a complete design spec, you can still work out a minimal path. You just have to work at the same detail level as the outline. If the outline has some clusters of rooms rather than every individual room, for example, the path would just say which cluster the player is in at any given time.

Plot

Most adventure games have a basic plot framework that controls the overall flow of the game. The plot is a good place to start your design.

An adventure game's plot isn't usually as elaborate as the plot of a piece static fiction, such as a book or a movie, because you have much less control over the details of the main character's actions. This makes plot design much more difficult, but you should give the player as much control as you can, since adventure games are always more satisfying when they give players a greater sense of control. Adventure game plots, therefore, should simply be a framework that provides the general direction of action in the game, and specifies only the important events.

You should start off with a basic background and goal. Where does the game take place? When? Who is the main character? What must be accomplished by the time the game is over?

For example, in Ditch Day Drifter, the location is the Caltech campus (or perhaps Caltech in some parallel universe, since the game isn't a strictly accurate simulation of the real Caltech), and the time is the present, generally, and Ditch Day, in particular. The main character is a Caltech underclassman. The goal is to solve the Ditch Day "stack" that the senior across the hall has created.

You can continue by identifying the major sub-goals that must be reached in order to reach the overall goal of the game. In Ditch, the major sub-goals are to find each treasure listed in the note that describes the stack.

Filling in the details of the plot can proceed by "working backwards" from the overall goal to the major sub-goals, then backwards to the smaller goals that must be reached for each sub-goal, and so on.

I would advise against designing a game with generic sub-goals of the form as "the player must find the five rings of power." When the sub-goals are just n copies of something, they don't suggest anything about what you might need to do to accomplish them. On the other hand, if a sub-goal is something concrete and specific like "the player must destroy the radio broadcasting tower," the minor sub-goals come almost automatically: you need to break into the compound where the broadcasting tower is located, and you'll need some sort of explosive, and you may need to turn off power to the tower to avoid being electrocuted. But if you can turn off the power, why do you need to blow it up? Maybe because an attendant will come and turn the power back on after a few turns. Now we have another puzzle: dealing with the attendant. Sub-goals that are abstract, such as finding five rings of power, aren't nearly as helpful in getting to the next level of detail. Concrete sub-goals can often provide a seed that your imagination can almost automatically expand into a full set of plot elements.

Setting

The basic plot will provide an overall setting for the game, and the plot elements will usually suggest a specific set of large-scale locations. So, you'll start off with a "low-resolution" map simply by designing the basic plot.

Next, you can start filling in the specific rooms. At this point, you'll probably find that you start to fill in the details of the plot at the same time as you're filling in the details of the setting. If you're going to work from an outline, you might not map every single room in the outlining phase. You might just map out the general areas, making some notations about the key rooms you need but waiting until later to flesh out the areas fully.

Many locations in the setting will offer natural puzzles: if you have a bank, you'll probably have a safe, for which you'll need to find the combination; maybe you'll need to figure out how to defeat the alarm system, or perhaps you'll need something to distract the teller; maybe you'll need to find the key to the safety deposit box. If you have an airport, you'll probably need to figure out how to get past the overly sensitive metal detectors, or you'll need to know someone's itinerary, or you'll need to find some airline tickets, or you'll need to find a badge or key or combination to get into a restricted area.

Whatever type of location you're designing, the location will often suggest a series of puzzles to be solved. As you design the solutions to the puzzles, you'll be adding detail to the plot, which will in turn give you new locations to develop.

As you flesh out the setting, you may be tempted to add enormous amounts of space to your locations, just because they'd be there in the real world. For example, if you're building an airport, you may find yourself putting in dozens of gates, each pretty much the same as all the others. While the added space may make the game setting more like a real airport, it can often harm the game's playability. Remember, you're designing a game, not an airport - the most important thing is making the game fun to play, not "real."

The main problem with adding lots of essentially unused space to a game is that it tends to make the level of detail throughout the game less consistent. You should make an effort to keep the level of detail as consistent as possible throughout the game, to avoid annoying and confusing the player. If you have a few rooms with a great deal of detail (such as lots of objects that can be examined and manipulated), the player will come to expect that level of detail in other rooms. Two dozen empty gates will break that consistency.

Pointless territory also adds to the player's perceived workload without adding anything enjoyable. Empty space is no fun to explore, but a player has to map and remember the locations.

Objects and Characters

You'll probably end up designing most of the game in the course of mapping out the setting and plot. As you develop plot elements, you should make notes of the objects and characters that are involved. You'll probably find it easiest to note objects and characters on the map, where they'll be placed.

For each object and character, you should make notes about its relevance to the game, and what it does. You should think carefully about what other objects might be used for the same purpose, and what other uses an object might have. For example, if you have a door that you need to break down, and you intend to provide an axe for this purpose, you should consider two things: What else might the axe reasonably be expected to destroy? And what else might reasonably be expected to be able to break down the door?

Because a player could reasonably expect an axe to have many uses, and because many objects should be able to break down a door, you should be very careful about creating puzzles that involve brute force and powerful tools of general utility. Explosives, flammable liquids, weapons, and heavy tools are all likely to frustrate the player when they don't remove just about any physical obstacle. On the other hand, it would be very satisfying if you took the trouble to fully realize the axe and the door by allowing the axe to break down everything that's reasonable, and allowing the door to be broken down by other reasonable objects.

Implementation

Once you have the game designed to your satisfaction, you're ready to start implementing. In this section, we'll show how to implement the basic types of objects.

Note that we're assuming here that you're working from a fully detailed plan. If you're working from an outline, you wouldn't go into as much detail at the planning stage - but you'd have to work out the same details when it came time to write the code, so the implementation process will be no different.

Start off by drawing the map, and making annotations on the map describing the essential details of the plot. This should include placement of the major objects in the game, and descriptions of the important actions the player must perform.

As an example, we'll implement a game that takes place in a small airport. Our airport will have a terminal area, a concourse, and a gate area. We'll also have a plane parked at one of the gates. The terminal area will have a ticket counter, and a metal detector leading into the concourse. In the concourse, there will be a snack bar, and a locked door leading off into a security area. The gate area will have a couple of gates, plus a locked maintenance room. Here's the basic map we'll be implementing.


[ Map ]


This map conveniently has a couple of locked areas, which we can use for puzzles. In addition, we can probably find some use for the metal detector, since it will prevent the player from carrying any objects through it. The plane can also be a puzzle, since you'd normally need a ticket to board a plane. Plus, the cockpit should be restricted to airline personnel.

Let's make the goal of the airport segment be getting out of the airport. The player will start off in the main terminal area, but won't be able to go outside the terminal - we'll make up some excuse, such as heavy traffic that always pushes the player back into the terminal, to prevent exiting that way. (If this were an actual game, we'd probably have more game outside the airport, so we wouldn't use such an artificial boundary as having heavy traffic that pushes the player back in. For this example, though, we want to keep things fairly small.) The only other obvious way to get out of the airport is to fly out on a plane; so, let's make the goal be to fly the plane.

To take the plane out of the airport, the player will have to get into the cockpit. (We'll implement this example up to the point that the player makes it into the cockpit; in a full game, we'd go on to let the player fly the plane somewhere else.) Now, only the pilot can go into the cockpit - the flight attendant wouldn't let a passenger into the cockpit. So, we'll need some way to get past the flight attendant. One way would be to create a diversion that distracts the flight attendant long enough to slip by; for this example, though, we'll require the player to find a pilot's uniform.

Where would the pilot's uniform be? The pilot's lounge would be a logical place; we'll put a suitcase in the pilot's lounge that contains a uniform. Fortunately, the lounge is behind a locked door, which creates a secondary puzzle. To get into the security area that contains the pilot's lounge, the player needs a magnetic ID card to put into a slot outside the security area.

We'll put the ID card out in the open, on the ticket counter in the terminal area. However, we'll make it impossible to carry the ID card past the metal detector - the card will set off the metal detector, and the security guard will confiscate it (and place it back on the counter so that the player can try again). To get the card by the metal detector, you'll have to turn off the power to the metal detector.

The power switch will be in the maintenance room, which is locked with a key. We'll leave the key with some other maintenance items in the plane's bathroom - we'll also leave a pail, sponge, and garbage bag, so that it's clear by association that the key is probably for the maintenance room.

To get into the plane's bathroom, you'll need a ticket to board the plane. We'll make the ticket fairly simple to find: we'll leave it hidden inside a newspaper in the snack bar. As soon as you pick up the newspaper, the ticket will fall out.

So, that's about the whole game: you go to the snack bar, pick up the newspaper, and find the ticket. You take the ticket and board the plane, then go to the plane's bathroom and get the key. Take the key to the maintenance room, unlock the door, enter, and turn off the power to the metal detector. Go back to the ticket counter, pick up the ID card, go to the security door, put the magnetic card in the slot, and enter the security area. Go to the pilot's lounge, get the pilot's uniform out of the suitcase, and wear it. Go to the plane, and stroll right past the flight attendant and into the cockpit.

We should draw a new map now, which includes annotations for the main objects and actions that make up the game.


[ Detailed Map ]

Implementing the Map

The first step is to convert the skeleton of your map into the beginnings of your game program. At this point, don't worry about entering all of the detailed behavior of your map, but just build the basic rooms and connections between rooms. This will allow you to get a prototype of the game running quickly, so you can walk around it and see how it feels.

Start off by creating a source file for your game, and including the base definition files:

#charset "us-ascii"

#include <adv3.h>
#include <en_us.h>

Remember, as always, to be absolutely certain that the #include command has no space characters in front of it. The # must be the first symbol on the line.

Next, add the basic versionInfo and gameDef information:

versionInfo: GameID    
    IFID = 'bcb7d5c4-81ee-30b0-5aec-7672b10e2cd6'
    name = 'Airport'
    byline = 'by Michael J. Roberts'
    htmlByline = 'by <a href="mailto:mjr_@hotmail.com">
           Michael J. Roberts'</a>'
    version = '1'
    authorEmail = ' Michael J. Roberts' <mailto:mjr_@hotmail.com>'
    desc = 'A brief demonstration of game design in TADS 3.'
    htmlDesc = 'A brief demonstration of game design in TADS 3.'
;

gameMain: GameMainDef
    /* the initial player character is 'me' */
    initialPlayerChar = me
;

(We got that IFID, by the way, from tads.org's IFID generator.)

Now, for each room in your game, make an entry that gives the room's name (roomName) and description (desc), and the other rooms that are connected to this room. Here's how to implement the first few rooms from the sample map above. For the time being, we won't worry too much about making the descriptions complete; we can always flesh those out later.

terminal: Room 'Terminal'    
   "You are in the airport's main terminal. To the east,
    you see some ticket counters; to the north is the main concourse. "
    east = ticketCounter
    north = securityGate
;

+ me: Actor
;

ticketCounter: Room 'Ticket Counter'
    "You are in the ticket counter area. Ticket counters
    line the north wall; so many people are waiting in line that 
    you're sure you'll never manage to get to an agent. The main
    terminal is back to the west. "
    west = terminal
;

securityGate: Room 'Security Gate'
    "You are at the security gate leading into the main
    concourse and boarding gate areas. The concourse lies to the
    north, through a metal detector. The terminal is back to the
    south. "
    north = concourse
    south = terminal
;

concourse: Room 'Concourse'
    "You are in a long hallway connecting the terminal
    building (which lies to the south) to the boarding gates (which are
    to the north). To the east is a snack bar, and a door leads west.
    Next to the door on the west in a small slot that looks like it
    accepts magnetic ID cards to operate the door lock. "
    north = gateArea
    south = securityGate
    east = snackBar
    west = securityArea
;

The other rooms are implemented in the same manner. For now, we're not worrying about the items contained in the rooms, or the other people around, or even the locked doors. We'll just implement all the rooms so we can walk through the map and try it out.

Implementing the items

The next step is to implement the basic objects that make up the game. As with the rooms, don't worry about the complex behavior of some of the objects at this point; just go through and write basic object definitions for the main items in the game.

Items have different properties than rooms. The basic properties of an item are its name (name), long description (desc), vocabulary words (vocabWords), and container (location), which may be either a room or another item). If the item can be carried by the player, the object will be of class Thing; if not, it will be of class Fixture. Some items may be of different classes; for example, if you want to make an object that can contain other objects (such as the pail), make it a Container. If you want to be able to put objects on top of another object, use a Surface object. You can make something both a Container or Surface and a Fixture if you want.

Here are some of the basic object definitions for our sample game.

counter: Surface, Fixture 'ticket counter' 'ticket counter' 
    @ticketCounter    
;

+ IDcard: Thing 'id identification card' 'ID card'      
;

newspaper: Readable 'news newspaper/paper' 'newspaper'
    @snackBar
    "It's today's copy of USA YESTERDAY. "

    readDesc = "You read a few articles, and promptly become
        depressed.  The federal deficit just went up by another
        twenty billion dollars, but it's all <q>off budget,</q> so
        it doesn't really count.  There's another White House
        scandal involving illegal arms sales, money laundering
        through Italian banks, Congressional Pages; several
        high-ranking federal arts critics have already resigned in
        disgrace.  The economy had yet another downturn, but the
        President says he's confident that the recovery is <q>just
        around the corner and picking up steam.</q> " ;

cardslot: Fixture 'card slot' 'card slot' @concourse "The
    slot appears to accept special ID cards with magnetic
    encoding. If you had an appropriate ID card, you could put
    it in the slot to open the door. "
;

suitcase: OpenableContainer 'suitcase/case' 'suitcase' 
    @pilotsLounge
    initiallyOpen = nil    
;

+ uniform: Wearable 'pilot pilot\'s uniform' 'pilot\'s uniform'   
    "It's a uniform for an Untied Airlines pilot. It's
    a little large for you, but you could probably wear it. "
; 

The rest of the objects are implemented in much the same way. In implementing the basic objects, the main properties you need to fill in are location, so the object appears somewhere in the game; vocabWords, so the player can refer to the object; and name, so the system knows what to call the object when it mentions the object in messages. It's also important to choose the appropriate class for each item, so that you can get the correct basic behavior of the object without any additional work. Note that these are all properties that are defined in the appropriate template, so they do not need to be explicitly named. At some point, you should go through the TADS 3 Tour Guide (or even the adv3 source or the TADS 3 Library Reference Manual) and familiarize yourself with the classes defined there, so you know what you can get from adv3 classes without any work.

Implementing Special Behavior

The next step is to implement all of the special behavior that really makes the game work. For example, let's implement the simple mechanism that lets the player find the airline ticket upon picking up the newspaper. To do this, all we need to do is add a dobjFor(Take) action() method to the newspaper object (we'll just show the new method below, along with the foundTicket property; the rest of the object is the same as shown above):

modify newspaper
  dobjFor(Take)
  {
   action()
   {
     if (!foundTicket)
     {
      "As you pick up the paper, an airline ticket
      that was inside falls to the floor. " ;
      ticket.moveInto( gActor.location );
      foundTicket = true;
     }
    inherited;
   }
  }
  
  foundTicket = nil
;

This method runs whenever the player takes the newspaper. The first thing we do is check to make sure that the airline ticket hasn't already been found; if not, we display a message that it's been found, move the ticket into the game, and note that it's been found. Finally, we continue with the default actionDobjTake action that the newspaper object inherited from its superclass (in this case, Readable) by using the inherited statement.

Note that the airline ticket itself should be defined with no location, because it's not anywhere at all when the game first starts:

ticket: Thing 'airline ticket' 'airline ticket'    
    "It's a one-way ticket to New York, in class C
    (the <q>C</q> probably stands for <q>Cattle</q>). "
;

As another example, let's implement the puzzle the keeps the player out of the security area until the ID card is used to unlock the door. First, we must prevent movement from the concourse into the security area. For this, we'll change the concourse room definition, and add a door object.

concourse: Room 'Concourse'
    "You are in a long hallway connecting the terminal
    building (which lies to the south) to the boarding gates
    (which are to the north). To the east is a snack bar, and a
    door leads west. Next to the door on the west in a small
    slot that looks like it accepts magnetic ID cards to operate
    the door lock. "

    north = gateArea
    south = securityGate
    east = snackBar
    west = securityDoor
;

+ securityDoor: IndirectLockable, Door 'door' 'door'
    "The door has a label reading SECURITY AREA-AUTHORIZED
    PERSONNEL ONLY. "    
  
    openDesc = (isOpen ? 'open, which isn\'t very secure'
               : 'securely closed')
  
    cannotUnlockMsg = 'You should examine the slot if you 
        want to unlock the door. '
  
    cannotOpenLockedMsg = 'The door is securely locked. '
;

So far the door is little more than a decoration item; the various methods we implement are just to inform the user that the door can't be operated directly. The real work is done by the card slot; we'll add some new behavior to that object now.

+  cardslot: RestrictedContainer, Fixture 'card slot' 'card slot'   
    "The slot appears to accept special ID cards with magnetic encoding.
    If you had an appropriate ID card, you could put it in the slot to
    open the door. "
    
    validContents = [IDcard]
    
    cannotPutInMsg(obj)
    {
       gMessageParams(obj);
       return '{That obj/he} do{es}n\'t seem to fit in the slot. ';
    }
    
    iobjFor(PutIn)
    {
      action()
      {
        if ( securityDoor.isOpen ) 
          "You put the card in the slot; nothing happens,
          so you remove it. ";
        else
        {
          "You put the card in the slot. There's a click, and
          the security door pops open! You remove the card. ";
          securityDoor.makeLocked(nil);
          securityDoor.makeOpen(true);          
        }
      }      
    }
  ;

The new behavior is that the player can put the ID card in the slot. When this is done, the iobjPutIn method runs, with the ID card as the direct object. This method opens the door, if it's not already open.

Most of the remaining puzzles in this sample game are implemented in a similar fashion. You'll need to implement a couple of actors: one for the flight attendant, and one for the guard at the metal detector. In addition, you'll need a few more locked doors and special items.

We won't go any further into the other puzzles, because the techniques for implementing these and much more are described elsewhere (see Getting Started in TADS 3, the TADS 3 Tour Guide, and other sections in this Technical Manual).

Where to go from here

Before expanding this sample game by adding more areas, you could flesh out the game by adding lots of detail to what we've implemented so far. Most of the added material would probably be irrelevant to the plot, but it could make the game more interesting and more fun to play. Keep in mind that you're writing a game, not a real-world simulator; try to concentrate on things that make the game more fun to play.

Some items that would enhance the airport: Add lots of incredibly overpriced and extremely dubious snack items at the snack bar. Generate random messages over the public address system once in a while, asking various people to pick up the white courtesy telephone and warning travellers not to park in the red zone. Implement other effects for other power switches in the maintenance room: what happens when you turn off power to the snack bar, or the ticket counter, or the PA system, or the automatic doors? Add lots of strange people milling about in the airport; make some of them actively bother the player, such as various fringe religious and political groups trying to hand out literature (you'll want to write some wacky literature for them to distribute).

Alternatively, you could expand this game by providing some place to fly to. The player could go on to crash the plane into a remote mountain or desert island, and explore that. Or, you could take the plane to several other cities and explore.

Of course, you'll probably have the most fun if you start with your own ideas and write a whole new game. The hard part is always finding the right idea; once you have the premise for your game, you will probably be surprised at how quickly you can build a map and start implementing. Refer to the examples in this chapter to help you get started. As your game starts to take shape, and you want to add more ambitious features, the examples of advanced TADS programming techniques shown, for example, in the TADS 3 Tour Guide should be helpful.