Making adventure games with AGI

Posted by Peter Kelly.
First posted on 21 January 2000. Last updated on 30 June 2009.
Have an opinion? Leave a comment!

Making adventure games with AGI
Figure 1. King's Quest III: To Heir is Human
Making adventure games with AGI
Figure 2. The Black Cauldron
Making adventure games with AGI
Figure 3. AGI Studio
Making adventure games with AGI
Figure 4. King's Quest: Quest for the Crown
Making adventure games with AGI
Figure 5. AGI Studio
Making adventure games with AGI
Figure 6. PICEDIT
Making adventure games with AGI
Figure 7. The new King Graham can now climb up a castle pillar!

AGI (Adventure Game Interpreter) is a game engine written by Sierra On-Line in the early 1980s. It is used to create a number of their early adventure games such as those from the King's Quest (Figure 1) and Police Quest series. AGI supports only fairly primitive graphics by today's standards (160x200 pixels in 16 colors) and uses a text based interface where the player enters actions to perform in the game. The player can also move their character around on screen using the arrow keys.

Despite these limitations, AGI is fairly revolutionary at the time. It uses a number of design ideas rarely, if ever, seen before in adventure games. The most advanced of these is the ability to provide a pseudo 3D look to scenes in the game by allowing the player's character to stand in different parts of the screen behind some objects and in front of others. This is, of course, a far departure of the definition of 3D what we use nowadays. In addition, AGI provides facilities for animation of characters and objects in the game, in contrast to the static screens of the earlier generation.

In recent years, there has been increasing interests in the technical aspects of AGI—how the interpreter works and how to view and edit games that use the interpreter. The purpose of this article is to describe how AGI has evolved since the days of its use by Sierra On-Line.

What is so special about AGI?

AGI is remembered by many adventure game fans because it is used in many of the early "classic" adventure titles. The first games of the King's Quest, Police Quest, Space Quest, and Leisure Suit Larry series, in addition to a few other games such as The Black Cauldron (Figure 2), have used this interpreter.

Since late 1996, having been an adventure game fan (particularly of Sierra On-Line) for a number of years, I have developed an interest in the inner workings of AGI. I originally start off by examining some of the files in King's Quest II: Romancing the Throne and working out what format they are stored in. I then develop a program called AGIHACK which can display some of the graphics from the games. Not long after that I start to meet some other people who have been doing similar hacks, and we begin working together on figuring out the file formats.

After we have worked out most of this information, I start work on a program called AGI Studio (Figure 3). My goal is to write a program which lets you view and edit all of the resources in AGI games as well as create your own AGI games. AGI Studio never gets completely finished, but with the help of a few other programs you can use it to create your own AGI games.

How do AGI games work?

Each AGI game consists of a number of scenes (called rooms). These are fairly standard elements of an adventure game. The player controls a character (called ego) which moves around the screen and can perform all sorts of actions like picking up items, opening doors, and talking to other characters in the game.

Each room has a background picture and a script (called a logic) which governs what can happen in the room. The logic is written in a C like language which is compiled into a bytecode and executed by the interpreter. Games can also contain views (animations, still images of game characters, and other graphics that are not part of the background picture) and sounds (3-voice music tracks).

In addition to the above components, a game generally has a number of other logics which control the remaining aspects of the game, such as setting up menus, displaying the help screen, and responding to miscellaneous player requests that include saving or loading a game.

Let us look at an example room (Figure 4). For this example, we use room 2 from King's Quest: Quest for the Crown. This room contains 3 main objects—a castle, a moat, and a bridge. The player can walk around the room, look at various parts of the scene, cross the bridge, open the castle doors, or even fall in the moat and get eaten!

The script for this room is quite big. If you are experienced in programming languages like C, Pascal or Java, you should be able to get a fair idea of what the script is doing.

In the script, you should notice that a lot of the code looks like this:

if (said("look","water")) {
  print("It's your typical moat water: 
    murky and smelly.");
}

This is an example of the simplest logic code, and you can see statements such as this in just about any room in the game. What it does is to check if the player has said "look water", and if so, display a message in response in a window that comes up on the screen.

A variation of the above code looks like this:

if (said("look","door")) {
  if (posn(ego,0,120,159,167)) {
    print("These doors are strongly built
      to keep out unwanted visitors.");
  }
  else {
    print("You can't see them from
      here.");
  }
}

When the player types "look door", the response depends on where the player is standing. If the coordinates on the screen are between (0,120) and (159,167), a description of the doors is given to the player. Otherwise, the player is told that "You can't see them from here.".

While this code works fine for looking at things, what if we want to add a little interactivity? Here is a simplified version of the code that is run when the player tries to enter the castle:

if (said("open","door")) {
  if (posn(ego,105,120,121,128)) {
    start.update(doors);
    sound(15,f28);
    end.of.loop(doors,f24);
    stop.motion(ego);
    set.priority(ego,15);
    print("The huge doors swing open 
      slowly.");
    score += 1;
  }
  else {
    print("You cannot reach the door 
      from here.");
  }
}

First, the game checks that the player is in near enough to the door. If so, a number of commands are executed to display the animation of the doors opening and the player walking through them, as explained below:

start.update(doors);
Enable animation of the doors

sound(15,f28);
Play sound 15 and when finished set flag 28

end.of.loop(doors,f24);
Play an animation of the doors opening and when finished set flag 24

stop.motion(ego);
Stop ego from moving

set.priority(ego,15);
Make sure ego gets drawn on top of everything else

print("The huge doors swing open slowly.");
Display a message to the user

score += 1;
Add 1 point to the player's score

Once the sound and animation have finished, flag 24 and flag 28 are set. When both of these are set, the following code gets run, which takes the player to room 55 (inside the castle):

if (isset(f24) &&
    isset(f28)) {
  new.room(55);
}

Note that flags are the same as Boolean variables in other languages where they can have 2 values—true or false. In AGI these values are known as set and unset.

I hope the above section has given you an overview about how an AGI game works. The next section discusses how you can actually get access to the source code and resources that make up a game.

Using AGI Studio to edit games

The program requires Windows 95 or 98 but probably also works on NT4 and Windows 2000.

AGI Studio presents a fairly typical but simple IDE (Integrated Development Environment) interface. It has a toolbar at the top, and you can have windows open for the different resources in the game. When you open a game, you see 2 windows (Figure 5). You can browse through the resources by selecting them from the list on the left-hand side. Initially, this contains view resources (animations), but you can select pictures from the list as well. To view a logic you need to double-click on the resource which brings up a text editor. You can also edit views by double-clicking on them. Sounds can not be previewed or edited. To edit pictures, you need a separate program called PICEDIT (Figure 6).

There are plenty of instructions in the help file for AGI Studio which explain how to use other features of the program and how to create games.

Of course, if you want to look at existing games you need to find them somewhere. Chances are that if you are a hardcore adventure game fan you probably still have some of the originals lying around.

Editing a room

To demonstrate some of the features of AGI Studio, let us walk though a short tutorial on how to edit a room. We use room 2 from King's Quest: Quest for the Crown that is mentioned above as an example. What we want to do is to add the ability for the player to climb the wall of the castle. If they go up to either of the pillars on the side of the steps and type "climb wall", ego climbs part way up but then loses the grip and falls back down again.

First, load up AGI Studio and open up the game. Select "LOGIC" from the pull down list in the resource window, and then double-click on LOGIC.002. This brings up an editor window with the contents of the logic.

The code you see in this window is exactly how AGI Studio has decompiled it. Because variable names and comments are not stored in the game files, there is no way to work out what these may have been in the original code. I have added these variable names to the code included above, but you cannot see them when you open up the logic. To make the code a bit easier for us to read, add the following line to the top of the file:

#define ego o0

This means that we can use the variable name "ego" to refer to object 0—the character that the player controls. Now, scroll down to just before the line

if (said("check","room")) {

and add the following lines:

if (said("climb","wall")) {
  if ((posn(ego,83,140,94,147) || posn(ego,
    128,140,139,147))) {
    print("Climb");
  }
  else {
    print("You're not close enough.");
  }
}

So far this is very similar to the "look door" code I have previously mentioned. Now, from the "File" menu select "Compile & Run". Unless there are errors in the code, the program should compile the logic and add it to the game's resource files (VOL.*). The first time you run the game from AGI Studio you may be asked for the name of the interpreter; if this happens, just select "sierra.com" in the file dialog that comes up.

When the game loads, make ego walk to room 2 (the screen to the left of the current one), go up to either pillar, and type "climb wall". You should see the message "Climb" displayed, provided that you are close enough to the wall.

Now we want to make it possible for ego to climb the wall. Go to the top of the file and add the following lines, which define some variables and flags we are going to use shortly:

#define climb_finished f210
#define ego_x v210
#define ego_y v211

Also, just before the line

draw(o0);

near the top of the file, add the line:

  reset(climb_finished);

This defines and initializes the name of a flag which is set when the player reaches the top of the wall. Go back to the code we have just added before and change the code so it looks like this:

if (said("climb","wall")) {
  if ((posn(ego,83,140,94,147) || posn(ego,
    128,140,139,147))) {
    load.view(74);
    set.view(ego,74);
    set.loop(ego,0);
    set.cel(ego,0);
    set.priority(ego,15);
    program.control();
    get.posn(ego,ego_x,ego_y);
    ego_y = ego_y - 30;
    move.obj.v(ego,ego_x,ego_y,0,
      climb_finished);
  }
  else {
    print("You're not close enough.");
  }
}

Once you have done this, compile and run the game again. Try out the climbing. This time you should see ego climbing up to the top of the wall and then stop. We are going to add the code for falling down next, but first I need to explain what the code above does.

The command

load.view(74)

loads view 74 into memory and the command

set.view(ego,74)

assignes it to ego. View 74 contains the animation of ego climbing, so once ego's view is set to this we see him climbing instead of walking when he moves. Then,

set.loop(ego,0)

and

set.cel(ego,0)

set the current loop or animation to the first loop in the view and the current cel or frame to the beginning of the loop. Views can have multiple loops in them, but this view only contains one, so this is what we use. You can have a look at this view by selecting it in the resource window, and stepping through the cels by using the buttons in the preview window.

Then we set ego's priority to 15 using

set.priority(ego,15)

This means that ego is to be drawn in front of all other objects (such as trees and other game characters) and not restricted in movement by the edges of the castle. The command

program.control()

stops the player from controlling ego while it is climbing.

The last thing we do here is start ego moving. The codes

get.posn(ego,ego_x,ego_y);

and

ego_y = ego_y - 30;

work out the screen coordinates that ego must move to, and then

move.obj.v(ego,ego_x,ego_y,0,
  climb_finished);

tells the game to move it to that location, and set the flag

climb_finished

once he reaches that point.

Adding the falling code

Once this is working, it is time to add the code to make ego fall back down again when he reaches the top of the wall. Go up to the top of the file and add just under

#define climb_finished f210

the following lines:

#define fall_finished f211
#define getup_finished f213
#define sound_finished f214

We must also initialize these variables:

  reset(fall_finished);
  reset(getup_finished);
  reset(sound_finished);

just under where we initialize

climb_finished

with

reset(climb_finished);

Now that we have set up these variables, there are 3 more bits of code required to complete the falling sequence. These should be added after the end of the climbing code mentioned above.

The first bit of code gets executed when the player reaches the top of the wall, that is, when the flag

climb_finished

is set. It loads view 105 which contains an animation of the player falling, and then basically does the reverse of the code above, moving ego back to his original position. The only new thing here is that sound 5 (a falling sound) is loaded, after which the game is told to play it and set the flag

sound_finished

when finished:

if (climb_finished) {
  load.view(105);
  set.view(ego,105);
  set.loop(ego,0);
  set.cel(ego,0);
  get.posn(ego,ego_x,ego_y);
  ego_y = ego_y + 30;
  move.obj.v(ego,ego_x,ego_y,0,
    fall_finished);
  reset(climb_finished);
  load.sound(5);
  sound(5,sound_finished);
}

As you can see above,

fall_finished

is passed to

move.obj.v()

so it get sets when ego reaches the ground again. The second piece of code, shown below, then responds. This time, instead of moving, ego stays still but an animation (contained in view 104) is played of him getting up. We have to set flag 98 so the game allows ego to stay animated when he is not moving. You may need to use a different flag in other games (the relevant code for this is in logic 0). Once this is done,

end.of.loop(ego,getup_finished)

tells the game to play the animation once and set

getup_finished

when it is done:

if (fall_finished) {
  stop.sound();
  load.view(104);
  set.view(ego,104);
  set.loop(ego,0);
  set.cel(ego,0);
  set(f98);
  end.of.loop(ego,getup_finished);
  reset(fall_finished);
}

Finally, the last piece of code gets called after ego has finished getting up. It gives control back to the player, releases the priority (so that ego is going to be hidden properly when behind objects such as trees), and sets ego's view back to 0 as it was before. We also remove the views that we loaded from memory, as AGI does not allow us to have more than a few loaded at once since we may need the memory elsewhere:

if (getup_finished) {
  reset(f98);
  player.control();
  release.priority(ego);
  set.view(ego,0);
  discard.view(104);
  discard.view(105);
  discard.view(74);
  reset(getup_finished);
}

The final result

Assuming the above code works, you should now be able to walk King Graham up to a castle pillar, climb up it, and then fall down again (Figure 7)!

With the addition of about 60 lines of code, we have now added additional functionality to the room. This is only a basic modification which is essentially just an animation sequence. Producing a complete room or a complete game is much more complex. In addition to animation sequences, you need to allow the player to interact with their environment, pick up and use items, talk to other characters, and explore the game world.

If you want to try out making your own games or modifying existing ones, the AGI Studio help file is the best reference for logic commands. It contains a description of every AGI command as well as information on various topics such as object movement, inventory, and variables.

References

http://www.ozemail.com.au/~ptrkelly/agi/index.html

• (3) Comments • (0) TrackbacksPermalink