AGI Scripting

2010-12-06

The good 'ol days. When 64k was enough for everybody and resolutions of 1650x1250 were imaginable. Back then software development was simpler. Or was it? Even though development tools of that time seem at best simple to us now, back then it was all you had. No fancy pancy IDE that holds your hand and points out every flaw in advancement, including a proposal for a solution and a pat on the back for trying anyways. Back then, an IDE was a text editor. Black and white. Sometimes even just shades of green.

This article covers the AGI scripting environment and explain you how to build a game using WinAGI. We made a small game using our office as the environment during a two day w00tcamp at Q42.

Back in 1990 Sierra released a series of games running on the same engine. This engine, called Adventure Game Interpreter (AGI), was built by Sierra Online and allowed game developers to create game logic without having to do that pesky assembly or C. The developers of the engine supplied a simple scripting language for them to use. That scripting language, called AGI Script, at first glance looks a lot like C. Especially back then, when most common languages now hadn't been invented yet, pretty much everything imperative looked like C :) Now the comparison to JavaScript might be made, although I'd only agree on the simplistic level.

AGI script doesn't have pointers or complex control structures. In fact, from what I've seen, it's hardly dynamic at all. It relies on a few simple syntactic rules. You break them? Stuff fails. Simple.

Another key element of the engine is the language parser. Games built in these engines relied on you telling the main character what to do. "Pick up bottle", "say secret password", "turn on the lights". The system that listens to these is relatively simple, as might be expected. At every game loop iteration (see below) the programmer can add certain groups of words to listen to. It merely has to add an if (said("activate", "lights")) { ... } to listen for any input that would match the pattern given. The patterns are actually words in the same group. So for the group that contains "activate", you might have "activate", "turn on" and "enable". For the group that contains "lights" you might also have "light". That way an explosional combination of possibilities are open to the player.

And even though you still have to type in those words exactly, the developer can add enough words to cover your bases. And it's not like you'll die for a typo. Well, not most of the time ;) The system also allows you to type more than required. So with the previous example, you could also just say "turn on the mfing lights right now and do it fast!" and you'd still turn on the lights for saying "turn on" and "lights".

The AGI engine is because of popular titles like Leisure Suit Larry, Kings Quest and Police Quest. The engine shows a straight angle isomorphic view of the environment. With straight angle I mean you only look from one side, never from a corner or somewhere in between. The engine has a horizon, trigger areas, actors and models. Terminology has changed over time though. AGI uses Logics (controller, this holds the game logic, one Logic file defines one room starting at room 1), Views (actors and models) and Pictures (background images). That's it.

All media is restricted to a 16 color palette. That limits the possibilities somewhat, especially with the reduced number of pixels you can use (160x200). But even so you can still go into great detail. The gamers are fairly good at imagining the rest, even if you only give them a few pixels. Just imagine the classics. Larry in the bar, the locker room in police quest, the various items in those games, etc.

So how does the engine work? These days the engine can still be used, new stories/games can still be created and still be played. Somebody even made an online version of the engine, right in your browser! (Sarien.net). The most popular IDE for AGI these days seems to be WinAGI. It's last update was around 2007, so (at the time of writing) it's not actively being developed. However, it does work under xp/7, albeit somewhat unstable. But for the most part, these instabilities are mostly pretty much predictable so it's workable. Note that there are other environments available. I've only worked with WinAGI.

You start with a black screen, an anonymous View (the actor), an empty word list and the set of predefined variables, strings, flags and objects.

AGI Script doesn't really work with declaring variables during runtime. You have to explicitly define the variables you'll use up ahead. Well wait, that's not exactly true. All variables (and other containers) have a default name. For variables it's v0 up to v255. For flags it's f0 up to f255. Objects have o0 and strings have, well you guessed it, s0. All these containers have up to 256 positions and some of them are in fact predefined/reserved. You can give these variables an alias, to prevent magic numbers. But you have to define them up ahead in a separate file. This can get a little annoying at times, but you get used to it.

Certain flags, objects and variables have predefined meanings. Like there's a flag that determines the walking position of the ego. That's you by the way, the main character. In AGI the main actor object is called ego, get used to it :) So there's a flag that determines the looking/walking direction of the ego. There's a flag for animations, for timers (very basic), for displaying text and what not. These are pretty well defined, but you're hardly warned unless you look for them.

An AGI script consists of a series of commands, with optionally some flow control. Flow control is a mere if-else and goto with labels. The catch, something that least caught me, is that the curlies are required. That makes the else if pretty annoying, but such is life. Other than that AGI has a set of commands. Compared to current languages one might be tempted to think they are objects with methods. They are not. The dot (.) is not an operator. It's just a character that's part of the command. What we'd use camel casing now for.

There are about 256 commands. These compile into byte code (hence, 256). These commands range from displaying text to walking directions for players to "shaking" the screen. WinAGI has a good help file listing all of them and will help you get along with these commands pretty quickly.

WinAGI also has an editor for creating new graphics like the environment, objects and character models. Note that most of the instability I've encountered lied here. For me, changing the order of an animation and compiling afterwards (required) crashed the IDE. This was a pretty stable crash for me. Luckily compiling code didn't have that problem :) The IDE doesn't really allow you to import images so you're pretty much on your own there. Luckily for you there's not that many pixels to begin with, but it'll still take up a lot of time to get right. All media can be easily used inside the game. You can change the name of the resource and simply refer to that name.

So let's do some examples. You're in a black world with some anonymous character. We'll pretend it's just dark and you're wearing lights in your cloths. Saves us some time on scenery :p It's dark so you want to turn on the lights. As usual in these games, you also want to allow the player to look around and examine stuff.

There's one important thing to be explained before continuing; the game loop. Like I said there are Logic files, one file for each room. However there's a Logic0 file, this contains the main game logic. It should not really be changed. So we start in Logic1. The main game loop runs a dozen of times per second. Each time it processes the entire file, regardlessly. So you have to be careful about what you want to execute without an if. Let's do some basic stuff.

Code: (AGI Script)
if (new_room) {
set.horizon(45);
print("Welcome to our little adventure. It's dark and you have no idea what's going on. That should reflect reality, no?");
}
if (said("look")) {
print("It's dark. Maybe if you look closer you can find a light switch or something...");
}
if (said("examine")) {
// show temp non-blocking message near vault
f15 = false; // make print listen to timer
v21 = 4; // wait 4*0.5 sec before removing message
print("*peep*");
}

So the script will be executed continuously and every if statement checked constantly. Whenever you say something, said will actually check whether it meets your criteria. If so, it will execute a certain code block. That's all there is to it, really.

The new_room is one of the built in flags. It will be set whenever the game loop runs for the first time when entering a room. It is automatically unset after that, so it's great to put your room initialization logic under it. You can check prev_room_no to see where the ego was coming from. The set.horizon command sets the artificial horizon height for this room. The coordinates run from 0,0 in the top-left corner to about 180,160 in the bottom right corner. Depending on a flag (see ignore.horizon and observe.horizon), the ego is normally not allowed to cross the horizon. After that a message is printed. This message will disappear once the user presses a key.

When you say "hello world", nothing matches. The game will detect no "rule" has matched the input and display a generic "no idea" message, to indicate this input is not recognized. When you say "look around", the game will match a word "look" in the "look" group, and parse the code block. It will print a message on screen again, for which the user has to press a key. When the user says "examine", certain flags are set and the message will disappear on its own after 4 seconds. Alternatively, the user can get rid of the message by pressing a key. There are a couple of different methods for displaying text on screen.

Likewise, there are a bunch of methods for moving the player (or other objects) around. Make an actor follow the ego. To load and unload resources. To control the environment (like input, status bar, etc). And general methods like doing math and controlling flags. To get more information about it, just open WinAGI's help file and search for "command". Start reading because there's enough to go 'round.

While working with AGI during Q42's w00tcamp I actually kind of liked the engine. I mean, it's very limited, but you can still achieve a lot with it. Heck, the existing legacy speaks for itself. I'm wondering whether the engine could be applied to other state of the art engines. Or a derivative of it. I was tempted to put an idea on my project list for doing a simple engine in js for AGI, but Martin beat me to it a long time ago. By far. He built the whole frigin engine for the web (open source).

The game we created was built using WinAGI (do not forget to put the cygwin1.dll in the same dir as your project AND your system32 dir, no need to completely install cygwin). We then exported it using Sarien.net and put it online. Note that we started from scratch, knowing virtually nothing about the engine or environment. In two days we built half of our office (no, really!), a few colleagues and some texts. You can find the demo here.

For this demo, you can use "look" and "examine" in a few rooms (mostly the initial). Use "skip" to go to the next room, the web conversion bugged a few transition points. In the meeting room (where there's another guy) you can say "kom hier" (come here, in Dutch) and the guy there will respond depending who you are. If you are our boss, he'll "follow" you. Otherwise he'll tell you to bugger off. You can type "morph" to switch character on the spot. You can type "secret" to start the adventure mode. It's just a few lines, but you have to turn on the lights. I'll give you the secret password; its 2458. Or was it 2548? I've forgotten :p

I hope we'll publish the source somewhere soon. I wonder whether I'll ever play around with AGI again....