A Brief Description of UCLA
Dungeon Definition Language (DDL)
Bruce Adler
Chris Kostanick
Michael Stein
Michael Urban
University of California
Los Angeles, CA 90024
This document describes Dungeon Definition Language, a
meta-adventure specification language. It is designed primarily
for the programmer who wishes to create a DDL "world", and
secondarily for the programmer attempting to implement DDL on a new
host machine.
(c) 1981 UCLA Computer Club
1. Introduction.
DDL is a system of notation for the specification
of "worlds". Using DDL, a programmer may create
Objects, Verbs to act upon those objects, and Routines
to describe the behavior of Objects and Verbs. The
user of a DDL program, known as the Player, types these
verbs and the names of objects to manipulate those
objects at a high level. Thus, a Player's dialogue
with a DDL program will appear something like:
You are standing outside the north entrance of a large
brick building. Inscribed above the doorway, appear the
text: 'AARDVARK'S MUSEUM -- GATEWAY TO ADVENTURELAND'.
There is a coil of rope here.
There is a shovel here.
There is a carbide-flame lamp here.
There is a copy of a newspaper here.
>take rope
OK
>south
You are in a large rotunda of an old museum. Doors lead
to the north, south, east, and west, and a narrow stairway
in the north-east corner of the room leads down.
There is a ball-point pen here.
There is a slip of paper here.
>take paper
OK
>take pen
OK
>e
You are in a dimly lit room containing an empty display case.
A portion of a vandalized sign above the case reads:
'ARTIFACTS OF ANCIENT INDIA -- Several of these items,
including the sacred rhinoceros horn, the deadly ...'.
The rest of the sign is unreadable.
To the west, you can look through a large door into the rotunda
of the museum. On the east wall of the hall there is an outline
of an arch.
>sign paper
In a blinding flash of light, a stone archway appears in the east wall!
This sort of behavior will be familiar to users of
the celebrated programs, Adventure and Dungeon (AKA
Zork ), of Crowther, Woods, Anderson and Blank. While
not as sophisticated in many ways as some of these pro-
grams, the primary function of DDL is to allow a number
of interesting puzzles and games to be exchanged among
users of disparate machines with a minimum of portabil-
ity problem.
2. General Flow of Execution.
When the DDL program begins execution, a special
routine which has been coded by the DDL programmer is
executed. This routine must be given the name START.
START will normally initialize demons and set certain
initial values. Execution then proceeds in the cyclic
fashion described below.
When a DDL scenario is running, execution proceeds
in a series of cycles known as "turns". On each turn,
a number of actions takes place.
(1) Demons:
Each of the Demon routines currently active
is run in order of activation. Demon rou-
tines are specified and activated by the DDL
program by executing the $sdem function.
Note: The normal action of Looking (executing
description routines) which one expects to
occur on each turn must be coded by the DDL
programmer as a Demon.
(2) Fuses: All active Fuse routines are checked to see
if they are to be executed on this turn.
Those Fuses which have thus "burned down" are
then executed (in reverse order of activa-
tion) and removed.
(3) Parse: The player types a line of input, and an
attempt is made to resolve that input into a
Verb, an Indirect Object, and a Direct
Object, by means of attendant Prepositions,
Articles, and Adjectives. Unambiguous abbre-
viations for words are recognized by the
parser. If an input Noun is ambiguous
(because of two objects distinguished by only
adjectives), DDL routines called DWIMD and
DWIMI are used to disambiguate direct and
indirect objects respectively. DWIMD and
DWIMI each return nonzero if the direct or
indirect object is "possibly the one he
means" (e.g. if it is in the room, etc));
only if exactly one such object exists with
the given Noun name can the parse complete
successfuly. any of the input components are
found to be missing, the value zero is
assumed for that object (and no associated
routines are executed).
If a syntax error or unknown word is detected, a
hopefully informative error message is printed. In
addition, unknown words encountered in the input may be
saved in a file for perusal by the DDL programmer.
The direct object may be enclosed in double-quotes
by the Player. Such a direct object is returned as a
String to the program. Strings may be detected by the
program as having "numeric values" less than zero.
Strings may be operated on with the $eqst, $subs, and
$leng functions, and the $say procedure.
(4) Pre-action:
The PREACT routine (if any) that the DDL pro-
grammer has associated with the input Verb is
executed. These routines typically will
check for the availability of the object in
question, and so on.
(5) Indirect Object:
The ACTION routine associated with the
Indirect Object that the Player typed (if
any) is executed.
(6) Direct Object:
The ACTION routine associated with the Direct
Object that the Player typed (if any) is exe-
cuted. For most specialized actions (like
"rub lamp") the particular code is frequently
attached to the object. If the Direct Object
is a String, the ACTION routine (if any)
associated with the object STRING (if such is
defined by the programmer) is executed.
(7) Room Action:
The ACTION routine associated with the room
the Player is in (actually, the LOC of .ME)
is executed. Normally, this will be a "tran-
sition" routine which will check if the verb
is "north", and so on. Note: This is the
ONLY aspect of "built-in" action which
depends in ANY WAY upon the actual state of
variables within the "dungeon" itself.
(8) Verb: The ACTION routine associated with the input
Verb (if any) is executed. ACTION routines
for most Verbs will often be default rou-
tines. For example the Action routine for
the Verb "rub" might print "Rubbing that
object is not useful."
If any of these routines terminates with an ($exit 1),
the remainder of the current turn is skipped. Further-
more, the DDL programmer is responsible for increment-
ing the Turn Counter (normally in a Demon routine) if
Fuses are to be used.
3. Data types.
3.1. Objects.
Player machinations are in terms of Objects. All
Objects are nodes in a tree, the root node of which is
labelled ".ALL". A second special object, ".ME" is
considered to represent the Player. Objects will nor-
mally be treated either as rooms or portable-type
objects, but DDL itself does not distinguish these
functions; all objects are stored and treated uni-
formly. It is therefore possible, in principal, to
write a DDL scenario in which the Player may pick up a
room, carry it, and later enter it. Each object
possesses the following attributes. If any of these is
not specified, it is given the default value of zero.
LOC: The object ID of the parent (location) of the
object.
CONT: The object ID of the first child (contents) of
the object.
LINK: The object ID of the next sibling (others in the
same place) of the object
ADJ: The Adjective ID which uniquely distinguishes
this object from others of the same name (if
any).
OTHERS:
The Object ID of another object with the same
name as this object, though with a different
adjective.
NAME: The unqualified Noun by which the Player names
the object.
PROPS: Up to 25 numeric values can be arbitrarily asso-
ciated with an object by the DDL programmer.
Properties 1-16 may only possess the values 0 or
1. The others may range in value from -32768 to
+32767. The last three of these properties have
special usages. Their indices are predefined by
the compiler.
LDESC (23)
The Routine ID of a "Long Description" routine
SDESC (24)
The Routine ID of a "Short Description" routine
ACTION (25)
The Routine ID of a "Action" routine, to be
called if the Player either attempts to do some-
thing with that object (specifies it as a Direct
or Indirect Object), or while inside that object.
3.2. Verbs.
The "commands" typed by the Player must name Verbs
which have been defined by the DDL programmer. Each
Verb is associated with two Routine ID's:
PREACT:
The Routine ID of a routine to execute when the
verb has been recognized and the remaining input
identified, but before any "Action" routines
associated with the Objects in that input have
been executed. For example, the PREACT routine
of "take" might check to see if the direct object
is in the room.
ACTION:
The Routine ID of a routine to execute after all
input object action routines have been called.
Our experience has been that such routines end up
being "default" routines that typically only say
things like "Rubbing that object does nothing."
3.3. Strings.
Simple strings may be defined by the DDL program-
mer to be printed. Strings may be up to 255 bytes in
length, delimited by double-quote marks. Carriage
returns may be embedded in strings freely, or the
sequence \n may be used to represent a carriage return
at any point.
3.4. Numbers.
DDL programers may only specify nonnegative
integers up to 32767. However, a routine may compute
any integer value from -32768 to +32767.
3.5. Adjectives.
Adjectives possess no data, but are uniquely num-
bered by the DDL compiler so as to have unique internal
IDs (which begin at the value 1). Adjectives are nor-
mally only used to distinguish various objects which
have the same Noun name (eg the "red book" and the
"blue book").
3.6. Routines
Routines represent the actual logical behavior of
the Dungeon. A routine consists of one or more calls
to builtin or user-defined functions. Internally, a
routine may be stored as an interpretive program for a
very simple stack machine. The internal representation
is up to the implementer. Routines may call one
another, and a single routine may call itself recur-
sively.
3.7. Globals
50 globals (numbered 0-49) are available to the
DDL programmer and may contain any integer value. They
are named by numeric constants. Such constants are
conveniently assigned symbolic names by means of the
VAR declaration described below. The last three glo-
bals are set each turn to contain the Indirect Object,
Direct Object, and Verb typed by the player. The con-
stants Iobj, Dobj, and Verb are predefined by the com-
piler to refer to those globals.
4. DDL Programs
Note: In the syntactic descriptions below, meta-
variables such as varname refer to user-defined iden-
tifiers. These identifiers consist of a string of
alphameric characters of arbitrary length. A DDL
specification consists of one or more DDL statements,
each terminated by a semicolon. The following state-
ments exist:
VAR varname, varname,...
Declares each varname as a new symbol. The symbol
is defined as a constant with a value different from
each previously declared <varname>. <varname> must not
be previously declared.
Example: VAR strength, intell, wisdom;
VERB verbname, verbname,...
Declares each verbname as a new verb. verbname
must not be previously assigned.
Example: VERB north,south,east,west;
ADJEC adjectivename, adjectivename,...
Creates a new adjective with name adjectivename,
which must not be previously assigned.
Example: ADJEC red,green,blue;
NOUN noun[(container)]
Creates a new object named noun whose initial
location is container. noun may not be previously
assigned; container must be of type NOUN. If the (con-
tainer) clause is omitted, the new object is placed in
object .ALL . the noun may actually be a adjective-
noun pair.
Examples:
NOUN red book, blue book;
NOUN worm(red book);
ROUTINE routinename, routinename, ...
Declares that the routinenames listed will be
used for Routines later in the program. This
is to allow DDL, which is intended to be easily
implementable, to deal with recursive routines
(which have not yet been declared at the time
of their definitions). Only routines which are
used before being defined need to be declared
with this statement.
ARTICLE article, article,...
Creates each article as an article. Articles are
recognized by the run-time parser, but are basically
"noise" words.
Example: ARTICLE the;
PREP prep, prep,...
Creates each prep as a preposition. Prepositions
are basically noise words, but are used by the parser
to recognize the presence of indirect objects in the
Player's input.
Example: PREP into,on,using,to,at;
noun (numexp) = exp2
Property numexp of noun is set to the value of
exp2. exp2 may be a number, a string, a routine name,
or a new routine; the numeric value or ID of exp2 is
always placed into the specified property.
Examples:
gem(11)=0; { 11 == Luminous }
gem(LDESC) = ($say "There is a bright gem here!");
gem(SDESC) = ($say "a bright gem");
gem(ACTION) = GmAct;
verb (PREACT | ACTION) = routine
Assigns routine as the pre-object action or
default action of the given verb. The routine may be a
predefined routine name or an actual routine.
Example:
rub(ACTION) = ($say "Rubbing ")
($sdisc ($dobj))
($say " seems silly.0);
name = number
Assigns name as equivalent to number. name must
not be previously assigned.
Example: OPEN=11; TRUE=1;
name1 = name2
Assigns name1 as a synonym for name2.
Example: n=north;s=south;se=southeast;
(numexp) = numexp2
Assigns the global (or VAR) named by numexp to the
value given by numexp2.
Example: (Maxpt)=450;
name = "string"
Assigns name as equivalent to "string". Note:
This seems to be rarely, if ever, used. Usually it's
just as easy to assign a routine to Say the given
string. However, there are other string functions,
such as $eqst and $substr, for which it may be useful
to predefine strings.
Example:
err="Nothing happens.\n";
MagicWord = "ShaZam";
name = routine
Assigns name as equivalent to routine
Example: sayer=($say "Nothing happens.\n");
INCLUDE "filename"
(UNIX implementation only) Causes input to be read
from the named file.
5. Routines
A routine is a list of one or more "forms". Forms are
of three types:
(form1 : form, form ... [: elseform, elseform ...])
Conditional expression. If form1 evaluates to
nonzero, the subsequent forms are executed in sequence.
Otherwise, the list of elseforms is executed in
sequence. Note: The second colon, and the subsequent
elseforms, are optional.
Example:
(TRUE : ($say "Always do me") : ($say "Never do me"))
(WHILE form1 : form, form ... )
Simple looping construct. If form1 evaluates to
nonzero, the subsequent forms are evaluated in
sequence. This process is repeated until such a time
as form1 is found to evaluate to zero.
Example:
(WHILE ($eq ($loc .ME) JewlRoom) : (TRYmv .ME Prison))
(function arg1 arg2 ...)
Function call (note that all builtin functions
begin with the character $). The function is applied
to the args. An argument may be a number, string,
declared name, or another form. However, the function
must be a simple identifier, or a form which evaluates
to a function identifier ( e.g. ($ldisc xxx)). In
addition, three special argument types are recognized:
An argument such as "@number" is interpreted as
"contents of global number".
An argument such as "%numberR" is interpreted as
"the value of the numberR argument to this function".
An argument such as "[adj noun]" must be used if
the programmer wishes to refer to an object with an
associated adjective.
Examples:
VERB north,south,east,west,ne,nw,se,sw,up,down;
n=north; s=south; e=east; w=west; u=up; d=down;
NOUN rm001,rm002,rm003,rm004,rm005,rm006;
NOUN .ME(rm001);
ADJECTIVE red,blue;
NOUN red ball(rm002),blue ball(rm003);
red ball(LDESC) = ($say "There is a red ball here.");
red ball(SDESC) = ($say "Red ball.");
VAR score;
(score) = 0;
TAKBT = 16;
TRUE = 1; FALSE=0;
red ball(TAKBT) = TRUE;
ROUTINE takeR; { Declared later }
VERB take;
take(ACTION) = ( ($and ($prop ($dobj) TAKBT)
($eq ($loc .ME)($loc ($dobj)))):
(takeR ($dobj))
);
takeR = ($move %1 .ME)
(($eq %1 [red ball]):
($say "The ball is glowing!")
($setg score ($plus 10 @score)));
6. Built-in Functions
The following functions are built-in functions avail-
able to the DDL programmer. These functions are the heart
of the DDL system and are the means whereby the DDL routines
manipulate all system data. Thus, these functions com-
pletely describe the facilities of the DDL system.
6.1. Functions on objects
$loc ($loc obj) -> The container of obj.
$cont ($cont obj) -> First item contained in obj.
$link ($link obj) -> The next object in the same node as obj.
$ldisc ($ldisc obj) -> The routine ID for the long description of obj.
$sdisc ($sdisc obj) -> The routine ID for the short description
of obj.
$rtn ($rtn obj) -> The ACTION routine for obj.
$prop ($prop obj propnum) -> returns the value of the propnum'th
property of obj.
6.2. Arithmetic Funcions
$plus ($plus arg1 arg2) -> arg1+arg2
$minus ($minus arg1 arg2) -> arg1-arg2
$times ($times arg1 arg2) -> arg1*arg2
$quotient ($quotient num den) -> [num/den]
$remainder ($remainder num den) -> num mod den
$rand ($rand arg) -> Random integer between 1 and arg inclusive
6.3. Boolean Functions
$and ($and a b) -> a (bitwise AND) b
$or ($or a b) -> a (bitwise OR) b
$not ($not x) -> IF x nonzero THEN zero ELSE one.
$yorn ($yorn) -> Waits for the Player to type a line of
input. Returns one if the Player types "yes" or "y"
and zero otherwise.
$pct ($pct prob) -> Returns one, prob% of the time, zero
otherwise.
$eq ($eq arg1 arg2) -> 1 if arg1 equals arg2, zero oth-
erwise.
$ne ($ne arg1 arg2) -> IF arg1 ~= arg2 THEN one ELSE
zero.
$lt ($lt arg1 arg2) -> 1 if arg1 < arg2, zero otherwise.
$gt ($gt arg1 arg2) -> 1 if arg1 > arg2, zero otherwise.
$le ($le arg1 arg2) -> 1 if arg1 <= arg2, zero other-
wise.
$ge ($ge arg1 arg2) -> 1 if arg1 >= arg2, zero other-
wise.
6.4. Builtin Procedures (no return value)
$setg ($setg globalnumber value) -> No return value.
Sets the contents of global #globalnumber to value.
$setp ($setp obj propnum value) -> No return value. Sets
the propnum'th property of obj to value. Note that
properties 1-16 may only contain 0 or 1.
$move ($move obj dest) -> No return value. Causes obj to
be placed inside dest, and adjusts pointers accord-
ingly. Danger: No checking is performed to verify
that $move is not being used to violate the tree
structure of the object list (eg ($move obj obj)).
Bad results are likely if this occurs.
$say ($say msg) -> No return value. Types msg.
$name ($name obj) -> No return value. Types the (5-
letter) name of obj.
$num ($num x) -> No return value. Types the number x.
$exit ($exit n) -> Leave present routine. ($exit 1)
causes the current "turn" to be prematurely ter-
minated and the next turn to be initiated at the
Demon phase. ($exit 0) returns to the driver to
begin the next phase.
$rtrn ($rtrn n) -> Exits to the calling routine, returning
value 'n' TO THE CALLING FUNCTION.
$spec ($spec code arg1 arg2 arg3 arg4) -> Performs a spe-
cial function as follows:
+------+-----------------------------------+
| code | function |
+------+-----------------------------------+
| 3 | Terminate this run of DDL |
+------+-----------------------------------+
| 4 | Save a game |
+------+-----------------------------------+
| 5 | Restore a game |
+------+-----------------------------------+
| 7 |Preserve unknown words in file arg1|
+------+-----------------------------------+
Functions 4 and 5 prompt for a file name in which the
saved game is kept. Function 7 causes any unknown words
encountered by the parser to be preserved in a file for
later perusal by the DDL programmer. It would be used to
learn about things players have tried unsuccessfully that
should be dealt with. The file must already exist, and must
be specified as a string.
ALL arguments must be specified, even if zero.
6.5. Global-value functions
$glob ($glob n) -> Value of global n. Equivalent to @n.
$verb ($verb) -> The ID of the verb returned by the parser
(zero if none). Typically used in comparisons, it
is equivalent to @Verb.
$dobj ($dobj) -> The ID of the direct object returned by
the parser (zero if none). Equivalent to @Dobj.
$iobj ($dobj) -> The ID of the indirect object returned by
the parser (zero if none). Equivalent to @Iobj.
6.6. Transition Procedures
$setv ($setv v1 v2 v3 v4 v5 v6 v7 v8 v9 v10) -> sets the
values in the internal vector VECVERB to the values
v1 thru v10. These are used by routines $hit and
$miss.
$hit ($hit mover d1 d2 d3 d4 d5 d6 d7 d8 d9 d10) -> No
return value. Compares ($verb) with the values in
builtin vector VECVERB. When ($verb) is found to
match the nth entry in VECVERB, ($move mover d[n])
is executed. Note that mover is what gets moved to
d[n]; this argument is naturally absent from $setv
and $miss.
$miss ($miss r1 r2 r3 r4 r5 r6 r7 r8 r9 r10) -> no return
value. Compares ($verb) to VECVERB as $hit does.
When a match to the nth entry in VECVERB is found,
routine r[n] is called. An attempt to call routine
0 does nothing.
6.7. String Functions
There are two varieties of strings. Constant strings
defined by the DDL programmer are permanent, and have a
numeric "value" greater than zero (which is in fact a table
index). Strings typed by the Player as a direct object, and
strings produced by the functions $eqst and $read are tem-
porary, have a numeric "value" less than zero (which allows
the programmer to determine if the direct object is in fact
a string), and are purged by having their index values recy-
cled at the beginning of every turn. No more than 200 such
strings may be generated on a given turn.
$eqst ($eqst arg1 arg2) )-> 1 iff the strings specified by
the two args are equal, zero otherwise.
$subs ($subs str index length) )-> a string consisting of
the substring of str, starting at character index
(with an origin of Zero for the beginning of the
string), for the specified length. A length of zero
causes all the remaining characters starting at
index to be taken.
$leng ($leng str) )-> The length of string str.
$read ($read) )-> Causes DDL to pause and wait for input
from the Player. Returns the string the player
typed, without the trailing newline.
6.8. Demons and Fuses
$sdem ($sdem n) -> Activates routine n as a Demon, to be
executed every turn. At least one such Demon should
exist, to Look at the Player's current location, and
to increment the turn counter
$ddem ($ddem n) -> Removes routine n from the active Demon
list. For example, ($ddem Kount) undoes the action
of ($sdem Kount).
$sfus ($sfus rout n) -> Causes routine "rout" to be exe-
cuted (one time only) after n turns. Such a routine
is called a Fuse.
$dfus ($dfus rout) -> Causes routine rout to be taken off
the pending fuse list.
$itun ($itun) -> Increments the turn counter. This is a
builtin function because fuses depend upon the turn
counter. The DDL programmer has the option to "slow
time" by refraining from incrementing the turn
counter.
$gtun ($gtun) -> Returns the current turn counter value.