The ADL Programmer's Reference Manual

Tim Brengle

Ross Cunniff

ABSTRACT

ADL (which stands for "Adventure Definition Language") is a programming language and run-time environment designed for the convenient implementation of Adventure-like games. This document describes ADL and is intended for the use of a programmer who wishes to create such a game.

The authors would like to acknowledge the tremendous influence of the earlier language DDL from which ADL was derived. DDL was created in 1981 by Bruce Adler, Chris Kostanick, Michael Stein, Michael Urban, and Warren Usui, then members of the UCLA Computer Club. For information on DDL, please consult the document "A Brief Description of UCLA Dungeon Definition Language (DDL)" written by the creators of DDL.

Notes

Note: the "classic" version of the ADL Programmer's Reference Manual - useful for reference when looking at older sources - can be found at http://adl.sourceforge.net/classic.html. Documentation on the programs which constitute the ADL system can be found at the following links:

http://adl.sourceforge.net/adlcomp.html The ADL compiler
http://adl.sourceforge.net/adlrun.html The ADL interpreter
http://adl.sourceforge.net/adldebug.html The ADL binary examiner

SourceForge Logo
This document is hosted by SourceForge at:

http://adl.sourceforge.net

For more info, see the ADL project page at:

http://sourceforge.net/projects/adl

ADL was originally released in 1987 under a "freeware" license. Some minor modifications have been made through the years, and the license terms have since been modified to the standard Gnu Public License.

Several ADL examples can be found formatted at http://adl.sourceforge.net/samples/samples.html


Table of Contents

1. Introduction
2. ADL Data types
2.1. Objects
2.2. Verbs
2.3. Adjectives
2.4. Strings
2.5. Numbers
2.6. Routines
2.7. Global Variables
2.8. Local variables
2.9. Modifiers
3. ADL Internal Structures
3.1. Actors
3.2. Daemons
3.3. Fuses
3.4. Prompter
3.5. Run-Time Macros
4. Putting It All Together
4.1. The Flow of Execution
4.2. $exit
5. ADL Programs
6. Routines
6.1. Proc Declaration
6.2. Statements
6.3. Expressions
7. ADL Built-in Routines
7.1. Object Routines
7.2. Verb Routines
7.3. Arithmetic Routines
7.4. Boolean Routines
7.5. Global Value Routines
7.6. Transition Routines
7.7. String Manipulation Routines
7.8. Name Routines
7.9. Conversion Routines
7.10. Internal Structure Manipulation Routines
7.11. Special Routines
7.12. Miscellaneous Routines
8. ADL Program Structure
9. ADL Sentence Structure
10. stdproc.adl
10.1. Object properties
10.2. Constants
10.3. Words
10.4. Verbs and their actions
10.5. Routines
Appendix 1 - A Tiny Dungeon
Appendix 2 - A scenario with multiple Actors
Appendix 3 - Glossary

1. Introduction

Computer games have existed for nearly as long as computers have existed. One of the most popular computer programs of all time is Adventure. In Adventure, the player is placed inside a world which exists only in the memory of the computer (and the mind of the player). The player interacts with this world by means of English-like sentences. Objects that the player finds may be taken, opened, closed, tasted, thrown, and otherwise manipulated.

Previously, most programmers attempting to write their own Adventure-like game have been bogged down by such trivial details as implementing a parser for player input, properly responding to the player's commands, and dealing with the passage of time. ADL is intended to relieve the programmer of such worries and to allow the programmer to concentrate on the important details of the imaginary world. The following is a short excerpt from the play of a game which was written in ADL:

     Red room.
     You are in a large room which is illuminated by a bright red glow.
     Exits lie to the east and south.
     > Go east.
     Green room.
     You are in a smallish room which is illuminated by a pleasant green
     glow.  The only exit is to the west.
       There is a robot here.
     > west
     Red room.
     > s
     Blue room.
     You are in a tiny room which is barely illuminated by a dim blue
     glow.  There is an exit to the north, and you seem to make out
     something on the floor.  There is a button on the wall.  Above the
     button is a sign that reads:

                     DANGER!

                  HIGH VOLTAGE!

     > n
     Red room.
     > e
     Green room.
     You can see:
       a robot
     > Tell the robot "Go west then south.  Push the button then go north."
     "Sure thing, Boss."
     The robot exits to the west.

Notice that this script demonstrates powerful features not present in many other Adventure-like games. This document will describe the utilities and "tricks" necessary to write games such as the above.

Return to Contents


2. ADL Data types

Structured data types are the heart of any structured language. ADL is not lacking in structured data types. It is through the proper definition of specific instances of these data types that the ADL programmer defines a scenario. Note that all data types in ADL are represented by sixteen bit integer IDs. Although there is little facility for producing user-defined data types, the power of the existing set makes it unlikely that such would be required for any reasonable scenario.

Return to Contents

2.1. Objects

As in most Adventure-like games, the most important data type in ADL is the Object. An object in real life can be a person, place, or thing. ADL models the world in the same way. Any Object encountered by the player is represented by this type, as are all locations in the scenario. Indeed, there can be Objects associated with people (more on that later). Notice that ADL treats all Objects uniformly and so it is possible to write a scenario in which a player picks up an Object (a tent, say), carries it around, and later enters it.

All Objects are represented by (unique) sixteen-bit integers. This number is known as the "Object ID" of the Object. Objects are (essentially) record structures with the following elements:

LocationThe Object ID of the Object which contains this Object.
ContentsThe Object ID of the first Object which is contained in this Object, or zero if there is no such Object.
LinkThe Object ID of the next Object which is located in the same place as this Object or zero if there is no such Object.
ModifierThe ID of the modifier of this Object or zero if the Object has no modifier. For example, the Object "blue streak" would have a modifier ID which is the adjective "blue". Modifiers are explained further in Section 2.9.
PropertiesAssociated with each Object are 48 properties. While all of the above elements are maintained directly or indirectly by the ADL system, the values and meanings of properties are the responsibility of the programmer. The first 32 of these properties may only hold the value 0 or 1 (hence they are usually called "boolean" properties). Properties 33 through 48 may hold any value between -32768 and 32767. The last three of these properties have special meaning to ADL:
LDESCThis is the ID of a routine which prints a "long" description of the Object. Routines are defined in Chapter 6.
SDESCThis is the ID of a routine which prints a "short" description of the Object.
ACTIONThis is the ID of a routine which is called under the circumstances detailed in Chapter 4.

All Objects in ADL are stored in a tree. The root node of the tree is predeclared and is named "$ALL". Its Object ID is always zero. All other Objects are ultimately located in $ALL.

Two other predeclared Objects exist. One is named "STRING" and the other is named "$ME". $ME is not truly an Object -- it is more like a variable which represents the current Actor during the execution of an ADL program (more on Actors in Section 3.1). It is illegal to use $ME outside of the context of a routine. STRING is the Object which is seen by the ADL program when the run-time sentence parser encounters a string. Note that although STRING is predeclared by ADL, the properties of STRING must be defined by the ADL programmer. See Chapter 9 for more information on STRING.

Return to Contents

2.2. Verbs

Verbs are the means whereby a player manipulates the environment. Verbs can denote motion, investigation, manipulation, and any other action the ADL programmer can imagine. A Verb is represented by a sixteen-bit integer known as the Verb ID. Like Objects, Verbs are record structures. They have the following elements:

PREACTThe ID of a routine to be called when this Verb is typed by the player. The routine is called before the ACTION routines of the Objects in the sentence. See Chapter 4 for more information.
ACTIONThe ID of a routine to be called when this Verb is typed by the player. This routine is called after the ACTION routines of the Objects in the sentence. Again, see Chapter 4 for more information.

Verbs may also be used as modifiers to nouns. This is to allow easy implementation of Objects like the "north wall" or "go north" (where "north" is normally a verb of motion).

ADL predeclares the two Verbs "TELLER" and "NOVERB" which are returned by the parser under circumstances shown in Chapter 9. Although TELLER and NOVERB are predeclared, their properties must be defined by the ADL programmer.

Return to Contents

2.3. Adjectives

Adjectives serve only one purpose: to disambiguate otherwise identical nouns (such as a "red ball" and a "blue ball"). Adjectives have no structure and exist only as sixteen-bit Adjective IDs.

Return to Contents

2.4. Strings

There are two forms of strings in ADL: compile-time strings and run-time strings. Compile-time strings are those which appear in the ADL source code for the scenario. They are delimited by double quotes and are transformed into positive sixteen-bit String IDs by the compiler. These strings are free-form in that a carriage return may appear in them at any point. This sort of carriage return is transformed into a blank. Should the ADL programmer desire a true carriage return, the sequence \n should be embedded in the string at the appropriate point. Compile-time strings may be limited to 255 characters in length in some implementations.

Run-time strings are those which are typed by the player and those which are generated by the built-in string manipulation routines. Strings in player input may be delimited by appropriately nested single or double quotes. All run-time strings are represented as NEGATIVE sixteen-bit string IDs.

Return to Contents

2.5. Numbers

There are two forms of numbers in ADL: compile-time numbers and run-time numbers. Compile-time numbers exist in the ADL source code for the scenario and may be any integer in the range of -32768 to 32767 inclusive. Run-time numbers are those which are typed by the player. Run-time numbers are transformed into a string consisting of the ASCII representation of their digits. A negative string ID is then returned for eventual use by the ADL program.

Return to Contents

2.6. Routines

Routines in ADL are represented by (what else?) sixteen bit Routine IDs. The only operations allowed on routines are calling them and passing them to other routines as parameters. The syntax of ADL routines is described in Chapter 6. The routine "START" is predeclared by ADL and must be defined by the programmer or execution will be prematurely terminated. The Routines "DWIMI" and "DWIMD" are also predeclared by ADL and should be defined by the programmer. DWIMI and DWIMD are called under circumstances detailed in Chapter 4.

Return to Contents

2.7. Global Variables

There are a number of global variables available for definition and use by the ADL programmer. A global is represented by a sixteen-bit ID and may hold any integer value from -32768 to 32767. These values may be interpreted as simple numbers, String IDs, Routine IDs, Object IDs, Verb IDs, etc. depending upon how they are used. The globals named Verb, Conj, Numd, Dobj, Prep, and Iobj are predeclared by ADL and at run-time contain the values of the current Verb, Conjunction, Number of Direct Objects, Direct Object, Preposition, and Indirect Object, respectively.

The ADL programmer may declare a block of global variables for use as an array or list of things. See Chapter 5 for more information.

Return to Contents

2.8. Local variables

Local variables differ from global variables in that their name is limited in scope to the routine in which they appear. They are represented by sixteen-bit IDs which may be passed to other routines if desired. Local variables are implemented on the stack (like local variables on C and Pascal); this means they only persist for as long as the current invocation of the routine.

Return to Contents

2.9. Modifiers

A modifier is simply a word that modifies an ambiguous noun to produce an Object. A modifier may be either a Verb or an Adjective. If the modifier of an Object is a Verb, it is represented as the NEGATIVE of the Verb ID. If it is an Adjective it is represented by the (positive) Adjective ID. If the modifier is zero, the Object has no modifier.

Return to Contents


3. ADL Internal Structures

ADL maintains several internal structures to achieve the level of interaction necessary for interesting play. These structures are accessible only through the built-in routines described in Chapter 7.

Return to Contents

3.1. Actors

In a typical adventure game it seems as if the player is moving around the dungeon taking things, smelling them, breaking them, and so on. A better model would be that the player is giving commands to an actor. It is the actor which actually moves around, collects items, and otherwise acts. It is this model which ADL follows.

An Actor is essentially an "animate" object which acts upon commands given to it. Notice that there is nothing in this model which prevents more than one Actor from running around a scenario. In fact, in ADL there may be up to ten Actors which are active at any one time.

There are two kinds of Actors: interactive and non-interactive. The player is an example of an interactive Actor. Commands are read directly from the keyboard and placed in a line buffer which is then passed to the parser and interpreter. When the line buffer is empty a new one is read from the keyboard. Any number of Actors may be interactive, making multiple player games a possibility.

The robot in the introductory script is an example of a non-interactive Actor (see Appendix 2 for the source to the scenario which produced that script). The line buffer for the robot was initialized after the player typed the sentence starting with "Tell the robot ...". The robot then acted on this command by performing the requested actions in parallel with the actions of the player. This means that each Actor gets one turn for each turn that the player experiences. A non-interactive Actor is deleted from the list of active Actors when its line buffer is emptied.

There is a special object-like item named "$ME" used to implement this sort of "multiprocessing". $ME represents the Object ID of the current Actor for the purposes of moving around, taking things, etc. Anything that the player can do can be done just as well by another Actor. This is probably the most powerful (and most obscure) feature of ADL.

Actors may be activated using the $actor built-in routine and deleted at any time by using the $delact routine.

Return to Contents

3.2. Daemons

Daemons are routines which execute once for each active Actor at the beginning of each turn. Daemons are typically used for things like describing the player's location and incrementing the turn counter. Daemons are activated by using the $sdem routine and may be de-activated by using the $ddem routine. Up to ten daemons may be active at one time.

Return to Contents

3.3. Fuses

Fuses are routines which wait a certain amount of time, execute, then become inactive. The list of fuses is examined each time the turn counter is incremented to see whether any have "burned down". If so, the fuse is executed and deleted from the list.

Fuses are typically used for things like waiting three turns and then collapsing the room that the player was in, or (the bane of all adventurers) running down the batteries in a lamp. Fuses are activated by using the $sfus routine. Up to ten fuses may be active at one time. The $dfus routine may be called if the programmer wishes to delete a fuse before it executes (the player found more batteries!).

Return to Contents

3.4. Prompter

Many times during the play of the game it is desired that a player enter a line from the keyboard. Some sort of prompting should be done in order to inform the player that input is desired. The ADL programmer may specify a Routine ID to do this prompting. This routine is known as the prompter and is set by using the $prompt routine.

Return to Contents

3.5. Run-Time Macros

Normally when the parser gets its input from the line buffer of the current Actor, the words are what they seem to be: simple words. ADL has a facility whereby these words may be transformed before the parser sees them. Each word is looked up in a table (the "macro table"). If found it is replaced by the expansion for the macro (which may be a string containing more than one word) and re-inserted into the line buffer whereupon the input process continues.

One use of this facility is to "rename" objects. For example, it may be desired that the player be able to type something like "Name the box 'bob'. Take bob." (notice that the second usage of bob has no quotes). This can be accomplished by the call $define("bob", "box") which says to expand "bob" to "box" whenever it is encountered in the line buffer. The built-in routine $undef may be used to "undefine" a macro if it outlives its usefulness -- for example $undef("bob") removes "bob" from the macro table. More is said about macros in Section 7.10 under the entries for $define and $undef.

Return to Contents


4. Putting It All Together

The flow of execution of the game can be described now that the basic data types have been defined. The execution starts with an initialization step: an ADL routine named START is called. ADL terminates prematurely if START has not been defined. START typically activates the principal Actor (the player) and a looker daemon (responsible for describing the player's surroundings), initializes the prompter, and so on. ADL then enters a loop from which it never returns (until program termination).

Return to Contents

4.1. The Flow of Execution

The main loop of the game consists of a series of phases. The built-in routine $phase will return the number of the phase currently executing (see the flow diagram and Section 7.12 for the number of each of the phases). At the beginning of each turn, all active Daemons are executed for each Actor on the Actor list -- in the REVERSE order in which the Actors were activated. This is so newly activated Actors don't act before the older Actors have a chance to act. The Daemons are executed in the order in which they were activated.

After all Daemons have executed for all Actors, a series of phases are executed for each Actor on the Actor list (in the reverse order of Actor activation). The loop progresses downward in an orderly fashion unless interrupted by a call to $exit. For information on $exit see Section 4.2. The following are the phases which are executed for each Actor on the Actor list:

Clear SentenceThe global variables Verb, Conj, Numd, Dobj, Prep, and Iobj are set to 0. This is done in a separate phase to facilitate the implementation of incremental sentences such as "Take. The red ball."
InputA new line buffer is prompted for and read if the line buffer is empty and the current Actor is interactive.

The current Actor is deleted from the Actor list and execution continues starting with the next Actor if the line buffer is empty and the current Actor is NOT interactive.
ParseAll upper case letters in the line buffer are transformed into lower case letters. An attempt is then made at parsing the line buffer into a Verb, Direct Objects, a Preposition, and an Indirect Object. Note that unambiguous abbreviations of words are recognized by the parser (for example, if the words "newt" and "newspaper" are in the vocabulary, "new" is ambiguous but "news" is an abbreviation of "newspaper"). An appropriate message is printed if this does not succeed and execution continues from the Input phase.

ADL sentences are typically of the form "Verb DobjList Prep Iobj" "Verb Iobj DobjList", or "Iobj, String". This is an overly simplistic description - for a full specification see Chapter 9.
DWIMAn object may be ambiguous either through the lack of a modifier or through the use of a modifier without a noun (e.g. typing "Take the ball" when there is both a "red ball" and a "blue ball", or typing "Take red" in the same situation).

An ADL routine named "DWIMI" is used if the Indirect Object is ambiguous. DWIMI is called once for each Object that could possibly be the one meant by the player. If EXACTLY one of these calls returns a non-zero value then the corresponding Object becomes the Indirect Object. However, if DWIMI never returns a non-zero value or if it returns a non-zero value more than once, the player is told to be more specific and execution continues starting with the Clear Sentence phase above.

An ADL routine named "DWIMD" is used if any of the Direct Objects are ambiguous. DWIMD is called for the Objects in question just like DWIMI.
ExecutionThe following phases are executed for every Direct Object in the Direct Object list. They are executed exactly once if there are no Direct Objects. This loop is the heart of the ADL system and is where the player's commands are actually carried out.
Actor ACTIONThe ACTION routine of the current Actor is executed. It typically checks the sentence and possibly modifies it. This allows the handling of cases like "Take the beer then drink it" (where "it" needs to be massaged to mean "beer") and "Go north. Again." (where "Again" needs to be transformed into "Go north").
Verb PREACTThe PREACT routine of the current Verb is executed. It typically guards against incorrect use of multiple Direct Objects, or the use of Indirect Objects or strings where such use doesn't make sense. It also might check that all objects named are available for use.
Iobj ACTIONThe ACTION routine of the current Indirect Object is executed. This is where some object-specific actions are performed. For example, the sentence "Put the coins in the slot" might be handled here if putting coins into the slot (as opposed to a box or a bag) causes something special to happen. If the Indirect Object is a string then the ACTION routine of the predeclared ADL Object named STRING is executed.
Dobj ACTIONThe ACTION routine of the current Direct Object is executed. This is where most object-specific actions are performed. For example, the sentence "Rub the lamp" might be handled here if rubbing the lamp is different than rubbing any other Object. The ACTION routine of the predeclared ADL Object STRING is executed if the Direct Object is a string.
Verb ACTIONThe ACTION routine of the current Verb is executed. This is where general default actions are usually handled. For example, the sentence "Rub the floor" might result in the message "Rubbing that object is not useful."
Room ACTIONThe ACTION routine of the current Actor's location is executed once the above loop has examined all of the Direct Objects. This routine is typically a "transition" routine -- that is, it might check whether the current verb is "north" and move the current actor to the appropriate location (it might check other directions as well!).

Return to Contents

4.2. $exit

It is possible to change the normal flow of execution by means of the $exit built-in routine. The programmer may use $exit(0) to halt execution of the current phase and move on to the next phase. At any time, $exit(1) may be used to halt the execution of the current phase and skip to the next Actor. Inside the Direct Object loop, $exit(2) may be used to skip the rest of the Object and Verb ACTIONs and go on to the next Direct Object in the list. At any time after the parsing phase, $exit(3) will return the flow of control to the Parsing phase without clearing the sentence. This allows for incremental entry of sentences; for example "The big door. Unlock. With the key".


The following is a diagram of the flow of execution:

ADL execution flow

Return to Contents


5. ADL Programs

This chapter describes the format of ADL programs. An ADL program consists of a list of one or more of the following statements. Comments in ADL programs are delimited by /* and */. Since case is significant in ADL, tokens which are identical except for differing case are different (for example, "noun" is not the same as "NOUN").

Note: for a full BNF specification of ADL programs, see Chapter 8.

INCLUDE "filename";
Input to the ADL compiler is read from filename until the end of file and compilation then resumes from the current file. A file included in compilation by means of an INCLUDE statement may INCLUDE other files. Example:
                     INCLUDE "stdproc.adl";
MESSAGE "message";
The string message is printed on the console at compile time. This is used to remind the programmer of things which should be initialized or to simply reassure the programmer that the compiler is indeed reading the file. Example:
                     MESSAGE "Whew!  We're halfway through the file!\n";
VAR name, name, ... ;
This declares each name to be a new global variable. The contents of global variables are initialized to zero. Each name must not have been previously declared. Each name may be followed by a size specifier, in which case that number of words is allocated.

Example:
                     VAR
                             Score,
                             Dark,
                             ObjList[ 10 ],
                             MyLoc;
Note that ADL does not maintain type information for arrays. This means it is fairly simple-minded about how it does array indexing - and the programmer has to be careful with how they use indexing. ADL tries to make simple array indexing work as you might expect; for example:
                    VAR a[10];
                    FOO = Proc() {
                        a[3] = 2;
                    }
works exactly as you think it should. However, the following example does NOT work well:
                    VAR a[10];
                    FOO = Proc() {
                        Var b;
                        b = &a;
                        b[3] = 2; // Scribble randomly on the stack
                    }
The programmer is responsible for remembering which variables contain addresses, and must add appropriate dereferencing operators. This example *does* work:
                    VAR a[10];
                    FOO = Proc() {
                        Var b;
                        b = &a;
                        (*b)[3] = 2;
                    }
VERB name, name, ... ;
This statement declares each name to be a new Verb. The PREACT and ACTION routines of Verbs are initialized to zero. Each name must not have been previously declared. Example:
                     VERB    take, drop, open, close;
ADJEC name, name, ... ;
This statement declares each name to be a new Adjective. Again, each name must not have been previously declared. Example:
                     ADJEC   red, green, blue;
NOUN ndecl, ndecl, ... ;
This statement declares Objects. Ndecl may take the form obj or obj ( container ). The first form declares a new Object located in the object $ALL. The second form declares a new Object located in container. Each obj may be one of: an undeclared identifier, a modifier followed by an undeclared identifier, or a modifier followed by a previously declared noun. If obj is just an undeclared identifier, the identifer is declared to be a noun and a new Object is created with that noun ID and with a modifier of 0. If obj is a modifier followed by an undeclared identifier, the identifier is declared to be a noun and a new Object is created with that noun ID and with the modifier set to the one specified. If obj is a modifier followed by a previously declared noun, a new Object is created with the specified noun ID and the specified modifier. Note that the declaration "NOUN foo, blue foo;" is illegal since it would be too easy to create situations where the player is unable to disambiguate the Objects. Example:
                     NOUN    room1;
                     NOUN    table( room1 ), chair( room1 ), red ball( room1 );
ROUTINE name, name, ... ;
This statement declares each name to be a new routine. Note that this does not associate a routine with the Routine ID -- it just declares the routine. This is useful for daisy-chaining routines (i.e. routine A calls routine B, which calls routine A) since everything must be declared before it is used. Each name must not have been previously declared. Example:
                     ROUTINE Looker, Prompter, Quitter;
ARTICLE name, name, ... ;
This statement declares each name to be a new Article. Each name must not have been previously declared. Example:
                     ARTICLE the, a, an;
PREP name, name, ... ;
This statement declares each name to be a new Preposition. Each name must not have been previously declared. Example:
                     PREP    in, into, on, above ;
obj (const) = expr ;
This statement assigns property const of obj to be expr. Const must be a number or the name of a constant (see below). Expr may be a string, a number, a routine, another noun, or just about anything else which yields a sixteen bit ID. Obj must be previously declared. A warning may be produced if this particular property is reassigned later in the program. Example:
                     room1( LDESC ) = Proc()
                     {
                         "You are in a huge room.\n";
                     }
                     chair( WEIGH ) = 450 ;
                     table( MSG ) = "This space for rent\n" ;
verb (const) = routine ;
This statement assigns property const of verb to be routine. Const must be either PREACT or ACTION, and verb must have been previously declared. A warning may be produced if this particular property is reassigned later in the program. Example:
                     take( ACTION ) = Proc() {"You can't take that object.\n";}
                     drop( PREACT ) = Proc() {CheckAvail();}
name = expr;
This statement declares that name is equivalent to expr. Name must not have been previously declared and expr may be an object, a string, a routine, a number, or just about anything else that yields a sixteen-bit value. Example:
                     MagicWord = "AbraCadabra";             // string ID
                     VISIT = 3;                             // constant
                     Silly = Proc() {"That's silly!\n";}    // routine ID
                     toolbox = tool box;                     // object ID
(global) = expr;
This statement initializes global variable global to have the value expr. Global must have been previously declared and expr is the same as expr above. Example:
                     ( MyLoc ) = -1;
                     ( Score ) = 10;
(global + const) = expr;
This statement initializes the const'th slot in the global array global to have the value expr. Example:
                     VAR foo[ 10 ];
                     ( foo ) = 3;            { Sets foo[0] to 3 }
                     ( foo + 5 ) = 6;        { Sets foo[5] to 6 }
prep1 obj prep2 = prep3;
This statement declares that if the three-word sequence prep1 obj prep2 is encountered during runtime parsing in the proper position for a preposition, it is to be replaced by prep3. Obj may be a modifier-noun pair and prep1, prep2, and prep3 must have been previously declared. Example:
                     PREP
                             in, of, before;
                     NOUN
                             front;

                     in front of = before;
verb1 prep = verb2;
This statement declares that if the two-word sequence verb1 prep is encountered during run-time parsing in the proper position for a verb, it is to be replaced by verb2. Verb1, verb2, and prep must have been previously declared. Example:
                     VERB
                             put, take, turn, wear, remove, light, douse;
                     PREP
                             on, off;

                     put on = wear;
                     take off = remove;
                     turn on = light;
                     turn off = douse;

Return to Contents


6. Routines

This chapter describes the syntax of ADL routines. The syntax of ADL routines is similar to that of C, with some notable differences dictated by the needs of the adventure game programmer.

Return to Contents

6.1. Proc Declaration

All routines start with the Proc declaration, immediately followed by the main block of instructions, enclosed in curly braaces. The declaration also defines the list of arguments which are expected by the routine. Here is the grammar of the top-level Proc declaration:

                proc            : 'Proc' '(' optnames ')' outerblock
                                ;

                optnames        : // NULL
                                | names
                                ;

                names           : IDENT
                                | IDENT ',' names
                                ;

                outerblock      : '{' locals stmts '}'
                                ;

                stmts           : // NULL
                                | stmt stmts
                                ;

The locals are a series of variable declarations. Any number of variable declarations may be present. Note that neither routine arguments nor local variables may have the same name as any other ADL object - this means, for example, that you cannot have both the verb "n" as well as a local variable named "n". This greatly reduces the potential for confusion. This is the grammar for the local variable declarations:

                locals          : // NULL
                                | 'Var' vars ';' locals
                                ;

                vars            : var
                                | var ',' vars
                                ;

                var             : IDENT
                                | IDENT '[' NUMBER ']'
                                ;

Return to Contents

6.2. Statements

The statements in a block are a series of zero or more of the following:

Procedure call A call to a procedure, with optional arguments. The return value is ignored.
Assignment statement A value is assigned to a variable or object property
Print statement A convenient way to output text to the user
Return statement Execution of the current procedure is terminated and a value returned to the calling procedure
Break statement Execution of the enclosing loop is terminated
Conditional statement The classical If-Else statement
Loop The classical repeating While loop
Nested block A compound series of statements enclosed in curly braces

The grammar for these statements is:

                stmt            : callassgn ';'
                                | return ';'
                                | 'Break' ';'
                                | ifstmt
                                | whilestmt
                                | block
                                ;

                callassgn       : expr '=' expr
                                | expr          // Proc call production
                                | STRING // Print statement
                                | STRING ',' exprlist // Print statement
                                ;

                exprs           : // NULL
                                | expr exprs
                                ;

                return          : 'Return' expr
                                | 'Return'
                                ;

                ifstmt          : 'If' '(' expr ')' stmt
                                | 'If' '(' expr ')' stmt 'Else' stmt
                                ;

                whilestmt       : 'While' '(' expr ')' stmt
                                ;

                block           : '{' stmts '}'
                                ;

Note that, like most Algol-like languages, the "Else" of an ifstmt binds to the most recent "If". This is exactly like C.

Return to Contents

6.3. Expressions

ADL has several built-in operators, and a precedence of evaluation, similar to C. Here is the table of operators, in precedence order:

. [] () Object property, array index, function call
- ~ ! * & Unary negative, bitwise NOT, logical NOT, dereference, address
* / % Integer multiply, divide, modulus
+ - Integer add, subtract
< <= >= > Less-than, less-equal, greater-equal, greater-than
== != ?= Integer equality, integer not-equality, string equality
& Bitwise AND
^ Bitwise XOR
| Bitwise OR
&& Logical AND (with short-circuit semantics)
|| Logical OR (with short-circuit semantics)

Here is the grammar which describes expressions:

                expr            : expr '||' logandexp
                                | logandexp
                                ;

                logandexp       : logandexp '&&' orexp
                                | orexp
                                ;

                orexp           : orexp '|' xorexp
                                | xorexp
                                ;

                xorexp          : xorexp '^' andexp
                                | andexp
                                ;

                andexp          : andexp '&' eqexp
                                | eqexp
                                ;

                eqexp           : eqexp '==' cmpexp
                                | eqexp '!=' cmpexp
                                | eqexp '?=' cmpexp
                                | cmpexp
                                ;

                cmpexp          : cmpexp '<' addexp
                                | cmpexp '<=' addexp
                                | cmpexp '>=' addexp
                                | cmpexp '>' addexp
                                | addexp
                                ;

                addexp          : addexp '+' mulexp
                                | addexp '-' mulexp
                                | mulexp
                                ;

                mulexp          : mulexp '*' unary
                                | mulexp '/' unary
                                | mulexp '%' unary
                                | unary
                                ;

                unary           : '-' dotexp
                                | '~' dotexp
                                | '!' dotexp
                                | '*' dotexp
                                | '&' dotexp
                                | dotexp
                                ;

                dotexp          : dotexp '.' term
                                | dotexp '[' expr ']'
                                | dotexp '(' funargs ')'
                                | term
                                ;

                funargs         : // NULL
                                | exprlist
                                ;

                exprlist        : expr
                                | exprlist ',' expr
                                ;

                term            : NUMBER
                                | STRING
                                | IDENT
                                | < IDENT IDENT > // Compound noun ref.
                                | '(' expr ')'
                                ;

Return to Contents

6.4. Example

The following is a sample ADL routine which demonstrates each of the above constructs and is almost useful as well. See Chapter 7 for the definitions of the built-in routines called.

                    /* A sample looking daemon */
                    Look = Proc()
                    {
                        Var obj;
                        $incturn();      // Increment the turn counter
                        If ($loc($ME).VISIT) {
                            // I've been here before - print a short description
                            $sdesc($loc($ME))();
                        }
                        Else If ($cont($loc($ME)) != $ME) {
                            // There are other objects here
                            $ldesc($loc($ME))();
                            "You can see:\n";
                            obj = $cont($loc($ME));
                            While (obj) {
                                // Describe each object in the room
                                $sdesc(obj)();
                                obj = $link(obj);
                            }
                        }
                        Else {
                            // I've never been here
                            $ldesc($loc($ME))();
                            "There is nothing else in the room.\n";
                        }
                        $loc($ME).VISIT = TRUE;
                   }

Return to Contents


7. ADL Built-in Routines

The following is the complete list of ADL built-in routines. They are organized into groups of related routines. A descriptio of each routine is provided with at least one example to clarify its usage. The following groupings of built-in routines are detailed in this chapter:

7.1 Object Routines
7.2 Verb Routines
7.3 Arithmetic Routines
7.4 Boolean Routines
7.5 Global Value Routines
7.6 Transition Routines
7.7 String Manipulation Routines
7.8 Name Routines
7.9 Conversion Routines
7.10 Internal Structure Manipulation Routines
7.11 Special Routines
7.12 Miscellaneous Routines

Return to Contents

7.1. Object Routines

These routines operate primarily on Objects. They move Objects around, find Object properties, and set Object properties.

$loc
$loc( obj ) -> The location of obj. Example:
                     If ($loc($ME) == volcano) {
                         "You are fried to a crisp.\n";
                     }
$cont
$cont( obj ) -> The first object which is contained in obj. Example:
                     If ($cont($ME) == 0) {
                         "You are empty-handed.\n";
                     }
$link
$link( obj ) -> The next object contained in the same location as obj. Example:
                     obj = $cont($ME);
                     While (obj) {
                         $say($name(obj), "\n");
                         obj = $link(obj);
                     }
$ldesc
$ldesc( obj ) -> The long description of obj. This is equivalent to obj.LDESC. Since this is a Routine ID, it is typically used as the callee in a routine call. Example:
                     obj = $loc($ME);
                     $ldesc(obj)()  // Call LDESC of $loc($ME)
$sdesc
$sdesc( obj ) -> The short description of obj. This is equivalent to obj.SDESC. Since this is a Routine ID, it is typically used as the callee in a routine call. Example:
                     obj = $loc($ME);
                     $sdesc(obj)();  // Call SDESC of $loc($ME)
$action
$action( obj ) -> The ACTION routine of obj. This is equivalent to obj.ACTION. Since this is a Routine ID, it is typically used as the callee in a routine call. Example:
                     $action($ME)();  // Call ACTION of $ME
$modif
$modif( obj ) -> The modifier of obj. This is zero if there is no modifier, negative if the modifier is a Verb, and positive if the modifier is an Adjective. Example:
                     If ($modif( < blue ball > ) == blue) {
                         "$modif works!\n";
                     }
                     If ($modif( < north wall > ) == -north) {
                         "$modif still works!\n";
                     }
                     If ($modif(room1) == 0) {
                         "$modif comes through one more time!\n";
                     }
$prop
$prop( obj, num ) -> The numth property of obj. Exactly the same as obj.num. Example:
                     obj = $loc($ME);
                     If ($prop(obj, VISIT)) {
                         "I've been here before!\n";
                     }
$setp
$setp( obj, num, val ) -> No return value. Sets the numth property of obj to val. Exactly the same as obj.num = val Example:
                     obj = $loc($ME));
                     $setp(obj, VISIT, TRUE);
$move
$move( obj, loc ) -> No return value. Moves obj to loc. WARNING: Do not attempt to violate the tree structure of objects (e.g. $move($ALL, foobar)) or horrible and unpredictable things will happen. Non-horrible example:
                     If (Verb == north)
                         $move($ME, room2);

Return to Contents

7.2. Verb Routines

These two routines operate on Verbs. They are provided for scenarios in which the properties of Verbs may change. Note that there is no "." syntax for doing this - you must use these routines.

$vset
$vset( verb, prop, val ) -> No return value. The property prop of verb is set to val. Prop must be either PREACT or ACTION. Example:
                     $vset(Verb, PREACT, Silly);
$vprop
$vprop( verb, prop ) -> The value of property prop of verb. Prop must be either PREACT or ACTION. Example:
                     /* Call Verb's PREACT */
                     $vprop(Verb, PREACT)();

Return to Contents

7.3. Arithmetic Routines

These routines operate on arbitrary sixteen-bit numbers, and return sixteen-bit values. Note that the numbers may actually be Object IDs, global variable IDs, or any of the sixteen bit IDs used by ADL. Most of these routines have an equivalent syntax (see Expressions, above, for more info).

$plus
$plus( num1, num2 ) -> Returns num1 + num2. Example:
                     Score = $plus(Score, 50);
$minus
$minus( num1, num2 ) -> Returns num1 - num2. Example:
                     LivesLeft = $minus(LivesLeft, 1);
$times
$times( num1, num2 ) -> Returns num1 * num2. Example:
                     TimeLeft = $times(NumBattery, 10);
$div
$div( num1, num2 ) -> Returns num1 / num2. Example:
                     Rating = $div(Score, 100);
$mod
$mod( num1, num2 ) -> Returns the remainder which results when num1 is divided by num2 according to normal integer division (that is, num1 % num2). Example:
                     /* Make sure XPos is from 0 to 9 */
                     XPos = $mod( Xpos, 10);
$rand
$rand( num ) -> Returns a random number from 1 to num inclusive. Example:
                     /* Move the player to a random room from room1 to room10 */
                     Num = $rand(10);
                     $move($ME, room1 + Num - 1);

Return to Contents

7.4. Boolean Routines

These routines are typically used in conditionals and loops. However, traditional bit-masking may be done with $and and $or. Many of these routines have an equivalent syntax (see Expressions, above, for more info).

$and
$and( a, b, c, ... ) -> Returns the bitwise AND of the vector a, b, c, .... Note that since this is the bitwise AND, care must be taken in conditions since ANDing two non-zero values does not necessarily return a non-zero value. Same as a & b & c .... Example:
                     $and(2, 4) is 0 (0b0001 AND 0b0010 = 0b0000)
                     $and(3, 7) is 3 (0b0011 AND 0b0111 = 0b0011)
                     $and(1, 1) is 1 (0b0001 AND 0b0001 = 0b0001)
$or
$or( a, b, c, ... ) -> Returns the bitwise OR of the vector a, b, c, .... Same as a | b | c .... Example:
                     $or(0,0) is 0  (0b0000 OR 0b0000 = 0b0000)
                     $or(1,2) is 3  (0b0001 OR 0b0010 = 0b0011)
                     $or(1,1) is 1  (0b0001 OR 0b0001 = 0b0001)
$not
$not( num ) -> Returns zero if num is non-zero and one if num is zero. Note that this is BOOLEAN NOT and not BITWISE NOT. BITWISE NOT could be coded as ((0 - num) - 1) for a two's complement machine. Same as !num. Example:
                     $not(0) is 1
                     $not(1) is 0
                     $not(5) is 0
$yorn
$yorn() -> Waits for the player to type a line of input, returns one if this line begins with the letter 'Y' or 'y', and returns zero otherwise. Note that no prompt is automatically made for this input. Example:
                     "Are you sure you want to quit? ";
                     If ($yorn()) {
                         "OK.  Goodbye!\n";
                         $spec(3);
                     }
                     Else {
                         "Whew! That was a close one!\n";
                     }
$pct
$pct( num ) -> Returns one num percent of the time and zero the rest of the time. This is equivalent to (num >= $rand(100)). Example:
                     If ($pct(30))
                         "The troll swings at you, and hits!\n";
                     Else
                         "The troll's axe misses you by a hair!\n";
$eq
$eq( num1, num2 ) -> Returns one if num1 is equal to num2 and zero otherwise. Exactly the same as num1 == num2. Example:
                     loc = $loc($ME);
                     If ($eq(loc, room1))
                         "You are in room 1.\n";
                     
$ne
$ne( num1, num2 ) -> Returns one if num1 is not equal to num2 and zero otherwise. Exactly the same as num1 != num2. Example:
                     loc = $loc($ME);
                     If ($ne(LastLoc, loc))
                         "You've moved since I last checked!\n";
$lt
$lt( num1, num2 ) -> Returns one if num1 is less than num2 and zero otherwise. Exactly the same as num1 < num2. Example:
                     If ($lt(Score, 100))
                         "You are a novice adventurer\n";
$gt
$gt( num1, num2 ) -> Returns one if num1 is greater than num2 and zero otherwise. Exactly the same as num1 > num2. Example: Example:
                     If ($gt(Score, 1000)) {
                         "You are a super master grand ";
                         "champion mongo adventurer!!!\n";
                     }
$le
$le( num1, num2 ) -> Returns one if num1 is less than or equal to num2 and zero otherwise. Exactly the same as num1 <= num2. Example:
                     If ($le(Score, 1000))
                         "You are a pretty good adventurer.\n";
                     
$ge
$ge( num1, num2 ) -> Returns one if num1 is greater than or equal to num2 and zero otherwise. Exactly the same as num1 >= num2. Example:
                     If ($ge(Weight, 200))
                         "The ice breaks under your weight!\n";

Return to Contents

7.5. Global Value Routines

$setg
$setg( addr, val ) -> Returns val. Sets the contents of (or the value of) the variable at address addr to be val. Exactly the same as *addr = val.
$global
$global( addr ) -> Returns the contents of (or the value of) address addr. Equivalent to *addr. Example:
                     Given:
                             VAR var[3];
                             (var + 0) = 10;
                             (var + 1) = 20;
                             (var + 2) = 30;

                     The statement
                             $global(2 + &var)
                     would return 30.
$verb
$verb() -> Returns the current Verb. Equivalent to the variable Verb. Example:
                     If ($verb() == take)
                         "You can't take that!!\n";
$dobj
$dobj() -> Returns the current direct object. Equivalent to the variable Dobj. Example:
                     If ($dobj() == ball)
                         "Dobj = ball\n";
$iobj
$iobj() -> Returns the current indirect object. Equivalent to the variable Iobj. Example:
                     If ($iobj() == basket)
                         "Iobj = basket\n";
$prep
$prep() -> Returns the current Preposition. Equivalent to the variable Prep. Example:
                     If ($prep() == into)
                         "Prep = into\n";
$conj
$conj() -> Returns the current conjunction. Equivalent to the variable Conj. Example:
                     If ($conj() == 1)
                         "The conjunction was 'but'\n";
                     Else
                         "The conjunction was 'and' or ','\n";
$numd
$numd() -> Returns the length of the current direct object list. Equivalent to the variable Numd. Example:
                     If ($numd() > 1)
                         "You may not use multiple direct objects!\n";

Return to Contents

7.6. Transition Routines

ADL has an internal structure known as the Transition Vector. This structure is a list of ten verb IDs and is set and used by the following routines. These routines are typically used in the ACTION routines of rooms in scenarios in order to move the player around.

$setv
$setv( verb1, verb2, verb3, ... verb10 ) -> No return value. Initializes the Transition Vector to the list of verbs verb1, verb2, verb3, ... verb10. Example:
                     $setv(north,south,east,west,ne,se,nw,sw,up,down);
$hit
$hit( obj, loc1, loc2, loc3, ... loc10 ) -> No return value. Scans the Transition Vector for a match with the current Verb. If found, obj is moved to the corresponding loc. Nothing happens if no match is found. An attempt to move an object to location 0 ($ALL) is ignored. Example:
                     room1(ACTION) = Proc()
                     {
                         $hit($ME,room2,room3,room4,0,0,0,0,0,0,0);
                     }
$miss
$miss( rout1, rout2, rout3 ... rout10 ) -> No return value. Scans the Transition Vector for a match with the current Verb. If found, the corresponding rout is called. Nothing happens if no match is found. An attempt to call routine 0 does nothing. Example:
                     cg = Proc() {"You can't go that way.\n";}

                     room2(ACTION) = Proc()
                     {
                         $miss(0,0,0,cg,cg,cg,cg,cg,cg,cg);
                     }

Return to Contents

7.7. String Manipulation Routines

There are basically three types of strings which an ADL program uses. The first type of string is the compile-time string (a string which was present in the ADL source file of the scenario). All compile-time strings have a positive string ID and exist for the duration of program execution.

The second type of string is the "volatile" run-time string. Examples of this type of string include strings typed by the player and strings produced by the builtin routines $subs, $cat, $read, $name, $vname, $mname, $pname, $num, and $chr (see also Sections 7.8 and 7.9). Volatile strings have negative string IDs and are "flushed" at the beginning of each turn (just before the Daemon phase).

The third type of string is the "non-volatile" run-time string. These strings also have negative string IDs but they are never "flushed". These strings are produced by the $savestr routine. Note that there is no easy way to distinguish volatile and non-volatile run-time strings.

In the context of the $subs and $pos routines, strings are indexed starting at zero (the first character of the string). The following routines operate on all types of strings:

$eqst
$eqst( str1, str2 ) -> Returns one if str1 has the same contents as str2 and zero otherwise. Note that this is NOT the same as $eq(str1, str2), since the $eq only compares the string IDs of the strings. It is the same as str1 ?= str2. Example:
                     The program:
                             str1 = "hello";
                             str2 = $cat("he", "llo");
                             If ($eqst(str1, str2))
                                 "String 1 == string 2\n";
                             If ($ne(str1, str2))
                                 "String ID 1 != string ID 2\n";

                     will produce the output:
                             String 1 == string 2
                             String ID 1 != string ID 2
$subs
$subs( str, start, len ) -> Returns a volatile copy of the substring of str starting at start and going for len characters. If len is 0, the suffix of str starting at start is returned. Example:
                     The program:
                             str = "Hello world";
                             $say($subs(str, 0, 5), "\n");
                             $say($subs(str, 6, 0), "\n");

                     will produce the output:
                             Hello
                             world
$leng
$leng( str ) -> Returns the length of str. Example:
                     $leng("Hello") is 5
                     $leng("") is 0
$cat
$cat( str1, str2 ) -> Returns a volatile string which is the result of concatenating str1 and str2. Example:
                     $cat("hello ", "world") returns "hello world"
$pos
$pos( str1, str2 ) -> Returns the position of str1 in str2. If> no occurrence of str1 is found in str2, -1 is returned. Example:
                     $pos("hello", "hello world") is 0
                     $pos("Foobar", "bletch") is -1
                     $pos("testing", "This is a test") is -1
                     $pos("is", "This is a test") is 2
$read
$read() -> Returns a volatile string which is read from the player's keyboard. Note that no prompt is automatically generated. Example:
                     "What is your name? ";
                     MyName = $read();
                     "Hello, ", MyName, ", welcome to ADL!\n";
$savestr
$savestr( str ) -> Returns a non-volatile copy of str. Note that str may be any string -- compile time, volatile, or non-volatile. Example:
                     MyName = $savestr(MyName);

Return to Contents

7.8. Name Routines

The following routines all return volatile strings which contain the requested name.

$name
$name( obj ) -> Returns a volatile string containing the (possibly multiple-word) name of obj. Example:
                     "You see no ", $name(Dobj), " here!\n";
$vname
$vname( verb ) -> Returns a volatile string containing the name of verb. Example:
                     "No multiple objects with ", $vname(Verb), "!\n");
$mname
$mname( modif ) -> Returns a volatile string containing: the name of modifier modif (if modif is greater than zero), the name of verb -modif (if modif is less than zero), or the null string (if modif is zero). Example:
                     "The modifier of blue ball is ", $mname(blue), "\n";
$pname
$pname( prep ) -> Returns a volatile string containing the name of Preposition prep. Example:
                     "The sentence is:\n",
                             $vname(Verb), " ",
                             $name(Dobj), " ",
                             $pname(Prep), " ",
                             $name(Iobj);

Return to Contents

7.9. Conversion Routines

The following routines perform conversions between strings and numbers.

$str
$str( num ) -> Returns a volatile string which contains the ASCII representation of num. Example:
                     $str(3) is the string "3"
$num
$num( str ) -> Returns the numeric value of str. Example:
                     $num("234") is the number 234
$ord
$ord( str ) -> Returns the ASCII code of the first character in str. Example:
                     $ord("ABC") is 65
$chr
$chr( num ) -> Returns a volatile string which contains exactly one character, whose ASCII code is num. Example:
                     $chr(97) is the string "a".

Return to Contents

7.10. Internal Structure Manipulation Routines

The following routines are the means whereby the ADL programmer may modify the Internal Structures described in Chapter 3. See also Chapter 4 for the use of some of these routines.

$sdem
$sdem( rout ) -> No return value. Activates rout as a daemon. Example:
                     $sdem(Looker)
                     $sdem(Follower)
$ddem
$ddem( rout ) -> No return value. De-activates rout as a daemon. No action is taken if rout is not an active daemon. Example:
                     $ddem(Follower)
$sfus
$sfus( actor, rout, count ) -> No return value. Activates rout as a fuse associated with actor to be executed in count turns. Example:
                     $sfus($ME, LampDie, 300)
$dfus
$dfus( actor, rout ) -> No return value. Deactivates rout as a fuse associated with actor. No action is taken if rout is not an active fuse. Example:
                     If (BatteryFound)
                         $dfus($ME, LampDie);
$incturn
$incturn( [ nturns ] ) -> No return value. Increments the turn counter by nturns (or 1 if nturns is not given) and activates any fuses associated with the current actor that have "burned down". The "burned down" fuses are then de-activated. The ADL programmer can "halt time" by refraining from incrementing the turn counter. Usually, $incturn() is only called when the daemons are executing for the primary actor. For other actors, $incturn(0) is used to see whether the fuses associated with the current actor have burned down, without incrementing the turn counter. Example:
                     sleep(ACTION) = Proc() {$incturn(300);}
$turns
$turns() -> Returns the current value of the turn counter. Example:
                     If (Verb == north) {
                         If ($turns() > 230) {
                             $move($ME, room3);
                         }
                         Else {
                             $move($ME, room5);
                         }
                     }
$prompt
$prompt( rout ) -> No return value. Sets the prompter to be rout. Example:
                     $prompt(Prompter)
$actor
$actor( obj, str, flag ) -> No return value. Activates obj as a new Actor with the line buffer initialized to str. If flag is non-zero then the new Actor will be interactive. If flag is zero then the new Actor will be non-interactive. If str is zero then the line buffer will be initialized to the empty string. Example:
                     $actor(Myself, NULL, TRUE);
                     str = "Go east then south.  Push button.  Go north";
                     $actor(robot, str, FALSE);
$delact
$delact( obj ) -> No return value. Deletes the Actor associated with obj from the Actor list. No action is performed if obj is not an active Actor. Example:
                     If (robot.BROKEN)
                         $delact(robot);
$define
$define( str1, str2 ) -> No return value. Informs the parser that upon input from an Actor, the string str1 is to be replaced with the contents of str2. This process continues until an infinite loop is detected or until a word is found for which there is no corresponding expansion. Str1 must contain no spaces. Str2 may contain several words separated by spaces. Note that in the case of multiple definitions (such as $define("a", "b") followed by $define("a", "c")), the macro table should be viewed as a stack with $define pushing macro definitions on the stack and $undef popping definitions. Example:
                     If (MyDir == 1) {
                         $define("left", "north");
                         $define("right", "south");
                     Else {
                         $define("left", "south");
                         $define("right", "north");
                     }
$undef
$undef( str ) -> No return value. This routine removes str and its expansion from the macro table. No action is performed if str is not an active macro. Example:
                     $undef("left");
                     $undef("right");

Return to Contents

7.11. Special Routines

$spec
$spec( code, arg1, arg2, ... argN ) -> No return value. Performs a special, system-dependent operation. Note that not all operations exist in all implementations. Consult your local ADL documentation for information.
CodeFunction
1Toggle the instruction trace flag
2Restart this game
3Terminate execution of this game
4Save this game in file arg1
5Restore this game from file arg1
6Execute the system program named arg1
7Preserve unknown words in file arg1
8Write a script to file arg1
9Print a header line on the screen
10Set the right margin
Code 1 Toggles the instruction trace flag. If this flag is set, an instruction trace and stack dump are printed for every ADL instruction executed (a very messy but informative process).
Code 2 Re-initializes all ADL structures and variables, re-executes START, and generally starts the game over from the beginning.
Code 3 Terminates the game immediately, no questions asked.
Code 4 Saves a "core image" of the ADL structures and variables sufficient to restore the game to the same position later. Arg1 is the name of the file to which the core image should be written.
Code 5 Reads a "core image" which was created by a previous invocation of $spec(4, file), thus restoring the game to its previous state. Arg1 is the name of the file from which the core image should be read.
Code 6 Runs the program arg1 with arguments arg2 through argN. All arguments must be strings, except the last argument which must be 0.
Code 7 Starts recording those words from the player's input which are unrecognized by the run-time parser. The words are appended to the file named by arg1. This recording is stopped if arg1 is 0.
Code 8 Starts recording a "script" of all input and output produced during the subsequent execution of the game. The script is written into the file named by arg1. Stops recording if arg1 is 0.
Code 9 Prints a line of the form "Room Name Score: NN Moves: NN" at the top of the screen. It is assumed that arg1 is the name of the room, arg2 is the current score, and arg3 is the number of turns that have passed.
Code 10 Sets the right margin to arg1. This function is provided for the use of those games whose messages would look better on narrower (or wider) screens than the default of 80 columns.
Examples:
                     VERB debug;
                     debug(ACTION) = Proc() {$spec(1);}

                     VERB restart;
                     restart(ACTION) = Proc() {$spec(2);}

                     VERB quit;
                     quit(ACTION) = Proc() {$spec(3);}

                     VERB save;
                     save(ACTION) = Proc()
                     {
                         Var name;
                         "Save to what filename? ";
                         name = $read();
                         If ($leng(name))
                             $spec(4, name);
                     }

                     VERB restore;
                     restore(ACTION) = Proc()
                     {
                         Var name;
                         "Restore from what filename? ";
                         name = $read();
                         If ($leng(name))
                             $spec(5, name);
                     }

                     VERB shell;
                     shell(ACTION) = Proc()
                     {
                         $spec(6, "/bin/sh");
                     }

                     VERB savewords;
                     savewords(ACTION) = Proc()
                     {
                         $spec(7, "unknown.txt");
                     }

                     VERB script;
                     script(ACTION) = Proc()
                     {
                         Var name;
                         "Script to what filename? ";
                         name = $read();
                         If ($leng(name))
                             $spec(8, name);
                         )
                     }

                     Status = Proc()
                     {
                         $spec(9, $name($loc($ME)), Score, $turns());
                     }

                     START = Proc() {$spec(10, 60);} // It makes the text prettier

Return to Contents

7.12. Miscellaneous Routines

These routines are placed here for lack of a better place to put them.

$say
$say( str1, str2, ... ) -> No return value. Prints the messages str1 str2 ... on the screen. Note that ADL automatically "word-wraps" strings so that they fit within the right margin as closely as possible. Therefore, it is not necessary for the ADL programmer to take great care in formatting the messages passed to $say. If the programmer desires that the current line be terminated, and output start on a new line, the character sequence "\n" should be embedded in the string. Note that each str may actually be an expression such as $name(foo) or $num(Score).

Note also that, as a syntactic shortcut due to the very large amount of output text in a typical text adventure, the programmer may start a statement with a string, and it is presumed to be a $say call. In this type of statement, the commas are ommitted between arguments. Additionally, in this type of statement, the first string must be a literal within "double quotes". Example:
                 $say("Hi!  My name is ", MyName, "! How are you today?\n");

            This is the same as (note the missing parentheses and commas):

                 "Hi!  My name is " MyName "! How are you today?\n";

            Note that MyName is assumed to contain a string ID in
            this example.
$arg
$arg( num ) -> Returns the numth argument of the current routine. The call $arg(0) returns the number of arguments passed to this invocation of the current routine. This function is most useful when writing functions which take variable numbers of arguments. Example:
                     /* Print all of the arguments to this routine */
                     i = 1;
                     While (i <= $arg(0)) {
                         "Arg ", $str(i), " = ", $arg(i), "\n";
                     }
$exit
$exit( code ) -> Doesn't return to the current routine. $exit terminates execution of the current phase. Control passes to an enclosing phase according to this table:
CodeNew control phase
0 Control passes to the next phase.
1 Control passes to the outermost loop.
2 Control passes to the top of the Dobj loop.
3 Control passes to the parser which attempts to complete a partial sentence.
See the diagram in Chapter 4 for a complete definition. Example:
                     take(PREACT) = Proc()
                     {
                         If ($loc(Dobj) != $loc($ME)) {
                             "You don't see that here!\n";
                             /* Skip the rest of the phases */
                             $exit(1);
                         }
                     }
                     safe(ACTION) = Proc()
                     {
                         If (Verb == take) THEN
                             "You can't budge the safe.\n";
                             /* Go on to the rest of the Dobjs */
                             $exit(2);
                         }
                     }
                     ball(ACTION) = Proc()
                     {
                         If (ball.BROKEN) {
                             /* Rely on the default verb ACTION */
                             $exit(0);
                         }
                         "The ball bounces nicely.\n";
                     }
                     NOVERB(PREACT) = Proc()
                     {
                         "What do you want me to do with the "
                                $name(Dobj) "?\n";
                         /* Re-parse the sentence */
                         $exit(3);
                     }
$return
$return( expr ) -> Doesn't return to the current routine. Evaluates expr and returns the result to the current routine's caller. Same as the Return statement. Note that in the absence of an explicit $return, the return value of a routine is the same as the value of the last statement executed. Example:
                     Increment = Proc(n) {$return(n + 1);{

                     "Increment( 3 ) = ", $str(Increment(3)), "\n";

                    would print:
                             Increment( 3 ) = 4
$phase
$phase() -> Returns the number of the phase currently executing. This number has values according to the following table:
PhaseDescription
0 During the START phase
1 During the Daemon phase
2 During the Actor ACTION
3 During the Verb PREACT
4 During the Iobj ACTION
5 During the Dobj ACTION
6 During the Verb ACTION
7 During the Room ACTION
Example:
                     If ($phase() == 2) THEN
                         "This is the Actor ACTION\n";
                     Else If ($phase() == 4) THEN
                         "This is the Iobj ACTION\n";
                     Else If ($phase() == 5) THEN
                         "This is the Dobj ACTION\n";

Return to Contents


8. ADL Program Structure

In the following extended BNF description of ADL program structure, terminal symbols are in BOLD UPPERCASE and non-terminals in lowercase. Items enclosed in quotes are literal terminals.

     adlprog    : // NULL
                | dstmt adlprog
                ;

     dstmt      : 'INCLUDE' STRING  ';'
                | 'MESSAGE' STRING  ';'
                | decl
                | assign
                ;

     decl       : 'VERB' ilist
                | 'ADJEC' ilist
                | 'ROUTINE' ilist
                | 'ARTICLE' ilist
                | 'PREP' ilist
                | 'VAR' vlist
                | 'NOUN' nlist
                ;

     assign     : ID  '='  value  ';'
                | nounp  '('  nprop  ')'  '='  value  ';'
                | VERB  '('  vprop  ')'  '='  proc ';'
                | '('  VAR  [ '+'  const ]  ')'  '='  value  ';'
                | PREP  nounp  PREP  '='  PREP  ';'
                | VERB  PREP  '='  VERB  ';'
                ;

     ilist      : ID  ( ','  ID ) *  ';'
                ;

     vlist      : vdec  ( ','  vdec ) *  ';'
                ;

     vdec       : ID  [ '['  const  ']' ]
                ;

     nlist      : nloc  ( ','  nloc  ) *  ';'
                ;

     nloc       : nounp  [ '('  nounp  ')' ]
                ;

     nounp      : [ modif ]  NOUN
                | OBJECT
                ;

     modif      : VERB
                | ADJEC
                ;

     vprop      : 'PREACT'
                | 'ACTION'
                ;

     nprop      : const
                | 'LDESC'
                | 'SDESC'
                | 'ACTION'
                ;

     const      : NUMBER
                | CONST_ID
                ;

     value      : const
                | STRING
                | nounp
                | proc
                | modif
                | ROUTINE
                | PREP
                | ARTICLE
                | VAR
                ;

   proc         : 'Proc' '(' optnames ')' outerblock
                ;

   optnames     : // NULL
                | names
                ;

   names        : IDENT
                | IDENT ',' names
                ;

   outerblock   : '{' locals stmts '}'
                ;

   block        : '{' stmts '}'
                ;

   locals       : // NULL
                | 'Var' vars ';' locals
                ;

   vars         : var
                | var ',' vars
                ;

   var          : IDENT
                | IDENT '[' NUMBER ']'
                ;

   stmts        : // NULL
                | stmt stmts
                ;

   stmt         : callassgn ';'
                | return ';'
                | 'Break' ';'
                | ifstmt
                | whilestmt
                | block
                ;

   callassgn    : expr '=' expr
                | expr
                | STRING // Implicit $say
                | STRING ',' exprlist // Implicit $say
                ;

   exprs        : // NULL
                | expr exprs
                ;

   return       : 'Return' expr
                | 'Return'
                ;

   ifstmt       : 'If' '(' expr ')' stmt
                | 'If' '(' expr ')' stmt 'Else' stmt
                ;

   whilestmt    : 'While' '(' expr ')' stmt
                ;

   expr         : expr '||' logandexp
                | logandexp
                ;

   logandexp    : logandexp '&&' orexp
                | orexp
                ;

   orexp        : orexp '|' xorexp
                | xorexp
                ;

   xorexp       : xorexp '^' andexp
                | andexp
                ;

   andexp       : andexp '&' eqexp
                | eqexp
                ;

   eqexp        : eqexp '==' cmpexp
                | eqexp '!=' cmpexp
                | eqexp '?=' cmpexp
                | cmpexp
                ;

   cmpexp       : cmpexp '<' addexp
                | cmpexp '<=' addexp
                | cmpexp '>=' addexp
                | cmpexp '>' addexp
                | addexp
                ;

   addexp       : addexp '+' mulexp
                | addexp '-' mulexp
                | mulexp
                ;

   mulexp       : mulexp '*' unary
                | mulexp '/' unary
                | mulexp '%' unary
                | unary
                ;

   unary        : '-' dotexp
                | '~' dotexp
                | '!' dotexp
                | '*' dotexp
                | '&' dotexp
                | dotexp
                ;

   dotexp       : dotexp '.' term
                | dotexp '[' expr ']'
                | dotexp '(' funargs ')'
                | term
                ;

   funargs      : // NULL
                | exprlist
                ;

   exprlist     : expr
                | exprlist ',' expr
                ;


   term         : NUMBER
                | STRING
                | IDENT
                | '<' IDENT IDENT '>'
                | '(' expr ')'
                ;

Return to Contents


9. ADL Sentence Structure

In the following extended BNF description of ADL sentences, terminal symbols are in BOLD UPPERCASE and nonterminals in lowercase. A CONJ is one of the word "and", a comma (","), or the word "but"; a SEP is one of a period ("."), the word "then", or a newline. Comment statements start with "--" and continue to the end of the line.

     input-line      =  ( sentence  SEP ) *

     sentence        =  simple-sent  // Verb, Iobj, and Dobj are
                                     // as you would expect
                     =  noverb-sent  // Verb = NOVERB;  Iobj and Dobj
                                     // are as you would expect
                     =  teller-sent  // Verb = TELLER;  Iobj = object;
                                     // Dobj = STRING

     simple-sent     =  verb-phrase  [ dobj-list ]  [ prep  object ]  [ prep ]
                     =  verb-phrase  object  dobj-list  [ prep ]

     noverb-sent     =  [ dobj-list ]  [ prep  object ]  [ prep ]
                     =  object  dobj-list  [ prep ]

     teller-sent     =  object  ","  STRING
                     =  object  ","  VERB  REST-OF-STRING

     verb-phrase     =  VERB  PREP *

     dobj-list       =  object  ( CONJ  object ) *

     object          =  [ ARTICLE ]  modif  NOUN
                     =  [ ARTICLE ]  modif
                     =  [ ARTICLE ]  NOUN
                     =  [ ARTICLE ]  OBJECT
                     =  STRING

     modif           =  VERB
                     =  ADJEC

     prep            =  PREP
                     =  PREP  PREP
                     =  PREP  object  PREP

This picture shows a non-deterministic finite-state machine which implements that grammar:

Finite-state machine

Return to Contents


10. stdproc.adl

Stdproc.adl is a file that contains many useful default definitions and routines. To use stdproc.adl, simply put 'INCLUDE "stdproc.adl"' before the rest of your program. Stdproc.adl defines six things: object properties, constants, global variables, useful words, some normal verbs and their actions, and some utility routines.

Return to Contents

10.1. Object properties

The following object properties are defined in stdproc.adl. The ADL programmer using stdproc.adl is advised not to re-use these properties with different meanings, as strange and unusual things will happen.

            BITPROP
                SEEN,           // I've been here / seen this
                OPENS,          // This can be opened
                LOCKS,          // This can be locked
                OPENED,         // This is opened
                LOCKED,         // This is locked
                TRANS,          // This is transparent
                LIGHT,          // This gives off light
                FLAME,          // This is on fire
                NOTAKE;         // Ignore this object for "take"
            PROPERTY
                AllLink,        // Link for objects used with "take" and "drop"
                SAVESENT;       // First VAR in a sentence save area

This leaves 23 boolean properties and 14 integer properties free for the programmer's definition and use. The above properties are used as follows:

SEEN The standard looking daemon sets this property of a room to TRUE whenever the player visits the room.
OPENS This property should be set to TRUE if it is possible to open or close the object (a treasure chest would be an example of this).
LOCKS This property should be set to TRUE if it is possible to lock or unlock the object (a door might be a good example of this).
OPENED This property is set to TRUE if the object is already opened and FALSE if the object is closed. This is meaningful only if OPENS is TRUE.
LOCKED This property is set to TRUE if the object is locked and FALSE if the object is unlocked. This is meaningful only if LOCKS is TRUE.
TRANS This property should be set to TRUE if the object is transparent (a glass box or a bottle would be a good example of this).
LIGHT This property should be set to TRUE if the object gives off light (in the case of a transportable object like a flashlight) or if the object is intrinsically lit (like an outdoor location).
FLAME This property should be set to TRUE if the object is on fire.
NOTAKE This property should be set to TRUE if it is desired that "take" and "drop" ignore the object when "take all" or "drop all" are requested.
AllLink This property is used by the PREACT and ACTION routines of the verbs "take" and "drop" and should not be used by anything else.
SAVESENT This property is used to hold the starting number of a block of six global variables in which to store a sentence for use with ActAction, below.

Return to Contents

10.2. Constants

For convenience and readability, stdproc.adl defines the following constants:

                  TRUE  = 1;
                  FALSE = 0;
                  NULL  = 0;

In addition, the following constants are defined for use as arguments to the $spec routine:

                  DEBUG = 1;
                  RESTART = 2;
                  QUIT = 3;
                  SAVE = 4;
                  RESTORE = 5;
                  EXEC = 6;
                  PRESERVE = 7;
                  SCRIPT = 8;
                  HEADER = 9;
                  MARGIN = 10;

The following constants are defined for use as arguments to the Expect routine (described in section 10.6):

                  NO_OBJ = 1;
                  ONE_OBJ = 2;
                  MULT_OBJ = 4;
                  PLAIN_OBJ = 8;
                  STR_OBJ = 16;

The following global variables are declared by stdproc.adl for use by the ADL programmer:

            VAR
                  Skip,
                  Indent,
                  Dark,
                  MyLoc,
                  Verbose,
                  Scripting,
                  LastVerb,
                  LastNumd,
                  LastDobj,
                  LastPrep,
                  LastIobj;

The above globals are used as follows:

Skip Skip is used in preference to $exit(1) or $exit(2) inside Object ACTIONs if it is desired that the rest of the Object list be processed by the Verb ACTION of "take" or "drop" (see the discussion on TakeAct and DropAct below).
Indent Indent should be set to TRUE if object descriptions are to be indented by two spaces before being printed.
Dark Dark is TRUE if it is currently dark. This variable is set by the Looker routine if there is no light in the current location of $ME, and may also be set as the result of some other action.
MyLoc MyLoc is the location of the player at the outset of the previous turn. The routine Looker checks to see whether MyLoc is the same as the location of the player. If so, the room description is printed. If not, no action is performed by Looker. MyLoc is initialized to -1 to force the printing of a room description at the beginning of the game.
Verbose Verbose should be set to TRUE if the player wishes that all room descriptions be verbose ones (i.e. long descriptions of the room and its contents). If Verbose is false and the room has been visited previously, a short description will be printed.
Scripting Scripting is set to TRUE by the ACTION of the Verb "script" when output is being scripted to a file. It is FALSE otherwise.
LastVerb LastVerb, LastNumd, LastDobj, LastPrep, and LastIobj contain the values present in the sentence prior to the current sentence. These values are set in the standard looking daemon. The routine SaveSentence is provided for this purpose.

Return to Contents

10.3. Words

The following words are defined to be a standard part of the ADL vocabulary:

     PREP          with, to, into, at, under, from, off, on;

     in = into;

     ARTICLE       the, a, an;

     NOUN          all, it;

Return to Contents

10.4. Verbs and their actions

Standard.adl declares the following verbs, and initializes their PREACT and ACTION routines to (usually) fairly simply-minded defaults.

             VERB
                  n,  s,  e,  w,
                  ne, se, nw, sw,
                  up, down,
                  enter, exit,
                  get, put, take, drop,
                  wear, remove,
                  verbose, terse,
                  open, close,
                  lock, unlock,
                  move, break, rub, touch,
                  throw, read, burn,
                  examine, look, inventory,
                  quit, restart,
                  save, restore, script,
                  turn, douse, light,
                  wait, again, go;

The following verbs have special semantics and redefinition of their PREACT or ACTION routines should be avoided:

NOVERB NOVERB (which is predeclared by ADL) is the verb returned by the parser if the player's sentence contained no verb. Standard.adl initializes the PREACT of NOVERB so that appropriate requests for more information are generated.
put "Put" transforms itself into "drop" then calls the PREACT of "drop".
get "Get" transforms itself into "take" then calls the PREACT of "take".
take "Take" determines whether the sentence is one like "Take all but the sword and the shield". If it is then a list of objects is built up which are then taken. If not, the normal semantics apply. If the programmer wants an action to be performed by the "take" ACTION, the routine TakeAct should be defined.
drop "drop" may be used in sentences like "Drop all but the book." If it is so used, a list of objects is created which are then dropped. If the programmer wants an action to be performed by the "drop" ACTION, the routine DropAct should be defined.
go If "go" is used in a sentence like "Go north", the Verb is changed to "north" and the Dobj and Iobj are set to NULL. This only applies to the direction verbs "north", "south", "east", "west", "northeast", "southeast", "northwest", "southwest", "up", and "down".
again If the standard actor action is in effect, the Verb "again" will never be called or seen by Objects since it is replaced by the previous sentence.

In addition to declaring the preceding verbs, stdproc.adl declares the following equivalences:

                  g               = again;
                  z               = wait;
                  l               = look;
                  u               = up;
                  d               = down;
                  north           = n;
                  south           = s;
                  east            = e;
                  west            = w;
                  northeast       = ne;
                  northwest       = nw;
                  southeast       = se;
                  southwest       = sw;

                  put on          = wear;
                  take off        = remove;
                  turn on         = light;
                  turn off        = douse;

Return to Contents

10.5. Routines

Standard.adl declares and defines the following Routines for use by the ADL programmer:

            ROUTINE
                  StdInit,
                  Reach,
                  See,
                  Lit,
                  Avail,
                  CheckAvail,
                  Expect,
                  Preact,
                  Looker,
                  Prompter,
                  TakeAct,
                  DropAct,
                  ActAction,
                  SaveSentence,
                  Dwimmer;

Their use is defined as follows:

StdInit StdInit(actor) should be executed in START if the programmer desires that ALL of the default routines be used. Actor should be the name of the primary interactive Actor in the scenario.
Reach Reach(object, container) is TRUE if object is contained in container and if the player can reach the object. It is FALSE otherwise. Note that this also checks whether object is contained in something which is contained in container and so on.
See See(object, container) is TRUE if object is contained in container and the player can see the object. It is FALSE otherwise. This also checks containers inside containers.
Lit Lit() is TRUE if something is lighting the player's location and FALSE otherwise.
Avail Avail(object) is TRUE if the player can see object (either in the room or in the player's inventory) and can reach the object. It is FALSE otherwise.
CheckAvail CheckAvail() checks to see whether the Dobj and Iobj typed by the player are available. If not, an appropriate message is printed and $exit(1) is performed.
Expect Expect is typically called by the PREACT of a Verb. It looks at the current sentence to see whether it is of acceptable form. The two parameters to Expect define criteria for acceptability. The first parameter indicates what types of direct objects are acceptable and the second indicates what types of indirect objects are acceptable. Each parameter consists of one or more of the Expect flags $or'd together. The flag NO_OBJ indicates that it is acceptable that no object be present; ONE_OBJ indicates that it is acceptable that one object be present; MULT_OBJ indicates that it is acceptable that multiple objects be present; STR_OBJ indicates that it's OK for the object(s) to be strings; and PLAIN_OBJ indicates that it's OK for the object(s) to be normal ADL objects. Example:
                        /* "take" needs 1 to N Dobjs and 0 or 1 Iobjs */
                        take(PREACT) = Proc()
                        {
                            Expect(MULT_OBJ|PLAIN_OBJ,
                                   NO_OBJ|ONE_OBJ|PLAIN_OBJ);
                        }
                        /* "quit" can accept no objects */
                        quit(PREACT) = Proc()
                        {
                            Expect(NO_OBJ, NO_OBJ);
                        }
                        /* "unlock" needs exactly one Dobj and Iobj */
                        unlock(PREACT) = Proc()
                        {
                            Expect(ONE_OBJ|PLAIN_OBJ,
                                   ONE_OBJ|PLAIN_OBJ);
                        }
                        /* "say" needs a string to say and possibly
                          someone to whom to say it */
                        say(PREACT) = Proc()
                        {
                            Expect( ONE_OBJ|STR_OBJ,
                                    NO_OBJ|ONE_OBJ|PLAIN_OBJ);
                        }
Preact Preact is the standard PREACT for Verbs. It checks to make sure that exactly one plain Direct Object was typed and that the Indirect Object is not a string. It also checks to see whether all of the named objects are available.
Looker Looker is the standard looking daemon. It is intended to be executed every turn. To enable this, either of the statements $sdem(Looker) or StdInit(actor) must be executed (where actor is the primary actor).
Prompter Prompter is the standard prompting routine. To use it, either of the statements $prompt(Prompter) or StdInit(actor) must be executed.
ActAction ActAction is the standard Actor action. It checks to see whether the Verb "again" or the Object "it" was used and modifies the sentences appropriately. To use it, either of the statements $ME.ACTION=ActAction or StdInit(actor) must be executed.
TakeAct TakeAct is called by the default action routine of the Verb "take" after the ACTION routines of all of the Direct Objects have been executed.
DropAct DropAct is similar to TakeAct, except that it is called by the ACTION routine of "drop".
SaveSentence SaveSentence should be called by the ADL programmer if it is desired that the Verb "again" and the Object "it" work as in ActAction above. Looker calls SaveSentence every turn.
Dwimmer Dwimmer is the standard DWIMming routine. It checks to see whether an ambiguous object could possibly be the one the player meant. To use Dwimmer, include the statement "If(Dwimmer($arg(1)) Return 1;" in DWIMI and/or DWIMD.

Return to Contents


Appendix 1 - A Tiny Dungeon

The following dungeon is a tiny but complete scenario. It demonstrates the use of $hit and $miss, as well as the use of some of the features of stdproc.adl.

INCLUDE "stdproc.adl";

NOUN startrm, brightroom;		/* Locations in the dungeon */
startrm(LIGHT) = TRUE;		brightroom(LIGHT) = TRUE;

cg = Proc() {"You can't go that way.\n";}

startrm(LDESC) = Proc()
{
    "You are in a small but comfortable room.  You hardly want ";
    "to leave, but there is a door leading east, if you insist.\n";
}
startrm (SDESC) = Proc() {"Comfortable room.\n";}
startrm(ACTION) = Proc()
{
    $miss(    cg, cg, 0,          cg, 0, 0, 0, 0, 0, 0);
    $hit($ME, 0,  0,  brightroom, 0,  0, 0, 0, 0, 0, 0);
}

brightroom(LDESC) = Proc()
{
    "You are in a brightly lit room.  The walls sparkle with ";
    "scintillating lights.  There is a darker room to the west.\n";
}
brightroom(SDESC) = Proc() {"Bright room.\n";}
brightroom(ACTION) = Proc()
{
    $miss(    cg, cg, cg, 0,       0, 0, 0, 0, 0, 0);
    $hit($ME, 0,  0,  0,  startrm, 0, 0, 0, 0, 0, 0);
}

ADJEC red, blue;

NOUN red pillow(startrm), blue pillow(startrm);

red pillow(LDESC) = Proc() {"There is a red pillow here.\n";}
red pillow(SDESC) = Proc() {"A red pillow";}

blue pillow(LDESC) = Proc() {"There is a blue pillow here.\n";}
blue pillow(SDESC) = Proc() {"A blue pillow";}

NOUN platinum(brightroom);		bar = platinum;
platinum(LDESC) = Proc() {"There is a bar of platinum here!\n";}
platinum(SDESC) = Proc() {"A platinum bar";}
platinum(ACTION) =  Proc()
{
    If (($verb() == drop) & ($loc($ME) == $loc(<red pillow>))) {
	"The bar falls onto the red pillow, breaking it!  The symbolism ";
	"impresses itself upon you, and you go back to work instead of ";
	"playing these silly games!\n";
	$spec(QUIT);
    }
}

NOUN SELF(startrm);		SELF(NOTAKE) = TRUE;

START = Proc ()
{
    StdInit(SELF);
}

DWIMD = Proc() {Return Dwimmer($arg(1));}
DWIMI = Proc() {Return Dwimmer($arg(1));}

Return to Contents


Appendix 2 - A scenario with multiple Actors

The following ADL program demonstrates both the use of the standard package and the use of multiple actors. This is the scenario which generated the script at the beginning of this document.

INCLUDE "stdproc.adl"; /* Include the standard package */


/* The following are Object properties */

BITPROP
    BROKEN,     /* Is the robot damaged? */
    TOLD;       /* Have I told the robot something? */
PROPERTY
    BSTATE;     /* State of the button */

B_OFF   =  0;   /* Button is off */
B_FLASH =  1;   /* Button is flashing */
B_LIT   =  2;   /* Button is lit */


/* Global variables */

VAR
    RobSave[ 6 ],       /* Saved sentence for the robot */
    Score;              /* Current score */


/* Utility routines */

ROUTINE
    NoGo,       Sayer,  Myself, Lifter,
    DoorCk,     TrapCk, RobMov, BlueCk,
    Header,     MyDie,  Skore,  RobEntr,
    HatchSD;


/* Locations in the dungeon */

NOUN
    Redrm,          Bluerm,
    Greenrm,        Cellar,
    Endrm;


/* Immovable objects */

NOUN
    button( Bluerm ),
    door( Cellar ),
    hatch( Bluerm );


/* Objects which may become actors */

NOUN
    me( Redrm ),
    robot( Greenrm );

me(NOTAKE) = TRUE;


/* Room descriptions */

Redrm( LDESC ) = Proc()
{
    "You are in a large room which is illuminated by a bright ",
    "red glow.  Exits lie to the east and south.\n";
}
Redrm( SDESC ) = Proc() {Return Header("Red room", $arg(0));}
Redrm( LIGHT ) = TRUE;


Greenrm( LDESC ) = Proc()
{
    "You are in a smallish room which is illuminated by a pleasant ",
    "green glow.  The only exit is to the west.\n";
}
Greenrm( SDESC ) = Proc() {Return Header("Green room", $arg(0));}
Greenrm( LIGHT ) = TRUE;


Bluerm( LDESC ) = Proc()
{
    "You are in a tiny room which is barely illuminated by a ";
    "dim blue glow.  There is an exit to the north,";

    If (button.BSTATE == B_LIT) {
        " and most of the floor has tilted up to reveal a hatch leading ";
        "down into blackness.  A button on the wall is glowing brightly.";
    }
    Else {
        " and you seem to make out something on the floor.";
        If (button.BSTATE)
            "  A button on the wall is flashing urgently.";
        Else
            "  There is a button on the wall.";
    }

    "  Above the button is a sign that reads:\n\n",
    "		DANGER!\n\n",
    "	     HIGH VOLTAGE!\n\n";
}
Bluerm( SDESC ) = Proc()
{
    If ($arg(0)) Return "Blue room";
    "Blue room.\n";
}
Bluerm( LIGHT ) = TRUE;

Cellar( LDESC ) = Proc()
{
    "You are in the cellar.  Far above you can be seen a dim blue light.";
    If (door.OPENED) 
        "  An open door leads to the north.\n";
    Else
        "  You can barely see the outline of a door to the north.\n";
}
Cellar( SDESC ) = Proc() { Return Header("Cellar", $arg(0)); }
Cellar( LIGHT ) = TRUE;


Endrm( LDESC ) = Proc()
{
    "You exit from the dark cellar into a land filled with singing birds, ";
    "blooming flowers, flowing streams, and bright blue skies.  In other ";
    "words, you have finished this game!\n";

    Score = Score + 25;
    Skore();
    $spec(QUIT);
}
Endrm( LIGHT ) = TRUE;


/* Verbs */
VERB
    score,
    push,
    shout;

tell = TELLER;
say = tell;
press = push;
feel = touch;
yell = shout;


/* Verb routines */

tell( PREACT ) = Proc()
{
    If (Iobj != robot) {
        /* The only logical thing to talk to is the robot */
        Sayer
            ("Talking to yourself is said to be a sign of impending insanity");
    }
    Else If (Dobj >= 0) {
        /* You must say strings */
        Sayer("You must put what you want to say in quotes");
    }
    Else If ($loc(robot) != $loc(me)) {
        /* The robot must be in the same place as the player */
        If (Myself()) "You don't see the robot here.\n";
    }
    Else {
        /* Everything is OK.  Add 25 points to the score */
        If (!robot.TOLD) {
            Score = Score + 25;
            robot.TOLD = TRUE;
        }
        $exit(0);
    }
    $exit(1);
}
tell( ACTION ) = Proc()
{
    /* Tell the player that we heard him */
    "\"Sure thing, Boss.\"\n";

    /* Delete the old action */
    $delact(robot);

    /* Add the new action - a non-interactive actor */
    $actor(robot, Dobj, FALSE);
}


shout( PREACT ) = Proc()
{
    If (Iobj & (Iobj != robot))  {
        /* Shouting at things other than the robot */
        "AAARRRGGGHHH!\n";
    }
    Else If (Dobj >= 0) {
        /* Shouting things other than strings */
        "EEEYYYAAAHHH!\n";
    }
    Else If (robot.BROKEN) {
        "There is no response.\n";
    }
    Else {
        /* Shouting at the robot - same as telling the robot */
        If (!robot.TOLD) {
            Score = Score + 25;
            robot.TOLD = TRUE;
        }
        $exit(0);
    }
    $exit(1);
}
shout( ACTION ) = Proc()
{
    /* Tell the player we heard them */
    If ($loc(robot) != $loc(me)) "In the distance you hear the words, ";
    "\"Sure thing, Boss\"\n";

    /* Delete the old robot action */
    $delact(robot);

    /* Add the new robot action */
    $actor(robot, Dobj, FALSE);
}


push( PREACT ) = Proc()
{
    /* Expect a plain direct object */
    Expect(ONE_OBJ|PLAIN_OBJ, NO_OBJ);
    CheckAvail();
}
push( ACTION ) = Proc()
{
    Sayer("That doesn't seem to do anything");
    $exit(1);
}


score(PREACT) = Proc()
{
    /* Score can accept no objects */
    Expect(NO_OBJ, NO_OBJ);
    Skore();
    $exit(1);
}


/* Object properties */

button( SDESC ) = Proc()
{
    IF (button.BSTATE == B_OFF)
        "a button";
    Else If (button.BSTATE == B_FLASH)
        "an urgently flashing button";
    Else
        "a brightly lit button";
}
button( ACTION ) = Proc()
{
    If (Myself() & ((Verb == push)|(Verb == take)|(Verb == touch))) {
        /* The player tried to do something with the button */
        "As you reach for the button, a 10,000,000 volt bolt of lightning ";
        "arcs toward your finger, disintegrating you upon impact.\n";
        MyDie();
    }
    Else If ((Verb == push) & (button.BSTATE == B_OFF)) {
        /* The robot pushed the button */
        button.BSTATE = B_FLASH;
        Score = Score + 50;
        $sfus(me, Lifter, 4);
        $exit(1);
    }
    Else If (Verb == take) {
        /* Can't take the button */
        Skip = TRUE;
    }
}

SimpleRobot = "I am just a simple robot";
robot( LDESC ) = Proc() {"There is a robot here.\n";}
robot( SDESC ) = Proc() {"a robot";}
robot( ACTION ) = Proc()
{
    If (Myself()) {
        /* I'm doing something with the robot */
        If (Verb == tell) {
            If (robot.BROKEN) {
                "There is no response.\n";
                $exit(1);
            }
        }
        Else If (Verb == take) {
            "The robot weighs at least 500 pounds!\n";
            $exit(1);
        }
    }
    Else If ($phase() == 2) {
        /* This is being called as the Actor ACTION */
        ActAction();
        If (    (Verb != push) & (Verb != go) &
                (Verb != wait) & (Verb != take) &
                ((Verb < north) | (Verb > down)))
        {
            /* The robot has a VERY simple vocabulary */
            Sayer(SimpleRobot);
            $delact(robot);
            $exit(1);
        }
    }
    Else If (Verb == take) {
        /* The robot is trying to take itself */
        Sayer("Mmmph!  Akkk!!  GGGGRR!!  No can do.  Sorry");
        Skip = TRUE;
    }
    Else {
        /* The robot is doing something to itself */
        Sayer(SimpleRobot);
        $delact(robot);
        $exit(1);
    }
}
robot( SAVESENT ) = RobSave;



/*      We break me( ACTION ) out into a named routine because
        StdInit overwrites that property and we need to restore it      */

MeAct = Proc()
{
    If ($phase() == 2) {
        /* This is the Actor ACTION - call standard's actor action */
        ActAction();
    }
    Else If (Verb == take) {
        Sayer("I thought you would never ask");
        Skip = TRUE;
    }
}


/*      We break hatch( SDESC ) out into a named routine because
        the hatch isn't visible until after Lifter has executed         */

HatchSD = Proc() {"an open hatch";}
HatchMSG = "The hatch doesn't budge";
hatch( ACTION ) = Proc()
{
    If (Verb == take) {
        /* Can't take the hatch */
        Sayer(HatchMSG);
        Skip = TRUE;
    }
    Else If ((Verb == open) | (Verb == push)) {
        /* Can't open or push it, either */
        Sayer(HatchMSG);
        $exit(1);
    }
}
hatch( OPENS ) = TRUE;
hatch( NOTAKE ) = TRUE;


door( SDESC ) = Proc() {"a door";}
door( ACTION ) = Proc()
{
    If (Verb == take) {
        "You can't take a door!\n";
        Skip = TRUE;
    }
}
door( OPENS ) = TRUE;


/*      Transition routines.  Note that RobMov is used in $miss.
        This produces the 'The robot exits to the <direction>
        messages.  The calls to RobEntr produce the messages like
        'The robot enters from the <direction>.         */

Bluerm( ACTION ) = Proc()
{
    $miss(RobMov, NoGo, NoGo, NoGo, NoGo, TrapCk, 0, 0, 0, 0);
    $hit($ME, Redrm, 0, 0, 0, 0, Cellar, 0, 0, 0, 0);
    RobEntr();
}


Redrm( ACTION ) = Proc()
{
    $miss(NoGo, BlueCk, RobMov, NoGo, NoGo, NoGo, 0, 0, 0, 0);
    $hit($ME, 0, Bluerm, Greenrm, 0, 0, 0, 0, 0, 0, 0);
    RobEntr();
}


Greenrm( ACTION ) = Proc()
{
    $miss(NoGo, NoGo, NoGo, RobMov, NoGo, NoGo, 0, 0, 0, 0);
    $hit($ME, 0, 0, 0, Redrm, 0, 0, 0, 0, 0, 0);
    RobEntr();
}


Cellar( ACTION ) = Proc()
{
    $miss(DoorCk, NoGo, NoGo, NoGo, BlueCk, NoGo, 0, 0, 0, 0);
    $hit($ME, Endrm, 0, 0, 0, Bluerm, 0, 0, 0, 0, 0);
    RobEntr();
}


/* Routines */

/* Myself() - returns 1 if "me" is the current actor; 0 otherwise */
Myself = Proc()
{
    Return ($ME == me);
}


/*      Sayer(str) - Says a string with appropriate quoting, depending
        on whether the robot or the player is doing the saying.         */
Sayer = Proc(str)
{
    If (Myself()) {
        "", str, ".\n";
    }
    Else If ($loc(robot) == $loc(me)) {
        "\"", str, ", Boss.\"\n";
    }
    Else {
        "You hear a muffled voice in the distance.\n";
    }
}


/*      NoGo() - "You can't go that way"        */
NoGo = Proc()
{
    Sayer("You can't go that way");
    $exit(1);
}


/*      Header(str, arg0) - To accomplish the printing of header lines,
        each location SDESC need to return a string if a parameter is
        passed to it.  By doing Return Header(<sdesc> ,$arg(0)), we can
        centralize the saying/returning decision.       */
Header = Proc(str, arg0)
{
    If (!arg0) {
        $say(str, ".\n");
    }
    Return str;
}


RobMov = Proc()
{
    If (!Myself() & ($loc(robot) == $loc(me))) {
        "The robot exits to the ";
        If (Verb == e)
            "east";
        Else If (Verb == w)
            "west";
        Else If (Verb == s)
            "south";
        /* The robot can't be seen leaving to the north */
        ".\n";
    }
}


RobEntr = Proc()
{
    If (!Myself() & ($loc(robot) == $loc(me))) {
        If (Verb == north)
            "The robot enters from the south.\n";
        Else If (Verb == east)
            "The robot enters from the west.\n";
        Else If (Verb == west)
            "The robot enters from the east.\n";
         /* The robot can't enter from the north in this scenario */
    }
}


DoorCk = Proc()
{
    If (!door.OPENED) {
        "The door seems to be closed.\n";
        $exit(1);
    }
}


TrapCk = Proc() { If (button.BSTATE != B_LIT) NoGo(); }

/*      BlueCk() - make sure that only one actor is in the blue room
        at one time.    */
BlueCk = Proc()
{
    If (($loc(me) == Bluerm) | ($loc(robot) == Bluerm)) {
        If (Myself())
            "The room is too small for both you and the robot to fit.\n"
        $exit(1);
    }
    Else If (!Myself() & (button.BSTATE == B_LIT)) {
        RobMov();
        "You hear a loud CRASH! in the distance.\n";
        Score = Score - 10;
        robot.BROKEN = TRUE;
        $move(robot, Bluerm);
        $delact(robot);
        $exit(1);
    }
    RobMov();
}


/*      MyDie() - kill off the player   */
MyDie = Proc()
{
    Score = Score - 50;
    Skore();
    Die();
}


/*      Lifter() - Lift the hatch, possibly killing the robot or
        the player      */
Lifter = Proc()
{
    IF ($loc(me) == Bluerm) {
        "All of a sudden, the floor lifts up, and you are crushed between it ",
        "and the wall!  ";
        MyDie();
    }
    Else {
        "In the distance, you hear a loud CRASH!\n";
        If ($loc(robot) == Bluerm) {
            Score = Score - 10;
            robot.BROKEN = TRUE;
            $delact(robot);
        }
    }
    hatch.SDESC = HatchSD;
    button.BSTATE = B_LIT;
    Bluerm.SEEN = FALSE;
}


/*      Prompt - print the status line and a prompt     */
PROMPT = Proc()
{
    $spec(HEADER, $sdesc($loc($ME))(1), Score, $turns());
    "> ";
}


/*      Increment - increment the turn counter  */
INCREMENT = Proc()
{
    If (Myself()) {
        /* We only want to increment once per turn */
        $incturn();
    }
    Else {
        /* We don't want Looker executing for the robot */
        $exit(0);
    }
}


/*      Skore() - print out the current score.  */
Skore = Proc()
{
    "You have scored " $str(Score)
        " out of a possible 100 in " $str($turns()) " moves.\n";
}


/*      Dwimming routines       */
DWIMI = Proc() {Dwimmer($arg(1));}
DWIMD = Proc() {Dwimmer($arg(1));}

START = Proc()
{
    $spec(MARGIN, 69);  /* Set the screen to 69 wide */
    $sdem(INCREMENT);   /* Turn counter increment */
    StdInit(me);        /* Initialize standard */
    $setp(me, ACTION, MeAct);    /* Restore me( ACTION ) */
    $setv(n, s, e, w, u, d, 0, 0, 0, 0); /* Use our own transition vector */
    $prompt(PROMPT);    /* and our own prompter */
    $setg(Indent, TRUE); /* Indent the object descriptions */
}

/**** EOF actdemo.adl ****/

Return to Contents


Appendix 3 - Glossary

Actor An Actor in ADL is similar to an Actor in a play, in that the Actor has a script to follow (the lines typed by the player), and there may be more than one Actor acting at a time.
Adjective An adjective is a part of speech which describes a noun. "Red", "green", "big", and "rusty" are all adjectives.
Argument An argument to an ADL routine is one of the list of "things" which the routine was told to operate on. For example, in the routine call $plus(20, 30, 40) the first argument is 20, the second argument is 30, and the third argument is 40.
Article An article is a part of speech which often conveys some sense of "definiteness". "The" is an article, as are "a" and "an". ADL ignores articles in player sentences, so their proper use is of little importance.
ASCII ASCII (which stands for American Standard Code for Information Interchange, as if you really wanted to know) is a method of representing characters (such as "a", "b", "9", etc.) as numbers for the purpose of computer manipulation. Thus, the ASCII representation of the letter "A" is 65. The expression "the ASCII representation of the number 45308" is often heard. This means that the number 45308 is represented as the ASCII string "45308". This is slightly different than the ASCII code of a character.
BNF BNF is a method of representing the syntax of a language in a concise way. In English, one may say that "A list is a sequence of things." In BNF, one may say that "list = thing *" which means that a list consists of zero or more things. (This is actually an extended form of BNF which is more concise than the original). Other things one may say include "foo = bar +" which means that foo consists of one or more bars; "bletch = [ ack ] gag" which means that a bletch is an optional ack followed by a gag. Parentheses may be used for grouping; for example "abcbc = a ( b c ) *" means that an abcbc is an "a" followed by zero or more occurrences of the two-element list "b c".
Buffer See Line Buffer.
Conjunction A conjunction is a part of speech which is used to join two parts of a sentence together. Conjunctions include the word "and", the word "but", and the comma ",".
Container A container is an object which contains another object, just as in real life.
Daemon A daemon is a routine which is executed periodically. For example, in real life Joe Blow goes on a coffee break every 15 minutes. A coffee break could then be considered a daemon which executes every 15 minutes (and Joe Blow could be considered lazy). ADL daemons execute once every turn.
Direct Object A direct object is a part of speech on which the verb is "acting" directly. For example, in the sentence "Take the food" the word "food" is the direct object. Direct objects may consist of more than one word.
Fuse A fuse is similar to a daemon except that instead of being executed periodically, it waits a for some time to pass then executes exactly once. For example, in real life setting your alarm to go off at six o'clock in the morning could be considered activating a fuse.
Global See Variable.
Global Variable See Variable.
Implementor The implementor is the person who wrote the ADL compiler and ADL interpreter which run on your computer. Send the implementor lots of praise and/or money.
Indirect Object An indirect object is a part of speech which is indirectly acted upon by the verb. For example, in the sentence "Take the rock from the stream", "stream" is the indirect object as it is not directly affected by the verb "take". Usually an indirect object is preceded by a preposition. There is one case where it is not. For example, in the sentence "Give the frog the bait" it is the bait which is being given. This may seem confusing but if you rewrite the sentence as "Give the bait to the frog" it makes more sense.
Line Buffer A line buffer is an area in the memory of the computer where the last line which was typed by a player is stored. Words which are read by the Parser are read from this buffer, not directly from the keyboard.
Local Variable See Variable.
Location The location of some specified object is the object which contains the specified object.
Modifier A modifier is a part of speech which is essentially the same as an adjective in function. ADL allows some verbs to act as modifiers in order to better mimic the English language.
Noun A noun is a person, place, or thing. A desk is a noun. America is a noun. Fred Rogers is a noun. "Noun" and "object" are normally interchangeable terms. Usually however, when a reference is made to something being a "noun" it implies that something is just one word (as in "desk"), and not two words (as in "blue streak").
Object See Noun.
Parse Parsing is the process of breaking down an input string into structured data. For example, parsing the string "Take the green brick and the nail from the wall" would parse into the verb "Take", the direct objects "green brick" and "nail", the preposition "from", and the indirect object "wall".
Player A player is a person who plays a game. Generally, a player is associated with an Actor in an ADL scenario.
Preposition A preposition is a part of speech which often specifies some location (like "under" or "beside") or some destination (like "in" or "on"). Prepositions are generally found before Indirect Objects in sentences, but occasionally modify Verbs.
Prompt A prompt is some sort of message from the computer to a human indicating that some input is expected.
Programmer The programmer (in this documentation, at least) is the person who created the game scenario which is compiled and interpreted by ADL. Send the programmer lots of praise and/or money too.
Room A room is any object that a player may eventually enter.
Routine A routine is a series of instructions to the computer telling it what to say, what to move, what to read, and/or where to go.
Scenario A "scenario" is like a scene in a play - it specifies where Objects are located, what events might occur, who is present, and what they may do. A scenario is somewhat more general than a scene since scenarios contain rules for generating many possible scenes whereas scenes are static.
Separator A separator is a part of speech which separates two sentences. A separator can be a period ".", the word "then", or the end of a line.
String A string is a series of characters (letters, etc.) surrounded by quote marks. "foo bar bletch" is a string (legal in both the compilation and execution phases of ADL) and 'Hi, there!' is a string (legal only in the execution phase of ADL).
Stack A stack is like a stack of dishes: you may put a new dish on top of the stack (this is known as "pushing") or you may take a dish from the top of the stack (this is known as "popping"). You may not take dishes from the bottom or middle of the stack; likewise, a computer stack doesn't allow the deletion of elements in the middle of the stack.
Syntax The syntax of a language is the set of rules which say how things may be put together in order to make a valid program in that language.
User See Player.
Variable A variable is a location in the memory of a computer in which values may be stored, changed, and erased. Global variables (or globals for short) are variables which are directly accessible by name to all routines of an ADL program. Local variables (or locals) are variables which are only directly accessible by the routine in which they are named. They are only indirectly accessible by other routines.
Verb A verb is a part of speech which implies some action. "Take", "run", "eat", "sleep", and "hide" are all verbs.

Return to Contents