Tutorial

Writing adventure games using JACL is easy. By providing short definitions for objects and locations you will rapidly build your virtual world. By associating small amounts of simple code with these objects and locations you will bring your world to life. During the course of this tutorial you will see the construction of a small text-only game from beginning to end. The full code for this tutorial game is included in the appendix and in the games subdirectory of your JACL distribution. As this game contains no web-specific features, it can be played locally using TACL as well as over the web using JACL. Please note that unless otherwise specificed, all references to JACL also include the TACL. Features that are only available in one interpreter or the other will be clearly stated.

Program Structure

A JACL program consists of two fundamental components: data and code. Data is provided in the form of definitions, code in the form of functions. There are nine types of definition, their keywords being location, object, synonym, filter, variable, constant, parameter, prefix and grammar. A Function begins with a left curly brace followed directly by its name, and ends with a right curly brace in a line on its own. Any text that appears on the lines between the two curly braces is considered to be the code body of that function. Other than comments, the only text that can appear outside a function is one of the eight definitions. Where definitions are read once at the start of the game then stored in memory, functions are executed from the game file as required during play.

Getting Started

To begin writing your first adventure game using JACL you will need to copy the file frame to another file called game.acl. By convention I like to use the extension .acl for games coded to work with both JACL and TACL, .jacl for web-only games, and .tacl for console-only games.

Once you have copied frame, concatenate the file library to the end of game.acl. This can be done using the command:

    cat library >> game.acl

The files library and frame contain functions and definitions that are common to most text adventure games. The difference between the two files is that frame, the significantly smaller of the two, contains code that will require game-specific modifications, while the contents of library should be left untouched. Both library and frame can be found in jacl-1.5/lib.
The contents of the library file should always be the last part of your game file and never modified in a game-specific manner. This allows it to be stripped off and a later version concatenated back onto your game at any time.

If you wish to player your game on the web, the file game.acl now needs to be placed in the directory specified in your Apache configuration as the home for all FastCGI scripts. If you have installed Apache in /usr/local/, this will be /usr/local/apache/fastcgi-bin. For more information see Installation. The file will also need to be executable by the user that your copy of Apache runs as. This can be determined by looking for the user directive in your httpd.conf file or by doing a ps aux command once Apache is running.

Now open game.acl, the beginnings of our tutorial game, with your favourite text editor. The name game.acl has been chosen for the purpose of this tutorial. Your game file can be given any name you choose.

Program Header

At the top of the file you will see the following few lines:


   #!/usr/local/jacl-1.5/bin/jacl
   # --------------------------------------------------------------------------
        prefix          ;Put game identifier here
        constant        GAME_VERSION    1
   # --------------------------------------------------------------------------

In JACL, a hash symbol or a semicolon indicates that the remainder of the line is a comment and should be ignored by the interpreter. In the header to our program there are three comments. The second two are purely aesthetic, while the first is very important. The first, although ignored by the JACL interpreter itself, tells the shell that the file is a JACL program, and the location of the executable to interpret the file. This line may require modification depending on where you have installed the JACL package.

If your game is likely to be played both locally and across the web, it is best to leave the first line pointing to the JACL interpreter. To play the game from console, you simply need to use the command:


     tacl game.acl

If you are sure the game will never be played over the web, you can change the first line to point to the TACL interpreter. This will allow you to run the game directly provided it has the execute bit set. For example:


     chmod +x game.acl
     ./game.acl

The third line of our program is a prefix keyword and must be followed by a short text string that is unique to this game. This text string is prefixed to the players user ID to create a file name to save the state of their game to. As players will often use the same user ID for all the games on any given site, this prevents any given game restoring the state of another. The prefix keyword is ignored by the TACL interpreter as it is not required on a single-user system. It is best for all games to include a prefix lines, however, so that it may be played using either system. For the purpose of this tutorial, this should be modified to read:


        prefix             TUTORIAL-

The final part of the header is the definitition of a constant called GAME_VERSION. It simply indicates that this is version one of our game. You should increment this number each time you release a new version of your game.

Locations

We will now begin to add the code for the first location. In text adventure games, a location represents a physical space that the player and other objects can be in, such as a room in a house. Although objects can also be placed inside other objects, the player can only be in a location.

Strictly speaking, this will not be the first location in our game. There are already two locations pre-defined in the library file: limbo and prologue. As objects cannot be be dynamically created or destroyed, any object that is to be removed from the game should be moved to limbo, and any object that is to be introduced to the game mid-way through should begin the game in limbo. When the game is over, either by the player dying or winning the game, the function +end should be called. When playing over the web, this function moves all the player's possessions to limbo and the player themselves to prologue.

We add this location by inserting the following text directly below the prefix definition:

      location bedroom: master bedroom
        short       a "master bedroom"
        west        bathroom

The first line states that we wish to define a location with the label bedroom. This label is the name by which we will refer to this location within our code. For those of you with previous programming experience, you can think of this label much in the same way as a variable name. Following the location's label is a space-delimited list of names by which the player can refer to this location. All locations must have at least one name, and may have as many as can fit into a single line of code. In this example, the location has two names: master and bedroom.

Each line of JACL code must be on a line of its own and may not exceed 1024 characters long. Any single parameter that includes spaces, commas, colons or tabs must be contained within double quotes, as these are all considered to be white space. Each individual parameter must be separated by white space.

Here I must confess that the earlier statement of all data coming in the form of six definition keywords was a slight over-simplification. Locations and objects also have associated properties that can be set to have initial values, such as the short and west properties on the next two lines of our location definition.

short is a two-parameter property used to supply a short description of the location. This description is used by the library code when referring to the location in a sentence. The first parameter after the keyword short is its pronoun, the second is its description. The supplied pronoun is used to prefix the description when the {list} macro is used. This would normally be a or an.

A {list} macro is a possible parameter of a write command. It is normally used when referring to an object or location in a list of several objects or locations. The most common example of this is a list of objects that inside another object or held by another object, such as a desk drawer or the player's inventory. Consider the following line of code:

     write "<p>The house you are in has " bedroom{list} ".^"

When executed, this line of code will display:

     The house you are in has a master bedroom.

The {list} macro is more commonly used with objects than locations, as only objects can be taken or placed inside other objects. More common for locations is the use of the {the} macro. This macro displays the word the followed by the object or locations short description text. For example:

     write "<p>You are in " bedroom{the} ".^"

will display:

     You are in the master bedroom.

"Why not just write You are in the master bedroom directly?" I hear you ask. Given the above two lines of code, you could. The {list} and {the} macros are normally used, however, with an object pointer, not an object label. An object pointer is a variable that can point to a different object or location at any given time. The most common object pointer is noun1. This pointer represents the first object referred to in any given command typed by the player. For example, consider the folowing line of code:

     write "<p>There is nothing special about " noun1{the} ".^"

If the player was to type the command examine bedroom, the above code would produce the output:

     There is nothing special the bedroom.

There is also one special purpose pronoun: name. If name is specified as an object's pronoun, the short description text will not be prefixed with anything whether displayed using noun1{the} or noun1{list}. This would normally be used when the description text is a proper noun. For more information on macros, see the section on Printing the Name of Objects.

Before moving on I should probably say a few words about screen display. The above write commands all begin with an HTML paragraph tag and end with a caret. The paragraph tag is processed by the web browser when playing the game using JACL, while the caret is used to display a linefeed when playing the game using TACL. TACL will automatically filter out all HTML tags, so by including both you are ensuring that your game can be played successfully using either interpreter.

The third line of our location definition states that if the player travels west from this location, then they should be moved to a yet-to-be-coded location with the label bathroom. You will learn more about this soon.

The next thing we will do is give the location its description. This is the text that the player will see when they are in this location. We do this by associating a function called look with the location definition.

A function can be associated with an object, a location or be global. Any function whose name does not begin with a plus sign is automatically associated with nearest object or location above it in the program. Any function whose name does begin with a plus sign is said to be global. A global function is in no way associated with a particlar object or location. More information about functions and how they are associated with items is provided in the section on Functions.

Below is the code for the look function to be added directly beneath the definition for the location bedroom. This function simply consists of three write statements:


     {look
     write "<p>You are in your bedroom. There is a large, soft bed "
     write "in the centre of the room while a doorway to the "
     write "west leads into the bathroom.^"
     }
The first name of a function must come directly after the left curly brace and the right curly brace must be in the left-most column on a line of its own. Although each line of code within the function must also be on a line of its own, it can start in any column.

As we discussed earlier, the definition of the location bedroom refers to a second location called bathroom, located to its west. We will now add this second location to our game. The code for this new location should be placed after the look function that is associated with the bedroom.

     location bathroom: bathroom
       short        the "bathroom"
       east         bedroom
       out          bedroom

     {look
     write "<p>You are in the bathroom. The only exit from here "
     write "is back east into the bedroom.^"
     }
     
     {movement
     if COMPASS = EAST : COMPASS = OUT
        write "<p>You bang your head as you walk through the "
        write "doorway.^"
        break false
     endif
     write "<p>The only exit from here is to the east.^"
     }

There are two points of note with this new location definition. Firstly, it demonstrates that it is quite valid (and in some cases highly desirable), to have more than one direction lead to the same location. In this case, if the player travels east or out from this location, they will be moved to the location with the label of bedroom. This completes the logical two-way connection of the bedroom to the bathroom, and the bathroom to the bedroom.

Secondly, it has a movement function associated with it. This function is called whenever the player moves, or attempts to move, out of this location. If this function issues a break false command, the move will continue as normal. If the function issues a break true command, the move will be prevented from taking place. Any function that reaches its closing brace will terminate as though it had issued a break true command. For move information on movement functions, see the section on Movement. The if statement in the movement function says that if variable COMPASS equals EAST or OUT, then the code up until the matching endif command should be executed. The variable COMPASS is set to the direction the player is attempting to move in before the movement function is called. For more information on the if command, see the section on Flow Control.

EAST and OUT are constants predefined in the library file to represent static numerical values. These numerical values correspond to the index of the location element that represents each of the directions.

The Player

Now that we have our small, two-location world, we need a player to explore it. At the top of the file frame there is a definition for an object with the label kryten. This object has been made with the specific purpose of representing the player and looks as follows:

     object kryten: myself self me
       short     name "yourself"
       has       ANIMATE; FEMALE
       capacity  42
       parent    ;PUT THE LABEL OF THE STARTING LOCATION HERE
       player
Time for a bit of trivia. The label kryten was chosen for the object representing the player after playing Infocom's Zork I with frotz's o option. This shows the object representing the player as having the name cretin. Being both an Infocom fan and a Red Dwarf fan, the choice was obvious.

The first line starts with the keyword object. This tells the interpreter that we want to define a new object with the label kryten. The words following this label are a list of names for the object. This, as you will have noticed is exact same format as defining a new location.
In JACL, a colon is treated as white space (as is a comma and tab). I simply use a colon in preference to a space in certain places to make the code more readable.

The second line is a short keyword. This has the same purpose as the short keyword associated with bedroom above. In the case of our object kryten, however, the word name appears as the pronoun. When using a {list} or {the} macro, anything other than the word name is printed verbatim. When name is specified, however, the JACL interpreter will not prefix the short description text with anything. For example, when noun1 points to the object kryten, the following code:

     write "<p>You can't take " noun1{the} .^
     write "<p>You can't take " noun1{list} .^ 

will produce the output:

     You can't take yourself.
     You can't take yourself.

The third line of the object definition starts with the keyword has followed by the attribute ANIMATE. Both objects and locations may have as many or as few of the available attributes as required. Attributes are simply a set of flags that can be given to and taken from objects and locations at any stage during the game. They are frequently tested for by code in the library. For example, the standard function to open an object will first check that it doesn't have the attribute LOCKED before taking away the attribute CLOSED, thus resulting in it becoming open. The attribute ANIMATE is tested for by functions associated with actions such as talking and killing. If the player attempts to talk to or kill an object that does not have the attribute ANIMATE, they are informed that the action is not logically possible. As well as various other special-purpose attributes, there are five (CUSTOM1 to CUSTOM5) that have no predetermined function and may be used by the game author as required. For a more information, see the section on Attributes.

Following the attribute ANIMATE, you will see a semicolon then the attribute FEMALE. A semicolon (or hash symbol) signifies that all text following it, until the end of the line, is a comment. Comments have no effect on a game, they are only there to serve as notes for the author’s benefit. In this case, deleting the semicolon will mean that the extra attribute will no longer be ignored. This will cause the player to be referred to in the feminine by all code in the library.

The fourth line, beginning with the keyword capacity, indicates how many mass units the object can hold. In the case of an object with the attribute ANIMATE (such as this object representing the player), it indicates how much they can carry. In the case of an object with the attribute CONTAINER, it indicates how much can be placed inside it, while in the case of an object with the attribute SURFACE, it indicates how much can be placed on top of it.

The fifth line, beginning with the keyword parent, is followed by the label of another object or location. This indicates where the object is to be when the game starts. In this game, the player is to start in the location bedroom, so we must modify this line to read:


       parent    bedroom

The final line has the keyword player. This keyword tells the interpreter to set the pointer player to equal kryten before the game begins. Only one object should have the keyword player defined, although the object pointer player can be changed to point to another object at any stage during the game if desired.

The properties that are associated with a location or object definition may be placed in any order following the line containing the location or object keyword. There are other properties that can be associated with an object, the defaults used when they are absent, however, are valid for our purposes in this instance. All of the possible properties are discussed in the section Definitions in Detail.

Some Introductory Text

When a game is started or restarted, the function +intro is executed. The main purpose of this function is to display the game's title, the author's name and some text introducing the game. This is done using write and centre commands. The centre command, as you will have probably guessed, displayed the supplied text in the centre of the current row. The JACL interpreter achives this by inserting <CENTER> tags around the text, while the TACL interpreter inserts spaced based on the current screen width. Any other commands required to set the initial state of the game-world can also be placed in +intro.

     {+intro
     centre "<h1>TUTORIAL GAME</h1>"
     centre "by I.F. Author"
     write "<p>Your alarm rings and you climb out of bed. "
     write "Monday morning again so soon. Oh well, at least "
     write "your house doesn’t have a front door so you have "
     write "a good excuse for not going to work.^^^"

     if here hasnt OUTDOORS
        move north_wall to here
        move south_wall to here
        move east_wall to here
        move west_wall to here
     endall
     move ground to here
     }

The final block of code moves all the wall objects to the current location if the current location doesn't have the attribute OUTDOORS. These objects are defined in the file frame and should be moved to the current location each time the player moves to a location that doesn't have the attribute OUTDOORS. This is done using the same block of code placed in the global function +movement. When the function +intro is executed, the current location will always be the starting location. For this reason, the if statement is not strictly necessary, but it is a good safeguard none the less.

Objects

You can now try playing the beginnings of this game using either interpreter. To play using your favourite web browser, go to the address http://localhost/fastcgi-bin/game.jacl. When you do so, you should see something like the screen below. If not, see the section on Trouble Shooting.

To play from the console, copy the tacl binary to somewhere in your PATH such as /usr/bin and type the command:


    tacl game.acl

Once playing, the following commands should give you the responses shown:

     >w
     You are in the bathroom. The only exit from here 
     is back east into the bedroom.

     >i
     You are empty-handed.

     >smell
     Nothing strikes you as out of the ordinary.

     >listen
     You don't hear anything out of the ordinary.

     >sit
     You plonk yourself down for a moments rest.

As you can see, at this stage there is very little to do as there is only one object in the game: you! Therefore, the next thing we will do is add another object: a small wooden box.

The above statement is not strictly true. As mentioned above, in the file frame there are five objects defined. These represent the north, south, east and west walls and the ground.

Once you have modifed a web-based JACL game, it is important to either kill any existing instances of the game or restart the Apache server. Use the command ps aux | grep game.acl to determine the process IDs you will need to kill. If any objects, locations or variables are added or removed, all old bookmarks will become invalid. For this reason it is important to start with a fresh user ID. To be issued with a fresh user ID, simply restart the game with no URL parameters.

We will add this next object by inserting the following definition after the bathroom's look function.

     object box: small wooden box
       has          CLOSABLE CONTAINER CLOSED
       short        a "small wooden box"
       long         "There is a small wooden box here."
       mass         25
       capacity     20

The first line says that we are defining an object and that it should have the label box. It then goes on to say that it can be referred to by the player with any combination of the names small, wooden and box.

The second line states that it should have the attributes CLOSABLE, CONTAINER and CLOSED. These attributes tell the appropriate verbs in the library that this object may be opened, closed, have things placed inside it and that it should be closed when the game begins.

The third line, as with the short statement for the object kryten, indicates the text to appear when either the object's {list} or {the} macro is used. In this case, however, rather than name, the pronoun is set to a. Therefore, when noun1 is set to box:

     write noun1{list}

will display "a small wooden box", while

     write noun1{the}

will display "the small wooden box".

The fourth line, beginning with the keyword long, details the text to be displayed when the object is in the current location. If an object has a mass of scenery, the long text will not be displayed. This is because a mass of scenery indicates that the object cannot be taken and should therefore be described in its parent location's look function instead, if at all.

Internally, heavy is constant with a value of 99 while scenery has a value of 100. It is good to keep this in mind when choosing a mass value for each object.

The fifth line sets this object to have a mass of 25. When the player takes an object, the value of the object's mass property is subtracted from the player's capacity property. This indicates that the player's capacity property must currently be 25 or greater for them to be able to take the box. Any other container object the player attempts to put the box in or on must also have a capacity property that is currently 25 or greater.

The final line, a capacity property, indicates how many mass units the box can hold. In this case it is set to 20. This means that other objects may be placed inside this object (due to it having the CONTAINER attribute) until the total of their mass properties equals 20.

As this new object has no parent property, it will start the game in the bathroom. This is because the bathroom is the nearest location above it in the program. Any objects with no parent property will begin in the nearest location above it regardless of the number of object or function definitions inbetween.

Before we access the game again, we will add a second object by putting the following code beneath the definition for the box.

     object note: orange note
       short       an "orange note"
       long        "An orange note rests on the ground."
       parent      box
       mass        5

As you can see, the parent property is followed by the label of our box object. This indicates that the note is to be inside the box when the game begins. If this parent property where to be omitted, the note would begin in the bathroom along with the box, as this is the nearest location defined above it in the game file.

If the box object had the attribute SURFACE rather than CONTAINER, the note would start the game on top of it. If the box object had the attribute ANIMATE, the note would start the game being carried by it.

Verbs and Functions

Now if you access the game (don't forget to kill any old processes if you are playing on the web), you can walk west into the bathroom and find our small wooden box. You can take it, open it, look in it, closed it, and apply a whole range of other standard verbs present in the library to it. When it is open, you will also be able to take the orange note out of it.

To explain a little bit about how verbs work, we will take a closer look at the read verb. The grammar definition and the global function for the read verb can be found in the library file and are reproduced here:

     grammar read *present >read

     {+read
     write "<p>There is nothing on " noun1{the} " to read.^"
     set TIME = false
     }

The grammar definition states that if the player types a command of the format

"read ObjectThatIsPresent" during the game, then the function read should be executed.

When the player types a command, the JACL interpreter will set the object pointers noun1 and noun2 to point to any objects referred to. They will be set based on the order the objects appear in the command. For example, if the player types the command give sword to troll the +give_to function would be called with noun1 being set to the sword and noun2 being set to the troll.

Returning to our read example, upon identifying the player's command as matching this grammar definition, the JACL interpreter will first attempt to execute a function called read that is associated with object that the player is referring to. If this does not exist, it will try to execute the same function name only prefixed with a plus sign. This is a global function and can be thought of as the default action that occurs for that verb if no object-specific one is provided.

Since we have not associated a read function with our note object, when the player attempts to read it global the function +read will be executed. If you try is this you will see that the default action for the read verb is very simple, but appropriate for most objects. The default function +read is not an appropriate, however, for our note object. We will therefore replace it by adding a function called read that is associated with the object note. This function is even simpler:

     {read
     write "<p>Welcome to Jamaica and have a nice day.^"
     }

We associate this function with the note object by typing it directly after the note object's definition. For clarity, you can of course leave a blank line or two in between the note definition and read function. This local read function would now be executed in place of +read whenever the player types the command read note, provided the note is visible to the player.

The read function above should really be given two names. This is done by placing the second name after the first, such as {read : examine. This means that both reading and examining the note will lead to the same code being executed. Any function may have as many names as can fit in a single line of JACL code.

Overriding Functions

Compared to +read, the +close function is quite long. Although the default +close function is perfectly suitable for our needs, we will use it to demonstrate overriding the default outcome of a function. It is reproduced here:

     {+close
     break +reach noun1
     if noun1 hasnt CLOSABLE
       write "<p>You can't close " noun1{the} .^
       set TIME = false
       break
     endif
     if noun1 has CLOSED
       write <p> noun1{The} noun1{is} " already closed.^"
       set TIME = false
       break
     endif
     override
     write "<p>You close " noun1{the} .^
     ensure noun1 has CLOSED
     }

During the course of the +close function, several tests are performed to determine the appropriate outcome. At the point in the function where it is decided that the command should be successful there is an override command. This command tells the JACL interpreter to look for a function called close_override that is associated with the object that the player is attempting to close. If this exists it will be executed in place of anything beyond the override command. If this does not exist, then execution of the +close function continues as normal from the line following the override command.

The reason for the override command is that a close function associated with any object will get called straight away, completely replacing all the code in the default function +close. This means that any test, such as whether the object is already closed, will have to be repeated manually in the new, local function. This is not so much of a problem with a simple verb like read, as no tests are performed, but with some other verbs this can be a considerable amount of code. The override command therefore provides an opportunity at the last moment to override only the outcome, not the entire function.

To demonstrate, we will override the normal outcome of closing the box. This is done by associating the following function with the object box:

     {close_override
     write "<p>The lid creaks as you push it closed.^"
     ensure box has CLOSED
     }

When the box is closed by the player, all the tests before the override command in the +close function will be executed. If all the tests pass, the code in close_override will be executed in place of any code after the override command.

It is important to be careful that you use an override function (or perform the tests manually) whenever a verb has several possible outcomes. If the above function was to be called close, as opposed to close_override, then the box could be closed over and over again – clearly a bug.

We will now add a third and final location. This location will be a living room and will be placed south of the bedroom. Add the following location definition beneath the close_override function that is associated with the box:

     location living_room: living room
       short        the "living room"
       north        bedroom

     {look
     if here has VISITED
        write "<p>You have returned to the living room.^"
     else
        write "<p>You are in the living room. There is a small "
        write "television perched on a low-lying table in front "
        write "of a sofa.^"
     endif
     }

The look function associated with the living room is slightly more complex than those associated with the other locations. After the player enters a location for the first time, it is automatically given the attribute VISITED by the JACL interpreter. This latest look function tests the current location for this attribute and displays a shorter, more appropriate description if it has it. Feel free at this stage to go back and add this test to the look functions for the bedroom and bathroom.

As you may have guessed, the next thing we will need to do is add an additional line to the definition of the bedroom to indicate that the player can travel south to get to the living room. This line should be placed beneath the west property giving the complete definition of:

     location bedroom: master bedroom
       west        bathroom
       south       living_room

Non-player Characters

Most games will include at least one character other than the player, and our small tutorial game is no exception. The character we will add is the player’s son who will be sitting in the living room watching television. Fortunately for us, simulating the responsiveness of a teenager watching television is not hard.

We will begin by adding the following two object definitions and their associated examine functions beneath the definition for the living room:

     object television: television tv tele
       short       a "television"
       mass        scenery


     {examine
     write "<p>There is currently a cartoon showing on the "
     write "television.^"
     }

     object rick: son boy teenager rick
       has          ANIMATE
       short        name "Rick"
       long         "Rick is here, watching television."
       mass         heavy


     {examine
     write "<p>Rick is staring blankly at the television screen.^"
     }

To make both Rick and the television respond to the player's commands, we will be required to associate more functions with each of them. This process of creating objects and associating functions with them is the essence of writing text adventure games using JACL.

The first action we will cater for is talking to Rick. The grammar statement that matches the command talk to rick calls the function talk_to. Therefore, in order to give a custom response to this command, we must associate a talk_to function with the object rick. This function should look as follows:


     {talk_to
     write "<p>~Uh, yeah, I'll do it in a minute,~ Rick "
     write "mumbles with out looking up. You have quite a "
     write "strong suspicion that he didn't really hear "
     write "a word you said.^"
     }
For a complete list of all the grammar statements defined in the library (and the names of the functions they call), see the appendix.

The above talk_to function is associated with Rick in the same way that the read function was associated with the note earlier. Should the player ask Rick about something in particular, however, the solution is not so straightforward. We can't simply associate a generic ask_about function, as there is always a second object involved. For example, to give a custom response to the player asking Rick about the note, we would need to associate the function ask_about_note with the object rick. This, by itself, is not particularly difficult, but what if we want to give the same custom response no matter what object Rick is asked about? The hard way would be to associate a function for each and every object. The easy way is to write a +default_ask_about function and change the response when the person being asked is Rick. This is a global function (as indicated by the leading plus sign), so it doesn't matter where you put it in the code. I tend to use comments to mark off a section where all the varying types of global functions can live. Here is the code to change the default response for ask_about when Rick is the person being asked:

     {+default_ask_about
     if noun1 = rick
        write "<p>Rick blinks several times then pokes out his "
        write "bottom lip. This, you have figured out over the "
        write "years, translates to, ~Not a clue.~^"
        break
     endif
     break false
     }

The first thing to happen when this function is called is that the current value of noun1 is tested. As disscussed above, noun1 and noun2 are object pointers that point to the first and second object referred to in the player's command. If this is currently set to rick, our new default message will be displayed. The only point of in the above function is the tilde character (~). When the write command encounters a tilde it will print a double quote.

If noun1 is not set to rick, a break false command is executed. This command causes the interpreter to do whatever it would have normally done had this function not existed at all. In this case, the result would be to perform the original default action specified in the library.

The global default function for any given action is called when an override command is reached and a specific override function for the object or objects in question does not exist. To demonstrate, if the function ask_about_overrride was now associated with the object rick, it would be called in preference to our new, global default. This allows specific responses to be given when asking about certain objects, while still having a custom default for all others. The order that functions are called in and the precedence they have over each other is fully detailed in the section on Functions.

The Passing of Time

Life goes on, with or without the player, and every now and then you will want to code for this. If the player was to do nothing other than type wait commands, people would still come and go, the song playing on a nearby radio would change and the sun would set. All these events would be coded for within an eachturn function. There can be an eachturn function associated with each location and a single global one.

The variable TIME is automatically set to true before the player types a command. If the player's command is not possible, this variable should be set to false. If, when the command has been fully processed, TIME is still set to true, the appropriate eachturn functions are executed. The first function executed, if it exists, is the eachturn function that is associated with the location the player is currently in. When this has finished, the global function +eachturn is executed. Once +eachturn has finished executing, the processing of the player's command is complete.

To demonstrate, we will make Rick take a sip from his drink every five turns, regardless of what the player does. Due to the fact that the player would not see this without being in the living room, we will put the code in an eachturn function associated with this location. Since this function is only executed when the player is in the living room, in reality the action will only occur after the player has spent a total of five turns there. Associate the following function with location living_room:

     {eachturn
     set rick(status) + 1
     if rick(status) = 5
        write "<p>Rick takes a sip from his drink.^"
        set rick(status) = 0
     endif
     }

The status property of an object is set and tested in the same way as the parent property. The status property, however, has no pre-determined use so we are free to use it as our counter. The code in the eachturn function increments this status property by one after each successful move made in the living room. When it equals five, a message is displayed and it is set back to zero. The process will then loop over and over again. If an action should happen every so many turns regardless of where the player is, put the code in +eachturn.

Winning and Losing the Game

Our mini game is not much good unless it can be won. For this to happen, the player must have a goal and be awarded points for each obstacle they overcome along the way. The goal for this game is going to be to find the television guide and give it to Rick. To make this game a fiendishly-clever, all-time classic, we are going to hide the guide under the bed.

Before we do this, however, we are going to introduce an element of danger by adding some code to cater for switching the television off. We already have an object for the television, so all we need to do now is associated a turn_off function with it. This should look like the following:

     {turn_off
     write "<p>As you reach over and switch off the television, "
     write "you get quite a shock to see Rick rapidly growing "
     write "a coat of hair and foaming at the mouth. The shock "
     write "of this is only surpassed by that of him sinking "
     write "his newly acquired fangs into your throat.^"
     execute +death
     }

Okay, so killing the player without any substantial warning is grossly unfair, but is serves as a demonstration of how to code the player dying. The function +death is defined in the file frame. The code within it displays the player's score presents them with the option to restore a previously saved game or restart or quit. TACL also presents the player with the option to undo their last command.

Before we move on to winning the game, it is worth mentioning that the default response for turning an object on is to say that this cannot be done. In the case of the television, it would be important to add a turn_on function stating that the television is already on.

Now, on to this television guide. To implement this puzzle we are going to need two more objects: the guide itself and the bed to hide it under. Begin by defining an object for the bed somewhere beneath the definition for the bedroom (but before that for the bathroom). Beneath that, add a definition for the television guide. The television guide must have its parent property set to limbo until the player has discovered it. The location limbo is defined in the library and is used exclusively for situations such as this where we need somewhere to temporarily store objects that the player should not have access to. Finally, we must associate a look_under function with the bed that moves the guide to the bedroom and awards the appropriate points. Here is the complete code for this:

     object bed: bed
       short       a "bed"
       mass        scenery

     {look_under
     if guide(parent) = limbo
        write "<p>Hidden under the bed you find this week's "
        write "television guide.^"
        set guide(parent) = here
        points 50
        break
     endif
     write "<p>You don't find anything else.^"
     }

     object guide: television tv tele guide
       short       a "television guide"
       long        "The television guide is here."
       parent      limbo
       mass        5

     {examine : read : look_in
     write "<p>It contains a listing of this week's programmes.^"
     }
It is important with object that share names, such as the television and the television guide to be aware of which has the most names. If only the shared name is used, the object with the lowest number of names will be selected. For more information, see CHAPTER 13: Object Resolution.

Now, when the player looks under the bed, the guide will be moved from its initial location, limbo, to the bedroom. Once this has been done, the player will be able to take it. When executed, the points command will also increase their score by 50%. The if statement in this function ensures that this can only be done once.

We will now associate a give_to_rick function with the guide. This will be the winning move and should look like this:

    {give_to_rick
    write "<p>~Cool!~ Rick exclaims as he snatches it from "
    write "your hands.^"
    write "<p>Satisfied that you have achieved at least one "
    write "thing today, you decide to go back to bed.^"
    points 50
    execute +gameover
    }

And so the game is won. The extra 50 points give the player a total of 100, and, like the +death function, +gameover presents the player with a range of options to continue.

Before it could really be considered complete, however, extra commands would need to be catered for by associating the appropriate functions with the appropriate objects. The more obvious of these includes showing the guide to Rick, telling Rick about the Guide and sleeping on the bed. In fact, the more commands you can give custom responses for, the more depth and character the game will have. Also, anything prominent that is mentioned in a location's description, such as the table and sofa in the living room, should also be defined as objects. This enables the player to refer to them, even if they aren't important to solving the game.