|
|
1.1 ! root 1: .RS ! 2: .ds CF "\(co 1981 UCLA Computer Club ! 3: .TL ! 4: A Brief Description of UCLA ! 5: Dungeon Definition Language (DDL) ! 6: .AU ! 7: Bruce Adler ! 8: Chris Kostanick ! 9: Michael Stein ! 10: Michael Urban ! 11: .AI ! 12: University of California ! 13: Los Angeles, CA 90024 ! 14: .AB ! 15: This document describes Dungeon Definition Language, a meta-adventure ! 16: specification language. It is designed primarily for the programmer ! 17: who wishes to create a ! 18: \s-2DDL\s+2 ! 19: "world", and secondarily for the programmer ! 20: attempting to implement ! 21: \s-2DDL\s+2 ! 22: on a new host machine. ! 23: .AE ! 24: .bp 1 ! 25: .ds CF "\(co 1981 UCLA Computer Club ! 26: .NH ! 27: Introduction. ! 28: .PP ! 29: \s-2DDL\s+2 ! 30: is a system of notation for the specification of "worlds". Using ! 31: \s-2DDL\s+2, ! 32: a programmer may create Objects, Verbs to act upon those objects, ! 33: and Routines to describe the behavior of Objects and Verbs. The user ! 34: of a ! 35: \s-2DDL\s+2 ! 36: program, known as the Player, types these verbs and the names of ! 37: objects to manipulate those objects at a high level. Thus, a Player's ! 38: dialogue with a ! 39: \s-2DDL\s+2 ! 40: program will appear something like: ! 41: .IP ! 42: .DS ! 43: .SM ! 44: ! 45: You are standing outside the north entrance of a large ! 46: brick building. Inscribed above the doorway, appear the ! 47: text: 'AARDVARK'S MUSEUM -- GATEWAY TO ADVENTURELAND'. ! 48: There is a coil of rope here. ! 49: There is a shovel here. ! 50: There is a carbide-flame lamp here. ! 51: There is a copy of a newspaper here. ! 52: >take rope ! 53: OK ! 54: >south ! 55: You are in a large rotunda of an old museum. Doors lead ! 56: to the north, south, east, and west, and a narrow stairway ! 57: in the north-east corner of the room leads down. ! 58: There is a ball-point pen here. ! 59: There is a slip of paper here. ! 60: >take paper ! 61: OK ! 62: >take pen ! 63: OK ! 64: >e ! 65: You are in a dimly lit room containing an empty display case. ! 66: A portion of a vandalized sign above the case reads: ! 67: 'ARTIFACTS OF ANCIENT INDIA -- Several of these items, ! 68: including the sacred rhinoceros horn, the deadly ...'. ! 69: The rest of the sign is unreadable. ! 70: To the west, you can look through a large door into the rotunda ! 71: of the museum. On the east wall of the hall there is an outline ! 72: of an arch. ! 73: >sign paper ! 74: In a blinding flash of light, a stone archway appears in the east wall! ! 75: .NL ! 76: .DE ! 77: .PP ! 78: This sort of behavior will be familiar to users of the celebrated programs, ! 79: .I "Adventure" ! 80: and ! 81: .I "Dungeon" ! 82: (AKA ! 83: .I "Zork" ! 84: ), of Crowther, Woods, Anderson ! 85: and Blank. ! 86: While not as sophisticated in many ways as some of these programs, ! 87: the primary function of ! 88: \s-2DDL\s+2 ! 89: is to allow a number of interesting ! 90: puzzles and games to be exchanged among users of disparate machines ! 91: with a minimum of portability problem. ! 92: .NH ! 93: General Flow of Execution. ! 94: .PP ! 95: When the ! 96: \s-2DDL\s+2 ! 97: program begins execution, a special routine which has been ! 98: coded by the ! 99: \s-2DDL\s+2 ! 100: programmer is executed. This routine must be given the ! 101: name START. START will normally initialize demons and set certain initial ! 102: values. Execution then proceeds in the cyclic fashion described below. ! 103: .PP ! 104: When a ! 105: \s-2DDL\s+2 ! 106: scenario is running, ! 107: execution proceeds in a series of cycles known as "turns". On ! 108: each turn, a number of actions takes place. ! 109: .IP "(1) Demons: " 10 ! 110: Each of the Demon routines currently active is run in order ! 111: of activation. ! 112: Demon routines are specified and activated by the ! 113: \s-2DDL\s+2 ! 114: program by executing ! 115: the $sdem function. ! 116: .B Note: ! 117: The normal action of Looking (executing description routines) which ! 118: one expects to occur on each turn must be coded by the ! 119: \s-2DDL\s+2 ! 120: programmer ! 121: as a Demon. ! 122: .IP "(2) Fuses: " 10 ! 123: All active Fuse routines are checked to see if they ! 124: are to be executed on this turn. Those Fuses which have thus "burned down" ! 125: are then executed (in reverse order of activation) and removed. ! 126: .IP "(3) Parse: " 10 ! 127: The player types a line of input, ! 128: and an attempt is made to resolve that input into a Verb, an Indirect Object, ! 129: and a Direct Object, by means of attendant Prepositions, Articles, ! 130: and Adjectives. Unambiguous abbreviations for words are recognized ! 131: by the parser. ! 132: If an input Noun is ambiguous (because of two objects distinguished by only ! 133: adjectives), ! 134: \s-2DDL\s+2 ! 135: routines called DWIMD and DWIMI are used to disambiguate ! 136: direct and indirect objects respectively. DWIMD and DWIMI each return ! 137: nonzero if the direct or indirect object is "possibly the one he means" ! 138: (e.g. if it is in the room, etc)); only if exactly one such object ! 139: exists with the given Noun name can the parse complete successfuly. ! 140: any of the input components are found to be missing, the value zero is ! 141: assumed for that object (and no associated routines are executed). ! 142: .PP ! 143: If a syntax error or unknown word is detected, a hopefully informative ! 144: error message is printed. In addition, unknown words encountered ! 145: in the input ! 146: may be saved in a file for perusal by the DDL programmer. ! 147: .PP ! 148: The direct object may be enclosed in double-quotes by the Player. ! 149: Such a direct object is returned as a String to the program. Strings ! 150: may be detected by the program as having "numeric values" less than ! 151: zero. Strings may be operated on with the $eqst, $subs, and $leng ! 152: functions, and the $say procedure. ! 153: .IP "(4) Pre-action: " 10 ! 154: The PREACT routine (if any) ! 155: that the ! 156: \s-2DDL\s+2 ! 157: programmer has associated ! 158: with the input Verb is executed. These routines typically will check ! 159: for the availability of the object in question, and so on. ! 160: .IP "(5) Indirect Object: " 10 ! 161: The ACTION routine associated with the Indirect Object ! 162: that the Player typed (if any) is executed. ! 163: .IP "(6) Direct Object: " 10 ! 164: The ACTION routine associated with the Direct Object ! 165: that the Player typed (if any) is executed. ! 166: For most specialized actions (like "rub lamp") the particular code ! 167: is frequently attached to the object. ! 168: If the Direct Object is a String, the ACTION routine (if any) ! 169: associated with the object STRING (if such is defined by the ! 170: programmer) is executed. ! 171: .IP "(7) Room Action: " 10 ! 172: The ACTION routine associated with the room the Player is ! 173: in (actually, the LOC of .ME) is executed. Normally, this will be ! 174: a "transition" routine which will check if the verb is "north", and so on. ! 175: .B Note: ! 176: This is the ONLY aspect of "built-in" action which depends in ANY ! 177: WAY upon the actual state of variables within the "dungeon" itself. ! 178: .IP "(8) Verb: " 10 ! 179: The ACTION routine associated with the input Verb (if any) ! 180: is executed. ACTION routines for most Verbs will often be ! 181: default routines. For example the Action routine for the Verb "rub" ! 182: might print "Rubbing that object is not useful." ! 183: .LP ! 184: If any of these routines terminates with an ($exit 1), the remainder of ! 185: the current turn is skipped. Furthermore, the ! 186: \s-2DDL\s+2 ! 187: programmer is responsible ! 188: for incrementing the Turn Counter (normally in a Demon routine) if Fuses ! 189: are to be used. ! 190: .NH ! 191: Data types. ! 192: .NH 2 ! 193: Objects. ! 194: .PP ! 195: Player machinations are in terms of Objects. All Objects are nodes in ! 196: a tree, the root node of which is labelled ".ALL". A second special ! 197: object, ".ME" is considered to represent the Player. Objects will ! 198: normally be treated either as rooms or portable-type objects, but ! 199: \s-2DDL\s+2 ! 200: itself ! 201: does not distinguish these functions; all objects are stored and treated ! 202: uniformly. It is therefore possible, in principal, to write a ! 203: \s-2DDL\s+2 ! 204: scenario in which the Player may pick up a room, carry it, and ! 205: later enter it. Each object possesses the following attributes. If ! 206: any of these is not specified, it is given the default value of zero. ! 207: .IP "LOC: " 6 ! 208: The object ID of the parent (location) of the object. ! 209: .IP "CONT: " 6 ! 210: The object ID of the first child (contents) of the object. ! 211: .IP "LINK: " 6 ! 212: The object ID of the next sibling (others in the same place) of the ! 213: object ! 214: .IP "ADJ: " 6 ! 215: The Adjective ID which uniquely distinguishes this object from others ! 216: of the same name (if any). ! 217: .IP "OTHERS: " 6 ! 218: The Object ID of another object with the same name as this object, ! 219: though with a different adjective. ! 220: .IP "NAME: " 6 ! 221: The unqualified Noun by which the Player names the object. ! 222: .IP "PROPS: " 6 ! 223: Up to ! 224: 25 ! 225: numeric values can be arbitrarily associated with an object by the ! 226: \s-2DDL\s+2 ! 227: programmer. Properties ! 228: 1-16 ! 229: may only possess the values 0 or 1. The others may range in value from ! 230: -32768 to +32767. ! 231: The last three of these properties have special usages. Their indices ! 232: are predefined by the compiler. ! 233: .IP "LDESC (23)" 6 ! 234: The Routine ID of a "Long Description" routine ! 235: .IP "SDESC (24)" 6 ! 236: The Routine ID of a "Short Description" routine ! 237: .IP "ACTION (25)" 6 ! 238: The Routine ID of a "Action" routine, to be called if the Player ! 239: either attempts to do something with that object (specifies it as a ! 240: Direct or Indirect Object), or while inside that object. ! 241: .NH 2 ! 242: Verbs. ! 243: .PP ! 244: The "commands" typed by the Player must name Verbs which have been ! 245: defined by the ! 246: \s-2DDL\s+2 ! 247: programmer. Each Verb is associated with two Routine ! 248: ID's: ! 249: .IP "PREACT: " 6 ! 250: The Routine ID of a routine to execute when the verb has been ! 251: recognized and the remaining input identified, but before any "Action" ! 252: routines associated with the Objects in that input have been executed. ! 253: For example, the PREACT routine of "take" might check to see if ! 254: the direct object is in the room. ! 255: .IP "ACTION: " 6 ! 256: The Routine ID of a routine to execute after all input object action ! 257: routines have been called. ! 258: Our experience has been that such routines end up being "default" routines ! 259: that typically only say things like "Rubbing that object does nothing." ! 260: .NH 2 ! 261: Strings. ! 262: .PP ! 263: Simple strings may be defined by the ! 264: \s-2DDL\s+2 ! 265: programmer to be printed. Strings ! 266: may be up to 255 bytes in length, delimited by double-quote marks. ! 267: Carriage returns may be embedded in strings freely, or the sequence \\n ! 268: may be used to represent a carriage return at any point. ! 269: .NH 2 ! 270: Numbers. ! 271: .PP ! 272: \s-2DDL\s+2 ! 273: programers may only specify nonnegative integers up to 32767. ! 274: However, a routine may compute any integer value from -32768 to +32767. ! 275: .NH 2 ! 276: Adjectives. ! 277: .PP ! 278: Adjectives possess no data, but are uniquely numbered by the ! 279: \s-2DDL\s+2 ! 280: compiler ! 281: so as to have unique internal IDs (which begin at the value 1). ! 282: Adjectives are normally only used to distinguish various objects which ! 283: have the same Noun name (eg the "red book" and the "blue book"). ! 284: .NH 2 ! 285: Routines ! 286: .PP ! 287: Routines represent the actual logical behavior of the Dungeon. A routine ! 288: consists of one or more calls to builtin or user-defined functions. ! 289: Internally, a routine may be stored as an interpretive program for a ! 290: very simple stack machine. The internal representation is up to the ! 291: implementer. ! 292: Routines may call one another, and a single ! 293: routine may call itself recursively. ! 294: .NH 2 ! 295: Globals ! 296: .PP ! 297: 50 ! 298: globals (numbered ! 299: 0-49) ! 300: are available to the ! 301: \s-2DDL\s+2 ! 302: programmer and may contain any integer value. They are named by ! 303: numeric constants. Such constants are conveniently assigned ! 304: symbolic names by means of the VAR declaration described below. ! 305: The last three globals are set each turn to contain the Indirect ! 306: Object, Direct Object, and Verb typed by the player. The constants ! 307: Iobj, Dobj, and Verb are predefined by the compiler to refer to those ! 308: globals. ! 309: .NH ! 310: \s-2DDL\s+2 ! 311: Programs ! 312: .PP ! 313: .B Note: ! 314: In the syntactic descriptions below, metavariables such as ! 315: .I varname ! 316: refer to user-defined identifiers. These identifiers consist ! 317: of a string of alphameric characters of arbitrary length. ! 318: A ! 319: \s-2DDL\s+2 ! 320: specification consists of one or more ! 321: \s-2DDL\s+2 ! 322: statements, each terminated ! 323: by a semicolon. The following statements exist: ! 324: .sp ! 325: .IP "VAR \fIvarname, varname\fR,..." 8 ! 326: .PP ! 327: Declares each ! 328: .I varname ! 329: as a new symbol. The symbol ! 330: is defined as a constant with a value different from each ! 331: previously declared <varname>. <varname> must not ! 332: be previously declared. ! 333: .PP ! 334: .B "Example: " ! 335: VAR strength, intell, wisdom; ! 336: .sp ! 337: .IP "VERB \fIverbname, verbname\fR,..." 8 ! 338: .PP ! 339: Declares each ! 340: .I verbname ! 341: as a new verb. ! 342: .I verbname ! 343: must ! 344: not be previously assigned. ! 345: .PP ! 346: .B "Example: " ! 347: VERB north,south,east,west; ! 348: .sp ! 349: .IP "ADJEC \fIadjectivename, adjectivename\fR,..." 8 ! 350: .PP ! 351: Creates a new adjective with name ! 352: .I adjectivename, ! 353: which must not be previously assigned. ! 354: .PP ! 355: .B Example: ! 356: ADJEC red,green,blue; ! 357: .sp ! 358: .IP "NOUN \fInoun\fR[(\fIcontainer\fR)]" 8 ! 359: .PP ! 360: Creates a new object named ! 361: .I noun ! 362: whose ! 363: initial location is ! 364: .I ! 365: container. noun ! 366: .R ! 367: may not ! 368: be previously assigned; ! 369: .I container ! 370: must be of ! 371: type NOUN. If the (\fIcontainer\fR) clause is omitted, ! 372: the new object is placed in object .ALL . ! 373: the ! 374: .I noun ! 375: may actually be a adjective-noun pair. ! 376: .PP ! 377: .B Examples: ! 378: .DS ! 379: NOUN red book, blue book; ! 380: NOUN worm(red book); ! 381: .DE ! 382: .sp ! 383: .IP "ROUTINE \fIroutinename, routinename, ...\fR" 8 ! 384: Declares that the \fIroutinename\fRs listed will be used ! 385: for Routines later in the program. This is to allow \s-2DDL\s+2, ! 386: which is intended to be easily implementable, to deal with ! 387: recursive routines (which have not yet been declared at the ! 388: time of their definitions). Only routines which are used ! 389: before being defined need to be declared with this statement. ! 390: .sp ! 391: .IP "ARTICLE \fIarticle, article,\fR..." 8 ! 392: .PP ! 393: Creates each \fIarticle\fR as an article. Articles are recognized ! 394: by the run-time parser, but are basically "noise" words. ! 395: .PP ! 396: .B Example: ! 397: ARTICLE the; ! 398: .IP "PREP \fIprep, prep\fR,..." 8 ! 399: .PP ! 400: Creates each ! 401: .I prep ! 402: as a preposition. Prepositions are basically ! 403: noise words, but are used by the parser to recognize the presence of ! 404: indirect objects in the Player's input. ! 405: .PP ! 406: .B Example: ! 407: PREP into,on,using,to,at; ! 408: .sp ! 409: .IP "\fInoun\fR (\fInumexp\fR) = \fIexp2\fR" 8 ! 410: .PP ! 411: Property \fInumexp\fR of \fInoun\fR is set to the ! 412: value of \fIexp2\fR. ! 413: .I exp2 ! 414: may be a number, a string, a routine name, or a new routine; ! 415: the numeric value or ID of ! 416: .I exp2 ! 417: is always placed into the specified property. ! 418: .PP ! 419: .B Examples: ! 420: .DS ! 421: gem(11)=0; { 11 == Luminous } ! 422: gem(LDESC) = ($say "There is a bright gem here!"); ! 423: gem(SDESC) = ($say "a bright gem"); ! 424: gem(ACTION) = GmAct; ! 425: .DE ! 426: .sp ! 427: .IP "\fIverb\fR (PREACT | ACTION) = \fIroutine\fR" 8 ! 428: .PP ! 429: Assigns \fIroutine\fR as the pre-object action or default action of ! 430: the given \fIverb\fR. The routine may be a predefined routine name or ! 431: an actual routine. ! 432: .PP ! 433: .B Example: ! 434: .DS ! 435: rub(ACTION) = ($say "Rubbing ") ! 436: ($sdisc ($dobj)) ! 437: ($say " seems silly.\\n"); ! 438: .DE ! 439: .sp ! 440: .IP "\fIname\fR = \fInumber\fR" 8 ! 441: .PP ! 442: Assigns \fIname\fR as equivalent to \fInumber\fR. \fIname\fR ! 443: must not be previously assigned. ! 444: .PP ! 445: .B Example: ! 446: OPEN=11; TRUE=1; ! 447: .IP "\fIname1\fR = \fIname2\fR" 8 ! 448: .PP ! 449: Assigns ! 450: .I name1 ! 451: as a synonym for ! 452: .I name2. ! 453: .PP ! 454: .B Example: ! 455: n=north;s=south;se=southeast; ! 456: .IP "(\fInumexp\fR) = \fInumexp2\fR" 8 ! 457: .PP ! 458: Assigns the global (or VAR) named by \fInumexp\fR to the value ! 459: given by \fInumexp2\fR. ! 460: .PP ! 461: .B Example: ! 462: (Maxpt)=450; ! 463: .IP "\fIname\fR = " ! 464: "\fIstring\fR" ! 465: .PP ! 466: Assigns ! 467: .I name ! 468: as equivalent to "\fIstring\fR". ! 469: .B Note: ! 470: This seems to be rarely, if ever, used. Usually it's just ! 471: as easy to assign a routine to Say the given string. ! 472: However, there are other string functions, such as $eqst ! 473: and $substr, for which it may be useful to predefine strings. ! 474: .PP ! 475: .B Example: ! 476: err="Nothing happens.\\n"; ! 477: MagicWord = "ShaZam"; ! 478: .IP "\fIname\fR = \fIroutine\fR" 8 ! 479: .PP ! 480: Assigns ! 481: .I name ! 482: as equivalent to ! 483: .I routine ! 484: .PP ! 485: .B Example: ! 486: sayer=($say "Nothing happens.\\n"); ! 487: .IP "INCLUDE ""\fIfilename\fR""" 8 ! 488: .PP ! 489: .B ! 490: (\s-2UNIX\s+2 implementation only) ! 491: .R ! 492: Causes input to be read from the named file. ! 493: .RE ! 494: .NH ! 495: Routines ! 496: .PP ! 497: A routine is a list of one or more "forms". Forms are of three types: ! 498: .RS ! 499: .IP "(\fIform1\fB : \fIform, form\fR ... [: \fIelseform, elseform\fR ...])" 8 ! 500: .PP ! 501: Conditional expression. If ! 502: .I form1 ! 503: evaluates to ! 504: nonzero, the subsequent \fIform\fRs are executed in ! 505: sequence. Otherwise, the list of \fIelseform\fRs is executed in sequence. ! 506: .B Note: ! 507: The second colon, and the subsequent \fIelseform\fRs, are optional. ! 508: .PP ! 509: .B Example: ! 510: .PP ! 511: .DS ! 512: (TRUE : ($say "Always do me") : ($say "Never do me")) ! 513: .DE ! 514: .IP "(WHILE \fIform1\fR : \fIform, form ... \fR)" 8 ! 515: .PP ! 516: Simple looping construct. If \fIform1\fR evaluates ! 517: to nonzero, the subsequent \fIform\fRs are evaluated ! 518: in sequence. This process is repeated until such ! 519: a time as \fIform1\fR is found to evaluate to zero. ! 520: .PP ! 521: .B Example: ! 522: .PP ! 523: .DS ! 524: (WHILE ($eq ($loc .ME) JewlRoom) : (TRYmv .ME Prison)) ! 525: .DE ! 526: .IP "(\fIfunction arg1 arg2\fR ...)" 8 ! 527: .PP ! 528: Function call (note that all builtin functions ! 529: begin with the character $). The \fIfunction\fR is applied ! 530: to the \fIarg\fRs. An argument may be a number, ! 531: string, declared name, or another form. However, the function must ! 532: be a simple identifier, or a form which evaluates to a function ! 533: identifier ( ! 534: .I ! 535: e.g. ! 536: .R ! 537: ($ldisc xxx)). ! 538: In addition, three special argument types are recognized: ! 539: .PP ! 540: An argument such as "@\fInumber\fR" is interpreted as ! 541: "contents of global \fInumber\fR". ! 542: .PP ! 543: An argument such as "%\fInumber\R" is interpreted as "the value of the \fInumber\R ! 544: argument to this function". ! 545: .PP ! 546: An argument such as "[\fIadj noun\fR]" must be used if the programmer wishes to ! 547: refer to an object with an associated adjective. ! 548: .RE ! 549: .PP ! 550: .B Examples: ! 551: .DS ! 552: .SM ! 553: VERB north,south,east,west,ne,nw,se,sw,up,down; ! 554: n=north; s=south; e=east; w=west; u=up; d=down; ! 555: ! 556: NOUN rm001,rm002,rm003,rm004,rm005,rm006; ! 557: NOUN .ME(rm001); ! 558: ! 559: ADJECTIVE red,blue; ! 560: NOUN red ball(rm002),blue ball(rm003); ! 561: ! 562: red ball(LDESC) = ($say "There is a red ball here."); ! 563: red ball(SDESC) = ($say "Red ball."); ! 564: ! 565: VAR score; ! 566: (score) = 0; ! 567: ! 568: TAKBT = 16; ! 569: TRUE = 1; FALSE=0; ! 570: red ball(TAKBT) = TRUE; ! 571: ! 572: ROUTINE takeR; { Declared later } ! 573: ! 574: VERB take; ! 575: take(ACTION) = ( ($and ($prop ($dobj) TAKBT) ! 576: ($eq ($loc .ME)($loc ($dobj)))): ! 577: (takeR ($dobj)) ! 578: ); ! 579: takeR = ($move %1 .ME) ! 580: (($eq %1 [red ball]): ! 581: ($say "The ball is glowing!") ! 582: ($setg score ($plus 10 @score))); ! 583: .NL ! 584: .DE
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.