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 and available
from the University of California.
This is the "classic" version of the documentation,
useful for reference when looking at older sources. For the current
version of the documentation, please see
the
ADL Programmer's Reference Manual.
The ADL home page is hosted by SourceForge at:
You may obtain sources and executables for various platforms there.
For more info, see the ADL project page at:
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. See the ADL home page for more information.
1. Introduction
2. ADL Data types
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.
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.
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:
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.
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:
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.
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.
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.
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.
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.
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.
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 may be implemented in one of two ways: on the stack (like local variables on C and Pascal) in which case they are only around for as long as the current invocation of the routine; or they may reside in the same space as global variables (like static locals in C or local variables in FORTRAN) in which case they persist for the entire duration of program execution. Consult your local ADL documentation to determine which method is used in your implementation. (Note: the portable version of ADL keeps local variables on the stack)
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.
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.
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.
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!).
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.
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.
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).
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:
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.
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.
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.
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:
START [0] | v +--------------------------------->o | | | v | Daemons [1] | | | v | Get Actor <----------------------+ | | | | v | | +------------------> Clear Sentence | | | | | | | v | | | ($exit 3)====> Get Input? --n---> Delete Actor | | | | y | | | | v | | | o<---------------------- Parse? | | | ^ | | | | | v | | | o<-------------fail----- DWIMI | | | ^ | | | | | v | | | +--------------fail----- DWIMD | | | | | | | v | | | Get Dobj <-------+ | | | | | | | | v | | | | Actor ACTION [2] | | | | Verb PREACT [3] | | | | Iobj ACTION [4] | | | | Dobj ACTION [5] | | | | Verb ACTION [6] | | | | | | | | | v | | | | ($exit 2)===> More Dobjs? -y----+ | | | | n | | | v | | | Room ACTION [7] | | | | | | | v | | | ($exit 1)=========>o<-------------------+ | | | | | v | +--------------------------n- More Actors? -y-------------------+
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 "standard.adl";
MESSAGE "Whew! We're halfway through the file!\n";
VAR Score, Dark, ObjList[ 10 ], MyLoc;
VERB take, drop, open, close;
ADJEC red, green, blue;
NOUN room1; NOUN table( room1 ), chair( room1 ), red ball( room1 );
ROUTINE Looker, Prompter, Quitter;
ARTICLE the, a, an;
PREP in, into, on, above ;
room1( LDESC ) = ($say "You are in a huge room.\n") ; chair( WEIGH ) = 450 ; table( MESSAGE ) = "This space for rent\n" ;
take( ACTION ) = ($say "You can't take that object.\n"); drop( PREACT ) = (CheckAvail);
MagicWord = "AbraCadabra"; { string ID } VISIT = 3; { constant } Silly = ($say "That's silly!\n"); { routine ID } toolbox = tool box; { object ID }
( MyLoc ) = -1; ( Score ) = 10;
VAR foo[ 10 ]; ( foo ) = 3; { Sets foo[0] to 3 } ( foo + 5 ) = 6; { Sets foo[5] to 6 }
PREP in, of, before; NOUN front; in front of = before;
VERB put, take, turn, wear, remove, light, douse; PREP on, off; put on = wear; take off = remove; turn on = light; turn off = douse;
This chapter describes the syntax of ADL routines. An ADL routine consists of an optional LOCAL declaration followed by a sequence of one or more expressions. An expression is one of the following:
The value of the expression is the result of
executing rout with arguments arglist.
( IF arg1 THEN expression ... ELSEIF arg2 THEN expression ... ... ELSE expression ... )This statement evaluates arg1 and if the result is non-zero the expressions following THEN are executed. If the result of the evaluation of arg is zero then the expressions following THEN are skipped until one of ELSE, ELSEIF or the end of the conditional are found. If ELSEIF was found the corresponding arg is evaluated and execution proceeds as for IF. If none of the ELSEIFs evaluate to a non-zero value then the ELSE expressions are executed. The ELSEIFs and the ELSE are optional. The conditional expression returns the value of the last expression executed or zero of no expressions were executed.
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 = LOCAL obj; ($incturn) { Increment the turn counter } (IF ($prop ($loc .ME) VISIT) THEN { I've been here before - print a short description } ( ($sdesc ($loc .ME)) ) ELSEIF ($ne ($cont ($loc .ME)) .ME) THEN { There are other objects here } ( ($ldesc ($loc .ME)) ) ($say "You can see:\n") ($setg obj ($cont ($loc .ME))) (WHILE @obj DO { Describe each object in the room } ( ($sdesc @obj) ) ($setg obj ($link @obj)) ) ELSE { I've never been here } ( ($ldesc ($loc .ME)) ) ($say "There is nothing else in the room.\n") ) ($setp ($loc .ME) VISIT TRUE) ;
The following is the complete list of ADL built-in routines. They are organized into groups of related routines. A description 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:
These routines operate primarily on Objects. They move Objects around, find Object properties, and set Object properties.
(IF ($eq ($loc .ME) volcano) THEN ($say "You are fried to a crisp.\n") )
(IF ($eq ($cont .ME) 0) THEN ($say "You are empty-handed.\n") )
($setg obj ($cont .ME)) (WHILE @obj DO ($say ($name @obj) "\n") ($setg obj ($link @obj)) )
($setg obj ($loc .ME)) ( ($ldesc @obj) ) { Call LDESC of ($loc .ME) }
($setg obj ($loc .ME)) ( ($sdesc @obj) ) { Call SDESC of ($loc .ME) }
( ($action .ME) ) { Call ACTION of .ME }
(IF ($eq ($modif [ blue ball ] ) blue) THEN ($say "$modif works!\n") ) (IF ($eq ($modif [ north wall ] ) ($minus 0 north)) THEN ($say "$modif still works!\n") ) (IF ($eq ($modif room1) 0) THEN ($say "$modif comes through one more time!\n") )
($setg obj ($loc .ME)) (IF ($prop @obj VISIT) THEN ($say "I've been here before!\n") )
($setg obj ($loc .ME)) ($setp @obj VISIT TRUE)
(IF ($eq @Verb north) THEN ($move .ME room2) )
These two routines operate on Verbs. They are provided for scenarios in which the properties of Verbs may change.
($vset @Verb PREACT Silly)
{ Call Verb's PREACT } ( ($vprop @Verb PREACT) )
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.
($setg Score ($plus @Score 50))
($setg LivesLeft ($minus @LivesLeft 1))
($setg TimeLeft ($times @NumBattery 10))
($setg Rating ($div @Score 100))
{ Make sure XPos is from 0 to 9 } ($setg XPos ($mod @Xpos 10))
{ Move the player to a random room from room1 to room10 } ($setg Num ($rand 10)) ($move .ME ($plus room1 ($minus @Num 1)))
These routines are typically used in conditionals and loops. However, traditional bit-masking may be done with $and and $or.
($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 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 0) is 1 ($not 1) is 0 ($not 5) is 0
($say "Are you sure you want to quit? ") (IF ($yorn) THEN ($say "OK. Goodbye!\n") ($spec 3) ELSE ($say "Whew! That was a close one!\n") )
(IF ($pct 30) THEN ($say "The troll swings at you, and hits!\n") ELSE ($say "The troll's axe misses you by a hair!\n") )
($setg loc ($loc .ME)) (IF ($eq @loc room1) THEN ($say "You are in room 1.\n") )
($setg loc ($loc .ME)) (IF ($ne @LastLoc @loc) THEN ($say "You've moved since I last checked!\n") )
(IF ($lt @Score 100) THEN ($say "You are a novice adventurer\n") )
(IF ($gt @Score 1000) THEN ($say "You are a super master grand ") ($say "champion mongo adventurer!!!\n") )
(IF ($le @Score 1000) THEN ($say "You are a pretty good adventurer.\n") )
(IF ($ge @Weight 200) THEN ($say "The ice breaks under your weight!\n") )
Given: VAR var[3]; (var + 0) = 10; (var + 1) = 20; (var + 2) = 30; The statement ($global ($plus var 2)) would return 30.
(IF ($eq ($verb) take) THEN ($say "You can't take that!!\n") )
(IF ($eq ($dobj) ball) THEN ($say "Dobj = ball\n") )
(IF ($eq ($iobj) basket) THEN ($say "Iobj = basket\n") )
(IF ($eq ($prep) into) THEN ($say "Prep = into\n") )
(IF ($eq ($conj) 1) THEN ($say "The conjunction was 'but'\n") ELSE ($say "The conjunction was 'and' or ','\n") )
(IF ($gt ($numd) 1) THEN ($say "You may not use multiple direct objects!\n") )
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 north south east west ne se nw sw up down)
room1(ACTION) = ($hit .ME room2 room3 room4 0 0 0 0 0 0 0) ;
cg = ($say "You can't go that way.\n") room2(ACTION) = ($miss 0 0 0 cg cg cg cg cg cg cg) ;
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:
The program: ($setg str1 "hello") ($setg str2 ($cat "he" "llo")) (IF ($eqst @str1 @str2) THEN ($say "String 1 == string 2\n") ) (IF ($ne @str1 @str2) THEN ($say "String ID 1 != string ID 2\n") ) will produce the output: String 1 == string 2 String ID 1 != string ID 2
The program: ($setg str "Hello world") ($say ($subs @str 0 5) "\n") ($say ($subs @str 6 0) "\n") will produce the output: Hello world
($leng "Hello") is 5 ($leng "") is 0
($cat "hello " "world") returns "hello world"
($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
($say "What is your name? ") ($setg MyName ($read)) ($say "Hello, " @MyName ", welcome to ADL!\n")
($setg MyName ($savestr @MyName))
The following routines all return volatile strings which contain the requested name.
($say "You see no " ($name @Dobj) " here!\n")
($say "No multiple objects with " ($vname @Verb) "!\n")
($say "The modifier of blue ball is " ($mname blue) "\n")
($say "The sentence is:\n") ($say ($vname @Verb) " " ($name @Dobj) " " ($pname @Prep) " " ($name @Iobj) )
The following routines perform conversions between strings and numbers.
($str 3) is the string "3"
($num "234") is the number 234
($ord "ABC") is 65
($chr 97) is the string "a".
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 Looker) ($sdem Follower)
($ddem Follower)
($sfus .ME LampDie 300)
(IF @BatteryFound THEN ($dfus .ME LampDie) )
sleep(ACTION) = ($incturn 300) ;
(IF ($eq @Verb north) THEN (IF ($gt ($turns) 230) THEN ($move .ME room3) ELSE ($move .ME room5) ) )
($prompt Prompter)
($actor Myself NULL TRUE) ($setg s "Go east then south. Push button. Go north") ($actor robot @s FALSE)
(IF ($prop robot BROKEN) THEN ($delact robot) )
(IF ($eq @MyDir 1) THEN ($define "left" "north") ($define "right" "south") ELSE ($define "left" "south") ($define "right" "north") )
($undef "left") ($undef "right")
+------+---------------------------------------+ | code | function | +------+---------------------------------------+ | 1 | Toggle the instruction trace flag | | 2 | Restart this game | | 3 | Terminate execution of this game | | 4 | Save this game in file arg1 | | 5 | Restore this game from file arg1 | | 6 | Execute the system program named arg1 | | 7 | Preserve unknown words in file arg1 | | 8 | Write a script to file arg1 | | 9 | Print a header line on the screen | | 10 | Set the right margin | +------+---------------------------------------+
VERB debug; debug(ACTION) = ($spec 1); VERB restart; restart(ACTION) = ($spec 2); VERB quit; quit(ACTION) = ($spec 3); VERB save; save(ACTION) = LOCAL name; ($say "Save to what filename? ") ($setg name ($read)) (IF ($leng @name) THEN ($spec 4 @name) ) ; VERB restore; restore(ACTION) = LOCAL name; ($say "Restore from what filename? ") ($setg name ($read)) (IF ($leng @name) THEN ($spec 5 @name) ) ; VERB shell; shell(ACTION) = ($spec 6 "/bin/csh") ; VERB savewords; savewords(ACTION) = ($spec 7 "unknown.wrds") ; VERB script; script(ACTION) = LOCAL name; ($say "Script to what filename? ") ($setg name ($read)) (IF ($leng @name) THEN ($spec 8 @name) ) ; Status = ($spec 9 ($name ($loc .ME)) @Score ($turns)) ; START = ($spec 10 60); { It makes the text prettier }
These routines are placed here for lack of a better place to put them.
($say "Hi! My name is " @MyName "! How are you today?\n")Note that MyName is assumed to contain a string ID.
{ Print all of the arguments to this routine } ($setg i 1) (WHILE ($le @i %0) DO ($say "Arg " @i " = " ($arg @i) "\n") )
take(PREACT) = (IF ($ne ($loc @Dobj) ($loc .ME)) THEN ($say "You don't see that here!\n") { Skip the rest of the phases } ($exit 1) ) ; safe(ACTION) = (IF ($eq @Verb take) THEN ($say "You can't budge the safe.\n") { Go on to the rest of the Dobjs } ($exit 2) ) ; ball(ACTION) = (IF ($prop ball BROKEN) THEN { Rely on the default verb ACTION } ($exit 0) ) ($say "The ball bounces nicely.\n") ; NOVERB(PREACT) = ($say "What do you want me to do with the " ($say ($name @Dobj) "?\n") { Re-parse the sentence } ($exit 3) ;
Increment = ($return ($plus %1 1)) ($say "Increment( 3 ) = " (Increment 3) "\n") would print: Increment( 3 ) = 4
Signum = (IF ($lt %1 0) THEN ($val -1) ELSEIF ($eq %1 0) THEN ($val 0) ELSE ($val 1) ) ;
(IF ($eq ($phase) 2) THEN ($say "This is the Actor ACTION\n") ELSEIF ($eq ($phase) 4) THEN ($say "This is the Iobj ACTION\n") ELSEIF ($eq ($phase) 5) THEN ($say "This is the Dobj ACTION\n") )
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 = stmt * stmt = "INCLUDE" STRING ";" = "MESSAGE" STRING ";" = decl = assign decl = "VERB" ilist = "ADJEC" ilist = "ROUTINE" ilist = "ARTICLE" ilist = "PREP" ilist = "VAR" vlist = "NOUN" nlist assign = ID "=" expr ";" = nounp "(" nprop ")" "=" expr ";" = VERB "(" vprop ")" "=" routine ";" = "(" VAR [ "+" const ] ")" "=" expr ";" = 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 expr = const = STRING = nounp = routine = modif = ROUTINE = PREP = ARTICLE = VAR routine = [ locals ] form + locals = "LOCAL" vlist form = "(" ifthen elseif * [ else ] ")" = "(" "WHILE" arg "DO" form + ")" = "(" arg + ")" ifthen = "IF" arg "THEN" form + elseif = "ELSEIF" arg "THEN" form + else = "ELSE" form + arg = form = "@" VAR = "[" nounp "]" = ".ME" = "%"NUMBER = const = STRING = NOUN = OBJECT = ROUTINE = modif = PREP = ARTICLE = VAR = vprop = nprop
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
The following object properties are defined in standard.adl. The ADL programmer using standard.adl is advised not to re-use these properties with different meanings, as strange and unusual things will happen.
This leaves (TBD: how many?) boolean properties and (TBD: how many?) integer properties free for the programmer's definition and use. The above properties are used as follows:
For convenience and readability, standard.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 standard.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:
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;
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:
In addition to declaring the preceding verbs, standard.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;
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:
{ "take" needs 1 to N Dobjs and 0 or 1 Iobjs } take(PREACT) = (Expect ($or MULT_OBJ PLAIN_OBJ) ($or NO_OBJ ONE_OBJ PLAIN_OBJ)) ; { "quit" can accept no objects } quit(PREACT) = (Expect NO_OBJ NO_OBJ) ; { "unlock" needs exactly one Dobj and Iobj } unlock(PREACT) = (Expect ($or ONE_OBJ PLAIN_OBJ) ($or ONE_OBJ PLAIN_OBJ) ) ; { "say" needs a string to say and possibly someone to whom to say it } say(PREACT) = (Expect ($or ONE_OBJ STR_OBJ) ($or NO_OBJ ONE_OBJ PLAIN_OBJ)) ;
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 standard.adl.
INCLUDE "standard.adl"; NOUN startrm, brightroom; { Locations in the dungeon } startrm(LIGHT) = TRUE; brightroom(LIGHT) = TRUE; cg = ($say "You can't go that way.\n"); startrm(LDESC) = ($say "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) = ($say "Comfortable room.\n"); startrm(ACTION) = ($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) = ($say "You are in a brightly lit room. The walls sparkle " "with scintillating lights. There is a darker room " "to the west.\n") ; brightroom(SDESC) = ($say "Bright room.\n"); brightroom(ACTION) = ($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) = ($say "There is a red pillow here.\n"); red pillow(SDESC) = ($say "A red pillow"); blue pillow(LDESC) = ($say "There is a blue pillow here.\n"); blue pillow(SDESC) = ($say "A blue pillow"); NOUN platinum(brightroom); bar = platinum; platinum(LDESC) = ($say "There is a bar of platinum here!\n"); platinum(SDESC) = ($say "A platinum bar"); platinum(ACTION) = (IF ($and ($eq ($verb) drop) ($eq ($loc .ME) ($loc [red pillow]))) THEN ($say "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 3) ) ; NOUN SELF(startrm); SELF(NOTAKE) = TRUE; START = ($prompt Prompter) ($sdem Looker) ($actor SELF 0 1 0) ($setv n s e w 0 0 0 0 0 0) ; DWIMD = ($return (DWIM %1)); DWIMI = (DWIM %1); { This result will be returned by default }
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 "standard.adl"; { Include the standard package } { The following are Object properties } BROKEN = 1; { Is the robot damaged? } TOLD = 2; { Have I told the robot something? } BSTATE = 17; { 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, Die, 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 ) = ($say "You are in a large room which is illuminated by a bright red glow. Exits lie to the east and south.\n" ) ; Redrm( SDESC ) = ($return (Header "Red room" %0)); Redrm( LIGHT ) = TRUE; Greenrm( LDESC ) = ($say "You are in a smallish room which is illuminated by a pleasant green glow. The only exit is to the west.\n" ) ; Greenrm( SDESC ) = ($return (Header "Green room" %0)); Greenrm( LIGHT ) = TRUE; Bluerm( LDESC ) = ($say "You are in a tiny room which is barely illuminated by a dim blue glow. There is an exit to the north," ) (IF ($eq ($prop button BSTATE) B_LIT) THEN ($say " 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 ($say " and you seem to make out something on the floor.") (IF ($prop button BSTATE) THEN ($say " A button on the wall is flashing urgently.") ELSE ($say " There is a button on the wall.") ) ) ($say " Above the button is a sign that reads:\n\n" " DANGER!\n\n" " HIGH VOLTAGE!\n\n" ) ; Bluerm( SDESC ) = (IF %0 THEN ($return "Blue room")) ($say "Blue room.\n") ; Bluerm( LIGHT ) = TRUE; Cellar( LDESC ) = ($say "You are in the cellar. Far above you can be seen a dim blue light." ) (IF ($prop door OPENED) THEN ($say " An open door leads to the north.\n" ) ELSE ($say " You can barely see the outline of a door to the north.\n" ) ) ; Cellar( SDESC ) = ($return (Header "Cellar" %0)) ; Cellar( LIGHT ) = TRUE; Endrm( LDESC ) = ($say "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" ) ($setg Score ($plus @Score 25)) (Skore) ($spec 3) ; Endrm( LIGHT ) = TRUE; { Verbs } VERB score, push, shout; tell = TELLER; say = tell; press = push; feel = touch; yell = shout; { Verb routines } tell( PREACT ) = (IF ($ne @Iobj robot) THEN { The only logical thing to talk to is the robot } (Sayer "Talking to yourself is said to be a sign of impending insanity" ) ELSEIF ($ge @Dobj 0) THEN { You must say strings } (Sayer "You must put what you want to say in quotes" ) ELSEIF ($ne ($loc robot) ($loc me)) THEN { The robot must be in the same place as the player } (IF (Myself) THEN ($say "You don't see the robot here.\n") ) ELSE { Everything is OK. Add 25 points to the score } (IF ($not ($prop robot TOLD)) THEN ($setg Score ($plus @Score 25)) ($setp robot TOLD TRUE) ) ($exit 0) ) ($exit 1) ; tell( ACTION ) = { Tell the player that we heard him } ($say "\"Sure thing, Boss.\"\n") { Delete the old action } ($delact robot) { Add the new action - a non-interactive actor } ($actor robot @Dobj FALSE) ; shout( PREACT ) = (IF ($and @Iobj ($ne @Iobj robot)) THEN { Shouting at things other than the robot } ($say "AAARRRGGGHHH!\n") ELSEIF ($ge @Dobj 0) THEN { Shouting things other than strings } ($say "EEEYYYAAAHHH!\n") ELSEIF ($prop robot BROKEN) THEN ($say "There is no response.\n") ELSE { Shouting at the robot - same as telling the robot } (IF ($not ($prop robot TOLD)) THEN ($setg Score ($plus @Score 25)) ($setp robot TOLD TRUE) ) ($exit 0) ) ($exit 1) ; shout( ACTION ) = { Tell the player we heard him } (IF ($ne ($loc robot) ($loc me)) THEN ($say "In the distance you hear the words, ") ) ($say "\"Sure thing, Boss\"\n") { Delete the old robot action } ($delact robot) { Add the new robot action } ($actor robot @Dobj FALSE) ; push( PREACT ) = { Expect a plain direct object } (Expect ($or ONE_OBJ PLAIN_OBJ) NO_OBJ) (CheckAvail) ; push( ACTION ) = (Sayer "That doesn't seem to do anything") ($exit 1) ; score(PREACT) = { Score can accept no objects } (Expect NO_OBJ NO_OBJ) (Skore) ($exit 1) ; { Object properties } button( SDESC ) = (IF ($eq ($prop button BSTATE) B_OFF) THEN ($say "a button") ELSEIF ($eq ($prop button BSTATE) B_FLASH) THEN ($say "an urgently flashing button") ELSE ($say "a brightly lit button") ) ; button( ACTION ) = (IF ($and (Myself) ($or ($eq @Verb push) ($eq @Verb take) ($eq @Verb touch) ) ) THEN { The player tried to do something with the button } ($say "As you reach for the button, a 10,000,000 volt bolt of lightning arcs toward your finger, disintegrating you upon impact.\n" ) (Die) ELSEIF ($and ($eq @Verb push) ($eq ($prop button BSTATE) B_OFF)) THEN { The robot pushed the button } ($setp button BSTATE B_FLASH) ($setg Score ($plus @Score 50)) ($sfus me Lifter 4) ($exit 1) ELSEIF ($eq @Verb take) THEN { Can't take the button } ($setg Skip TRUE) ) ; SimpleRobot = "I am just a simple robot"; robot( LDESC ) = ($say "There is a robot here.\n"); robot( SDESC ) = ($say "a robot"); robot( ACTION ) = (IF (Myself) THEN { I'm doing something with the robot } (IF ($eq @Verb tell) THEN (IF ($prop robot BROKEN) THEN ($say "There is no response.\n") ($exit 1) ) ELSEIF ($eq @Verb take) THEN ($say "The robot weighs at least 500 pounds!\n") ($exit 1) ) ELSEIF ($eq ($phase) 2) THEN { This is being called as the Actor ACTION } (ActAction) (IF ($and ($ne @Verb push) ($ne @Verb go) ($ne @Verb wait) ($ne @Verb take) ($or ($lt @Verb north) ($gt @Verb down))) THEN { The robot has a VERY simple vocabulary } (Sayer SimpleRobot) ($delact robot) ($exit 1) ) ELSEIF ($eq @Verb take) THEN { The robot is trying to take itself } (Sayer "Mmmph! Akkk!! GGGGRR!! No can do. Sorry") ($setg 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 = (IF ($eq ($phase) 2) THEN { This is the Actor ACTION - call standard's actor action } (ActAction) ELSEIF ($eq @Verb take) THEN (Sayer "I thought you would never ask") ($setg Skip TRUE) ) ; { We break hatch( SDESC ) out into a named routine because the hatch isn't visible until after Lifter has executed } HatchSD = ($say "an open hatch"); HatchMSG = "The hatch doesn't budge"; hatch( ACTION ) = (IF ($eq @Verb take) THEN { Can't take the hatch } (Sayer HatchMSG) ($setg Skip TRUE) ELSEIF ($or ($eq @Verb open) ($eq @Verb push)) THEN { Can't open or push it, either } (Sayer HatchMSG) ($exit 1) ) ; hatch( OPENS ) = TRUE; hatch( NOTAKE ) = TRUE; door( SDESC ) = ($say "a door"); door( ACTION ) = (IF ($eq @Verb take) THEN ($say "You can't take a door!\n") ($setg 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 ) = ($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 ) = ($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 ) = ($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 ) = ($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 = ($return ($eq .ME me)) ; { (Sayer str) - Says a string with appropriate quoting, depending on whether the robot or the player is doing the saying. } Sayer = (IF (Myself) THEN ($say %1 ".\n") ELSEIF ($eq ($loc robot) ($loc me)) THEN ($say "\"" %1 ", Boss.\"\n") ELSE ($say "You hear a muffled voice in the distance.\n") ) ; { (NoGo) - "You can't go that way" } NoGo = (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> %0)), we can centralize the saying/returning decision. } Header = (IF ($not %2) THEN ($say %1 ".\n") ) ($return %1) ; RobMov = (IF ($and ($not (Myself)) ($eq ($loc robot) ($loc me))) THEN ($say "The robot exits to the " (IF ($eq @Verb e) THEN ($val "east") ELSEIF ($eq @Verb w) THEN ($val "west") ELSEIF ($eq @Verb s) THEN ($val "south") { The robot can't be seen leaving to the north } ) ".\n" ) ) ; RobEntr = (IF ($and ($not (Myself)) ($eq ($loc robot ) ($loc me))) THEN ($say (IF ($eq @Verb north) THEN ($val "The robot enters from the south.\n") ELSEIF ($eq @Verb east) THEN ($val "The robot enters from the west.\n") ELSEIF ($eq @Verb west) THEN ($val "The robot enters from the east.\n") { The robot can't enter from the north in this scenario } ) ) ) ; DoorCk = (IF ($not ($prop door OPENED)) THEN ($say "The door seems to be closed.\n") ($exit 1) ) ; TrapCk = (IF ($ne ($prop button BSTATE) B_LIT) THEN (NoGo) ) ; { (BlueCk) - make sure that only one actor is in the blue room at one time. } BlueCk = (IF ($or ($eq ($loc me) Bluerm) ($eq ($loc robot) Bluerm)) THEN (IF (Myself) THEN ($say "The room is too small for both you and the robot to fit.\n" ) ) ($exit 1) ELSEIF ($and ($not (Myself)) ($eq ($prop button BSTATE) B_LIT)) THEN (RobMov) ($say "You hear a loud CRASH! in the distance.\n") ($setg Score ($minus @Score 10)) ($setp robot BROKEN TRUE) ($move robot Bluerm) ($delact robot) ($exit 1) ) (RobMov) ; { (Die) - kill off the player } Die = ($setg Score ($minus @Score 50)) (Skore) ($say "Do you wish to restart the game? ") (IF ($yorn) THEN ($spec 2) ELSE ($spec 3) ) ; { (Lifter) - Lift the hatch, possibly killing the robot or the player } Lifter = (IF ($eq ($loc me) Bluerm) THEN ($say "All of a sudden, the floor lifts up, and you are crushed between it and the wall! " ) (Die) ELSE ($say "In the distance, you hear a loud CRASH!\n") (IF ($eq ($loc robot) Bluerm) THEN ($setg Score ($minus @Score 10)) ($setp robot BROKEN TRUE) ($delact robot) ) ) ($setp hatch SDESC HatchSD) ($setp button BSTATE B_LIT) ($setp Bluerm SEEN FALSE) ; { Prompt - print the status line and a prompt } PROMPT = ($spec 9 (($sdesc ($loc .ME)) 1) @Score ($turns)) ($say "> ") ; { Increment - increment the turn counter } INCREMENT = (IF (Myself) THEN { 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 = ($say "You have scored " ($str @Score) " out of a possible 100 in " ($str ($turns)) " moves.\n") ; { Dwimming routines } DWIMI = (Dwimmer %1); DWIMD = (Dwimmer %1); START = ($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 ***}