Interactive Fiction Tutorial

JACL is a language for writing interactive fiction. 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 source code for this tutorial game is included at end of this guide and in the games subdirectory of your JACL distribution.

Language Syntax

JACL is an interpreted language. This means that the interpreter directly reads your program source cde and executes it without the need for it to be compiled first. Each JACL command or definition must be on a line of its own and may not exceed 1024 characters in length. 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. If a command accepts parameters, each parameter must be separated by white space.

Any text that appears between a hash (#) or a semicolon (;) and the end of the line is considered a comment and has no affect on the program's execution. Comments are useful to explain the purpose of your code to other authors or to refresh your own memory when returning to old code.

One special use of comments is to tell the command shell the location of the interpreter that can execute your program. The first line of most JACL programs will be something like:

#!/usr/local/jacl.1.13/bin/jacl

If a JACL program has a first line similar to this, when it is executed directly the shell will pass the name of the program as an argument to the interpreter specified after the #!. This means that the following shell command:

./grail.jacl

becomes the equivalent to the following command:

/usr/local/jacl.1.13/bin/jacl grail.jacl
In order for this to work on Microsoft Windows, you must be running a Unix shell under Cygwin. To work under Unix, the JACL program must be set to executable using a command such as:
chmod 755 grail.jacl

Although the core JACL language is identical for all three interpreters, there are differences some in places. Special mention will be made when a piece of code only applies to one particular interpreter. In these situations any reference to the cgijacl interpreter is to be taken as being applicable to both of the web-based interpreters, cgijacl and fcgijacl, unless otherwise specified.

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, string, parameter and grammar. A function begins with a left curly brace ({) followed directly by its name, and ends with a right curly brace (}) on 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 nine definitions. While 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.jacl from the directory jacl-1.13/games/include to a file called game.jacl in the directory jacl-1.13/games. This new file is the one you will edit to create your game.

The file frame.jacl is a skeleton program that provides a good starting point when writing a piece of interactive fiction from scratch. The file verbs.library, is also included from the last line of frame.jacl. While the code in frame.jacl should be modified to suit your game, the code in verbs.library should never be modified. This allows new versions of verbs.library to be installed without adversely affecting your game. verbs.library contains a extensive set of verbs for use by the player during the game.

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

Locations

We will now begin to add the code for the first location. In text adventure games, a location represents a discrete 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 as there are already two locations pre-defined. These are the locations limbo, defined in verbs.library and prologue, defined in frame.jacl. As objects cannot be be dynamically created or destroyed while the game is being played, any object that is to be removed from the game should be moved to limbo, and any object that is to be introduced mid-way through the game should begin in limbo. When the game is over, either by the player dying or winning the game, the function +game_over should be called. When being played with one of the cgijacl interpreters, this function moves all the player's possessions to limbo and the player to prologue. When being played with the jacl interpreter, this function issues an endgame command.

Add this location by inserting the following line of code below the initial comment lines at the top of the file:

location bedroom: master bedroom

This 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.

All the locations and objects you define have associated properties. When you define an object or location it is possible to set the initial value of these properties. For the new location bedroom we are going to set the intial value of two properties: short and west. This is done by adding two more lines to the location definition so it looks like this:

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

short is a two-value 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 indefinite article, the second is its description. The supplied indefinite article is used to prefix the description when the {list} macro is used. This would normally be a or an.

The {list} macro is used as a 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 are inside another object or held by another object, such as a desk drawer or the player's inventory. Below is an example of the {list} macro:

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. It is more common for locations to be referred to using the {the} macro. This macro displays the object's definite article (the word the by default) 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 special type of variable that can refer 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:

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 master bedroom.

There is also one special purpose indefinite article: name. If name is specified as an object's article, 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 Names and Descriptions of Objects.

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 long 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 last object or location defined above it in the game file. 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 chapter 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 "
write "large, soft bed in the centre of the room "
write "while a doorway to the west leads into the "
write "bathroom.^"
}

write statements are one of the areas where behavior varies depending on whether the game is being played with the jacl interpreter or a cgijacl interpreter. The jacl interpreter will automatically discard any text between angle brackets such as the <p> tag at the start of the first write statement. The cgijacl interpreters will of course output these tags. The caret symbol (^) will tell all the interpreters to start a new line. With cgijacl this translates to a new line in the HTML code sent to the player's web browser, while the jacl interpreter will start a new line on the player's screen. The jacl interpreter will use the configured screen width to word wrap as required. For more information see the chapter on Screen Display.

As 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 the 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 "
write "exit from here is back east into the "
write "bedroom.^"
}

{movement
if COMPASS = east : COMPASS = out
   write "<p>You bang your head as you walk "
   write "through the doorway.^"
   break false
endif
write "<p>The only exit from here is to the "
write "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 verbs.library to represent static numerical values. All the directions that can be travelled in from a location are stored in a 12 element array. These numerical values correspond to the index of the array element that stores the destination for that direction.

The Player

Now that we have our small, two-location world, we need a player to explore it. There is a definition for an object with the label kryten in frame.jacl. 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     ;SPECIFY STARTING LOCATION HERE
 player
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 of this definition 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 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 contains 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 indefinite article. When using a {list} or {the} macro, anything other than the word name is printed verbatim. When name is specified, 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 boolean 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 verbs.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. If the player attempts to talk to 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 chapter 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 verbs.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 object 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 an object definition may be placed in any order. There are other properties that can be associated with an object that we have not set here, as the defaults used when they are absent are valid for our purposes. All of the possible properties are discussed in the chapter 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. Any other commands required to set the initial state of the game-world can also be placed in +intro. Below is the +intro function for the tutorial game. Insert this text just above the final #include line of the program:

{+intro
if interpreter = CGIJACL
   write "<center>"
   write "<H1>TUTORIAL GAME</H1>"
   write "<p>by I.F. Author</p>"
   write "</center>"
else
   clear
   centre "T U T O R I A L   G A M E"
   centre "by I. F. Author"
   write ^^
endif

write "<p>Your alarm rings and you climb out "
write "of bed. Monday morning again so soon. Oh well, "
write "at least your house doesn't have a front door "
write "so you have a good excuse for not going to "
write "work.^^^"

if here hasnt OUTDOORS
   set north_wall(parent) = here
   set south_wall(parent) = here
   set east_wall(parent) = here
   set west_wall(parent) = here
endif
set ground(parent) = here
look
}

This function begins by checking which interpreter the program is currently being executed by. If it is being executed by one of the cgijacl interpreters, some HTML is output. If it is being executed by the console-based interpreter, the clear command is used to clear the screen then the centre command is used to display some text centred on the current line. For more information on these commands see the chapter on Screen Display.

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.jacl 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 by first typing the command from within the games subdirectory:

../bin/cgijacl game.jacl

Next, using your favourite web browser, navigate to the URL http://localhost:8080. When you do so, you should see something like the screen below. If not, see APPENDIX C: Trouble Shooting.

 

 

You can also play the game from the console using the command:

../bin/jacl game.jacl
./game.jacl

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.

>examine north wall
There is nothing special about the north wall.

As you can see, at this stage there is very little for the player to interact with in this game. Therefore, the next thing we will do is add another object: a small wooden box.
Once you have modifed a JACL game, it is important for the game file to be reloaded. This is usually done by the interpreter automatically by checking the timestamp of the file. If for any reason this test fails, stop and restart the cgijacl interpreter. If any objects, locations or variables are added or removed, all old saved game states will become invalid. For this reason it is important to either start with a fresh user ID or delete the contents of the temp directory. To be issued with a fresh user ID, simply restart the game with no URL parameters.

Add the small wooden box by inserting the following object 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 and 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 article 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 this 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, scenery is a constant with a value of 100 while heavy has a value of 99. An object that has its mass set to heavy will have its long text displayed when the object is in the current location, but can't be taken by the player. 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 him or her 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 last location defined above it in the game file. 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 play 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 note's parent property is followed by the label of the box object. This indicates that the note is to start the game inside the box. If this parent property where to be omitted, the note would begin in the bathroom along with the box, as this is the last 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 restart the game, 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 verbs.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, lets take a closer look at the verb read. The grammar definition and the global function for the verb read can be found in verbs.library and are reproduced here:

grammar read *present >read

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

This 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 makes a move, 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 move. 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 the global 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 will 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. The +close function 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 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 "
   write "room.^"
else
   write "<p>You are in the living room. There "
   write "is a small television perched on a low-lying "
   write "table in front 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 this 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 "
write "showing on the 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 "
write "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,~ "
write "Rick mumbles with out looking up. You have "
write "quite a strong suspicion that he didn't "
write "really hear a word you said.^"
}

The above talk_to function is associated with Rick in the same way that the read function was associated with the note earlier. For a complete list of all the grammar statements defined in the library and the names of the functions they call, see APPENDIX B: Library Verb Functions.
As double quotes are used to enclose any command parameter that contains spaces, attempting to print a double quote directly to the screen will not give the desired results. Wherever you want to print a double quote put a tilde character (~) and the interpreter will print a double quote in its place.

To code a response to the player asking Rick about something in particular, you need to associate a function that has a compound name with the object rick. The grammar definition for the command ask noun1 about noun2 calls the function ask_about, so this is the beginning of the function name. You specify which object is being asked about by appending an underscore and then the label of the object to the function name. For example, the following function (when associated with the object rick) will be called if the player types the command ask rick about note:

object rick: son boy teenager rick
 ...

{ask_about_note
write "~Yep, that's a note,~ Rick says "
write "looking at your blankly.^"
}

This give a custom response when the player asks Rick about the note, 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 from each and every object that prints your required response. The easy way is to write a +default_ask_about function and test whether 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. Here is the code to create a default response for whenever Rick is asked about an object:

{+default_ask_about
if noun1 = rick
   write "<p>Rick blinks several times then "
   write "pokes out his bottom lip. This, you have "
   write "figured out over the years, translates to, "
   write "~Not a clue.~^"
   break
endif
break false
}
If both this function and the specific ask_about_note function exist, the ask_about_note function will be executed if player types ask rick about note in preference over this function.

The first thing this function does is test the current value of noun1. As disscussed above, noun1 and noun2 are object pointers that point to the first and second objects referred to in the player's move. If this is currently set to rick, our new default message will be displayed. 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. The order that functions are called in and the precedence they have over each other is fully detailed in the chapter on Functions.

The Passing of Time

In many games actions will occur based on the passing of time rather than the direct actions of the player. If the player was to do nothing other than type wait, 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 each of their moves. If the player's move 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 "
   write "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 "
write "television, you get quite a shock to see Rick "
write "rapidly growing a coat of hair and foaming at "
write "the mouth. The shock of this is only surpassed "
write "surpassed by that of him sinking his newly "
write "acquired fangs into your throat.^"
execute +game_over
}

Okay, so killing the player without any real warning is grossly unfair, but is serves as a demonstration of how to code the player dying. The function +game_over is defined in the file frame.jacl. The code within it moves the player to a special location called prologue that is also defined in frame.jacl. The player's score is then displayed and they are presented with the option to restore a previously saved game, restart or quit.

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 the 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 "
   write "find this week's 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 "
write "week's programmes.^"
}
It is important with objects that share names, such as the television and the television guide to be aware of which object has the most names. If only shared names are used, the object with the lowest number of names will be selected. For more information, see the chapter on 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. The points command will increase the player's 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 "
write "snatches the guide from your hands.^"
write "<p>Satisfied that you have achieved "
write "at least one thing today, you decide to "
write "go back to bed.^"
points 50
execute +game_over
}

And so the game is won. The extra 50 points give the player a total of 100, and the function +game_over is executed.

In order to make this tutorial game more complete, other moves the player is likely to try would need to have custom responses added by associating the appropriate functions with the appropriate objects. The more obvious of these include: showing the guide to Rick, telling Rick about the guide and sleeping on the bed. In fact, the more moves you can give custom responses to, 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.

Although not a large or complex game, this tutorial game does demonstrate most of the elements of JACL that you will need to create a more complete piece of interactive fiction. The rest of this guide contains a complete description of every feature of the JACL language and interpreters. It is recommended that you at least skim through these chapters in order to gain an awareness of the features at your disposal.