|
|
1.1 ! root 1: .RS ! 2: .ds CF "\(co 1982 UCLA Computer Club ! 3: .TL ! 4: A Brief Description of UCLA ! 5: Dungeon Definition Language (DDL) ! 6: (Second Edition) ! 7: .AU ! 8: Bruce Adler ! 9: Chris Kostanick ! 10: Michael Stein ! 11: Michael Urban ! 12: .AI ! 13: University of California ! 14: Los Angeles, CA 90024 ! 15: .AB ! 16: This document describes Dungeon Definition Language, a meta-adventure ! 17: specification language. It is designed primarily for the programmer ! 18: who wishes to create a ! 19: \s-2DDL\s+2 ! 20: "world", and secondarily for the programmer ! 21: attempting to implement ! 22: \s-2DDL\s+2 ! 23: on a new host machine. ! 24: .AE ! 25: .bp 1 ! 26: .ds CF "\(co 1982 UCLA Computer Club ! 27: .NH ! 28: Introduction. ! 29: .PP ! 30: \s-2DDL\s+2 ! 31: is a system of notation for the specification of "worlds". Using ! 32: \s-2DDL\s+2, ! 33: a programmer may create Objects, Verbs to act upon those objects, ! 34: and Routines to describe the behavior of Objects and Verbs. The user ! 35: of a ! 36: \s-2DDL\s+2 ! 37: program, known as the Player, types these verbs and the names of ! 38: objects to manipulate those objects at a high level. Thus, a Player's ! 39: dialogue with a ! 40: \s-2DDL\s+2 ! 41: program will appear something like: ! 42: .IP ! 43: .DS ! 44: .SM ! 45: ! 46: You are standing outside the north entrance of a large ! 47: brick building. Inscribed above the doorway, appear the ! 48: text: 'AARDVARK'S MUSEUM -- GATEWAY TO ADVENTURELAND'. ! 49: There is a coil of rope here. ! 50: There is a shovel here. ! 51: There is a carbide-flame lamp here. ! 52: There is a copy of a newspaper here. ! 53: >take rope ! 54: OK ! 55: >south ! 56: You are in a large rotunda of an old museum. Doors lead ! 57: to the north, south, east, and west, and a narrow stairway ! 58: in the north-east corner of the room leads down. ! 59: There is a ball-point pen here. ! 60: There is a slip of paper here. ! 61: >take paper ! 62: OK ! 63: >take pen ! 64: OK ! 65: >e ! 66: You are in a dimly lit room containing an empty display case. ! 67: A portion of a vandalized sign above the case reads: ! 68: 'ARTIFACTS OF ANCIENT INDIA -- Several of these items, ! 69: including the sacred rhinoceros horn, the deadly ...'. ! 70: The rest of the sign is unreadable. ! 71: To the west, you can look through a large door into the rotunda ! 72: of the museum. On the east wall of the hall there is an outline ! 73: of an arch. ! 74: >sign paper ! 75: In a blinding flash of light, a stone archway appears in the east wall! ! 76: .NL ! 77: .DE ! 78: .PP ! 79: This sort of behavior will be familiar to users of the celebrated programs, ! 80: .I "Adventure" ! 81: and ! 82: .I "Dungeon" ! 83: (AKA ! 84: .I "Zork" ! 85: ), of Crowther, Woods, Anderson ! 86: and Blank. ! 87: While not as sophisticated in many ways as some of these programs, ! 88: the primary function of ! 89: \s-2DDL\s+2 ! 90: is to allow a number of interesting ! 91: puzzles and games to be exchanged among users of disparate machines ! 92: with a minimum of portability problem. ! 93: .NH ! 94: Processor Structure ! 95: .PP ! 96: \s-2DDL\s+2 consists of two processors. The first, ! 97: .I ddlcomp, ! 98: reads a program in the \s-2DDL\s+2 language, analyzes it, ! 99: notes syntax errors, and produces a data file representing ! 100: the game described by the program. The second, ! 101: .I ddlrun, ! 102: takes one such data file as input and presents a Player with ! 103: the scenario represented by that file. ! 104: .NH ! 105: General Constructs ! 106: .PP ! 107: A \s-2DDL\s+2 program will consist of a series of declarations. ! 108: Some declarations will define properties of Objects and Verbs; ! 109: others will define Routines to be executed at various stages ! 110: of play. These routines are roughly similar to \s-2LISP\s+2 ! 111: functions in that they consist of a series of functional ! 112: expressions. Certain identifiers, such as DWIMI and START, ! 113: are expected to be defined as routines by the programmer, ! 114: and have special meaning to the processor. ! 115: .NH ! 116: General Flow of Execution. ! 117: .PP ! 118: When the ! 119: \s-2DDL\s+2 ! 120: program begins execution, a special routine which has been ! 121: coded by the ! 122: \s-2DDL\s+2 ! 123: programmer is executed. This routine must be given the ! 124: name START. START will normally initialize demons and set certain initial ! 125: values. Execution then proceeds in the cyclic fashion described below. ! 126: .PP ! 127: When a ! 128: \s-2DDL\s+2 ! 129: scenario is running, ! 130: execution proceeds in a series of cycles known as "turns". On ! 131: each turn, a number of actions takes place. ! 132: .IP "(1) Demons: " 10 ! 133: Each of the currently active Demon routines ! 134: (routines set up to do some work on each turn) ! 135: is run in order ! 136: of activation. ! 137: Demon routines are specified and activated by a ! 138: \s-2DDL\s+2 ! 139: program through ! 140: the ! 141: .I $sdem ! 142: function. ! 143: .B Note: ! 144: The normal action of Looking (executing description routines) which ! 145: one expects to occur on each turn must be coded by the ! 146: \s-2DDL\s+2 ! 147: programmer ! 148: as a Demon. ! 149: .IP "(2) Fuses: " 10 ! 150: All active Fuse routines are checked to see if they ! 151: are to be executed on this turn. Those Fuses which have thus "burned down" ! 152: are then executed (in reverse order of activation) and removed from the ! 153: Fuse list. ! 154: .IP "(3) Parse: " 10 ! 155: The player types a line of input, ! 156: and an attempt is made to resolve that input into a Verb, an Indirect Object, ! 157: and a Direct Object, by means of attendant Prepositions, Articles, ! 158: and Adjectives. Unambiguous abbreviations for words are recognized ! 159: by the parser. ! 160: ! 161: If an input Noun is ambiguous (for example, if the user says ! 162: "take book" when "red book" and "blue book" have both been ! 163: \fIdefined\fR), ! 164: \s-2DDL\s+2 ! 165: routines called DWIMD and DWIMI are used to disambiguate ! 166: direct and indirect objects respectively. DWIMD and DWIMI, ! 167: which must be defined by the \s-2DDL\s+2 programmer, should return ! 168: nonzero if the direct or indirect object is "possibly the one he means" ! 169: (e.g. if it is in the room, etc); only if exactly one such object ! 170: exists with the given Noun name can the parse complete successfuly. ! 171: If ! 172: any of the input components is found to be missing, the value zero is ! 173: assumed for that object (and no associated routines are executed). ! 174: ! 175: If a syntax error or unknown word is detected, a hopefully informative ! 176: error message is printed. In addition, unknown words encountered ! 177: in the input ! 178: may be saved in a file for perusal by the DDL programmer. ! 179: ! 180: The direct object may be enclosed in double-quotes by the Player. ! 181: Such a direct object is returned as a String to the program. Strings ! 182: may be detected by the program as having "numeric values" less than ! 183: zero. Strings may be operated on with the ! 184: .I $eqst, ! 185: .I $subs, ! 186: and ! 187: .I $leng ! 188: functions, and the ! 189: .I $say ! 190: procedure. ! 191: .IP "(4) Pre-action: " 10 ! 192: The PREACT routine (if any) ! 193: that the ! 194: \s-2DDL\s+2 ! 195: programmer has associated ! 196: with the input Verb is executed. These routines typically will check ! 197: for the availability of the object in question, and so on. ! 198: .IP "(5) Indirect Object: " 10 ! 199: The ACTION routine associated with the Indirect Object ! 200: that the Player typed (if any) is executed. ! 201: .IP "(6) Direct Object: " 10 ! 202: The ACTION routine associated with the Direct Object ! 203: that the Player typed (if any) is executed. ! 204: For many specialized actions (like "rub lamp") the particular code ! 205: is best attached to the object. ! 206: If the Direct Object is a String, the ACTION routine (if any) ! 207: associated with the object STRING (if such is defined by the ! 208: programmer) is executed. ! 209: .IP "(7) Room Action: " 10 ! 210: The ACTION routine associated with the room the Player is ! 211: in (actually, the LOC of .ME) is executed. Normally, this will be ! 212: a "transition" routine which will check if the verb is "north", and so on. ! 213: .B Note: ! 214: This is the ONLY aspect of "built-in" action which depends in ANY ! 215: WAY upon the actual state of variables within the "dungeon" itself. ! 216: .IP "(8) Verb: " 10 ! 217: The ACTION routine associated with the input Verb (if any) ! 218: is executed. ACTION routines for most Verbs will often be ! 219: default routines. For example the Action routine for the Verb "rub" ! 220: might print "Rubbing that object is not useful." ! 221: .LP ! 222: If any of these routines terminates with ($exit 1), the remainder of ! 223: the current turn is skipped. Furthermore, the ! 224: \s-2DDL\s+2 ! 225: programmer is responsible ! 226: for incrementing the Turn Counter (normally in a Demon routine) if Fuses ! 227: are to be used. ! 228: .NH ! 229: Data types. ! 230: .NH 2 ! 231: Objects. ! 232: .PP ! 233: Player machinations are in terms of Objects. All Objects are nodes in ! 234: a "containment" tree, the root node of which is labelled ".ALL". ! 235: A second special ! 236: object, ".ME" is considered to represent the Player. Objects will ! 237: normally be treated either as rooms or portable-type objects, but ! 238: \s-2DDL\s+2 ! 239: itself ! 240: does not distinguish these functions; all objects are stored and treated ! 241: uniformly. It is therefore possible, in principal, to write a ! 242: \s-2DDL\s+2 ! 243: scenario in which the Player may pick up a room, carry it, and ! 244: later enter it. Each object possesses the following attributes. If ! 245: any of these is not specified, it is given the default value of zero. ! 246: .IP "LOC: " 6 ! 247: The object ID of the parent (location) of the object. ! 248: .IP "CONT: " 6 ! 249: The object ID of the first child (contents) of the object. ! 250: .IP "LINK: " 6 ! 251: The object ID of the next sibling (others in the same place) of the ! 252: object ! 253: .IP "ADJ: " 6 ! 254: The Adjective ID which uniquely distinguishes this object from others ! 255: of the same name (if any). ! 256: .IP "OTHERS: " 6 ! 257: The Object ID of another object with the same name as this object, ! 258: though with a different adjective. The DWIMx routines are called ! 259: for each of the objects in this chain associated with ! 260: an ambiguous direct ! 261: or indirect object. For example, if the player types "take book", ! 262: and both "red book" and "blue book" are defined, DWIMD will be ! 263: called once with "red book" as its parameter, and once with "blue book" ! 264: as its parameter. If the DWIMD is coded correctly for this example, ! 265: DWIMI will return TRUE (nonzero) if and only if the parameter book ! 266: can be taken. If zero or both books satisfy the DWIMD criteria, ! 267: an error message is printed. ! 268: .IP "NAME: " 6 ! 269: The unqualified Noun by which the Player names the object. ! 270: .IP "PROPS: " 6 ! 271: Up to ! 272: 25 ! 273: numeric values can be arbitrarily associated with an object by the ! 274: \s-2DDL\s+2 ! 275: programmer. Properties ! 276: 1-16 ! 277: may only possess the values 0 or 1. The others may range in value from ! 278: -32768 to +32767. ! 279: The last three of these properties have special usages. Their indices ! 280: are predefined by the compiler. ! 281: .RS ! 282: .IP "LDESC (23)" 6 ! 283: The Routine ID of a "Long Description" routine ! 284: .IP "SDESC (24)" 6 ! 285: The Routine ID of a "Short Description" routine ! 286: .IP "ACTION (25)" 6 ! 287: The Routine ID of a "Action" routine, to be called if the Player ! 288: either attempts to do something with that object (specifies it as a ! 289: Direct or Indirect Object), or while inside that object. ! 290: .RE ! 291: .NH 2 ! 292: Verbs. ! 293: .PP ! 294: Each "command" typed by the Player must begin with a Verb which ! 295: has been ! 296: defined by the ! 297: \s-2DDL\s+2 ! 298: programmer. Each Verb has two Routines associated with it: ! 299: .IP "PREACT: " 6 ! 300: The Routine ID of a routine to execute when the verb has been ! 301: recognized and the remaining input identified, but before any "Action" ! 302: routines associated with the Objects in that input have been executed. ! 303: For example, the PREACT routine of "take" might check to see if ! 304: the direct object is in the room. ! 305: .IP "ACTION: " 6 ! 306: The Routine ID of a routine to execute after all input object action ! 307: routines have been called. ! 308: Our experience has been that such routines end up being "default" routines ! 309: that typically only say things like "Rubbing that object does nothing." ! 310: .NH 2 ! 311: Strings. ! 312: .PP ! 313: Simple strings may be defined by the ! 314: \s-2DDL\s+2 ! 315: programmer to be printed. Strings ! 316: may be up to 255 bytes in length, delimited by double-quote marks. ! 317: Carriage returns may be embedded in strings freely, or the sequence \en ! 318: may be used to represent a carriage return at any point. ! 319: Additionally, strings may be generated by the ! 320: .I $subs ! 321: and ! 322: .I $read ! 323: functions at run time, or typed by the player ! 324: as a "direct object." ! 325: .NH 2 ! 326: Numbers. ! 327: .PP ! 328: \s-2DDL\s+2 ! 329: programers may only specify nonnegative integers up to 32767. ! 330: However, a routine may compute any integer value from -32768 to +32767. ! 331: .NH 2 ! 332: Adjectives. ! 333: .PP ! 334: Adjectives possess no data, but are uniquely numbered by the ! 335: \s-2DDL\s+2 ! 336: compiler ! 337: so as to have unique internal IDs (which begin at the value 1). ! 338: Adjectives are normally only used to distinguish various objects which ! 339: have the same Noun name (e.g. the "red book" and the "blue book"). ! 340: .NH 2 ! 341: Routines ! 342: .PP ! 343: Routines represent the actual logical behavior of the Dungeon. A routine ! 344: consists of one or more calls to builtin or user-defined functions. ! 345: Internally, a routine may be stored as an interpretive program for a ! 346: very simple stack machine. The internal representation is up to the ! 347: implementer. ! 348: Routines may call one another, and a single ! 349: routine may call itself recursively. ! 350: .NH 2 ! 351: Globals ! 352: .PP ! 353: 50 ! 354: globals (numbered ! 355: 0-49) ! 356: are available to the ! 357: \s-2DDL\s+2 ! 358: programmer and may contain any integer value. They are named by ! 359: numeric constants. Such constants are conveniently assigned ! 360: symbolic names by means of the VAR declaration described below. ! 361: The last three globals are set each turn to contain the Indirect ! 362: Object, Direct Object, Preposition, ! 363: and Verb typed by the player. The constants ! 364: .I Iobj, ! 365: .I Dobj, ! 366: .I Prep, ! 367: and ! 368: .I Verb ! 369: are predefined by the compiler to refer to those ! 370: globals. ! 371: .B "Implementor's Note:" ! 372: If \s-2DDL\s+2 is implemented on a system that ! 373: does not permit case distinctions, these constants ! 374: should be renamed as ! 375: .I iobj, ! 376: .I dobj, ! 377: .I prepg, ! 378: and ! 379: .I verbg ! 380: to avoid conflict with the ! 381: .I VERB ! 382: and ! 383: .I PREP ! 384: declarations described below. ! 385: .NH ! 386: \s-2DDL\s+2 ! 387: Programs ! 388: .PP ! 389: .B Note: ! 390: In the syntactic descriptions below, metavariables such as ! 391: .I varname ! 392: refer to user-defined identifiers. These identifiers consist ! 393: of an arbitrary-length string of characters. ! 394: These characters may be alphabetic (upper or lower case; case ! 395: is distinguished), numeric, or one of the special characters ! 396: '#', '$', '_', or '.'. ! 397: .PP ! 398: A ! 399: \s-2DDL\s+2 ! 400: specification consists of one or more ! 401: \s-2DDL\s+2 ! 402: statements, each terminated ! 403: by a semicolon. The following statements exist: ! 404: .sp ! 405: .IP "VAR \fIvarname, varname\fR,..." 8 ! 406: .sp ! 407: Declares each ! 408: .I varname ! 409: as a new symbol. The symbol ! 410: is defined as a constant with a value different from each ! 411: previously declared \fIvarname\fR. \fIvarname\fR must not ! 412: be previously declared. ! 413: .PP ! 414: .B "Example: " ! 415: VAR strength, intell, wisdom; ! 416: .sp ! 417: .IP "VERB \fIverbname, verbname\fR,..." 8 ! 418: .sp ! 419: Declares each ! 420: .I verbname ! 421: as a new verb. ! 422: .I verbname ! 423: must ! 424: not be previously assigned. ! 425: .PP ! 426: .B "Example: " ! 427: VERB north, south, east, west; ! 428: .sp ! 429: .IP "ADJECTIVE \fIadjectivename, adjectivename\fR,..." 8 ! 430: .sp ! 431: Creates a new adjective with name ! 432: .I adjectivename, ! 433: which must not be previously assigned. ! 434: .PP ! 435: .B Example: ! 436: ADJECTIVE red, green, blue; ! 437: .sp ! 438: .IP "NOUN \fInoun\fR [(\fIcontainer\fR)]" 8 ! 439: .sp ! 440: Creates a new object named ! 441: .I noun ! 442: whose ! 443: initial location is ! 444: .I ! 445: container. noun ! 446: .R ! 447: may not ! 448: be previously assigned; ! 449: .I container ! 450: must be of ! 451: type NOUN. If the "(\fIcontainer\fR)" clause is omitted, ! 452: the new object is placed in object .ALL . ! 453: The ! 454: .I noun ! 455: may actually be a adjective-noun pair; ! 456: if so, the ! 457: .I adjective ! 458: must have been previously defined. ! 459: .PP ! 460: .B Examples: ! 461: .DS ! 462: NOUN red book, blue book; ! 463: NOUN gem(red book); ! 464: .DE ! 465: .sp ! 466: .IP "ROUTINE \fIroutinename, routinename, ...\fR" 8 ! 467: .sp ! 468: Declares that the \fIroutinename\fRs listed will be used ! 469: for Routines later in the program. This is to allow \s-2DDL\s+2, ! 470: which is intended to be easily implementable, to deal with ! 471: recursive routines (which have not yet been declared at the ! 472: time of their definitions). Only routines which are used ! 473: before being defined need to be declared with this statement. ! 474: .sp ! 475: .IP "ARTICLE \fIarticle, article,\fR..." 8 ! 476: .sp ! 477: Creates each \fIarticle\fR as an article. Articles are recognized ! 478: by the run-time parser, but are basically "noise" words. ! 479: .PP ! 480: .B Example: ! 481: ARTICLE the; ! 482: .IP "PREP \fIprep, prep\fR,..." 8 ! 483: .sp ! 484: Creates each ! 485: .I prep ! 486: as a preposition. Prepositions are basically ! 487: used by the parser to recognize the presence of ! 488: indirect objects in the Player's input. ! 489: However, a global named ! 490: .I Prep ! 491: contains the preposition typed by the player on each turn ! 492: (or zero if none). The DDL program can thus distinguish ! 493: "put red book on shelf" from "put red book in shelf" if ! 494: it is so desired. ! 495: .PP ! 496: .B Example: ! 497: PREP into,on,using,to,at; ! 498: .sp ! 499: .IP "\fInoun\fR (\fInumexp\fR) = \fIexp2\fR" 8 ! 500: .sp ! 501: Property \fInumexp\fR of \fInoun\fR is set to the ! 502: value of \fIexp2\fR. ! 503: .I exp2 ! 504: may be a number, a string, a routine name, or a new routine; ! 505: the numeric value or ID of ! 506: .I exp2 ! 507: is always placed into the specified property. ! 508: .PP ! 509: .B Examples: ! 510: .DS ! 511: gem(11)=1; { 11 == Luminous } ! 512: gem(LDESC) = ($say "There is a bright gem here!"); ! 513: gem(SDESC) = ($say "a bright gem"); ! 514: gem(ACTION) = GemAction; { Earlier-defined routine } ! 515: .DE ! 516: .sp ! 517: .IP "\fIverb\fR (PREACT | ACTION) = \fIroutine\fR" 8 ! 518: .sp ! 519: Assigns \fIroutine\fR as the pre-object action or default action of ! 520: the given \fIverb\fR. The routine may be a predefined routine name or ! 521: an actual routine. ! 522: .PP ! 523: .B Example: ! 524: .DS ! 525: rub(ACTION) = ($say "Rubbing ") ! 526: (($sdesc ($dobj))) ! 527: ($say " seems silly!"); ! 528: .DE ! 529: .sp ! 530: .IP "\fIname\fR = \fInumber\fR" 8 ! 531: .sp ! 532: Assigns \fIname\fR as equivalent to \fInumber\fR. \fIname\fR ! 533: must not be previously assigned. ! 534: .PP ! 535: .B Example: ! 536: OPEN=11; TRUE=1; ! 537: .sp ! 538: .IP "\fIname1\fR = \fIname2\fR" 8 ! 539: .sp ! 540: Assigns ! 541: .I name1 ! 542: as a synonym for ! 543: .I name2. ! 544: .PP ! 545: .B Example: ! 546: n=north;s=south;se=southeast; ! 547: .sp ! 548: .IP "(\fInumexp\fR) = \fInumexp2\fR" 8 ! 549: .sp ! 550: Assigns the global (or VAR) named by \fInumexp\fR to the value ! 551: given by \fInumexp2\fR. ! 552: .PP ! 553: .B Example: ! 554: (Maxpt)=450; ! 555: .IP "\fIname\fR = " ! 556: "\fIstring\fR" ! 557: .sp ! 558: Assigns ! 559: .I name ! 560: as equivalent to "\fIstring\fR". ! 561: Frequently, it is just ! 562: as easy to assign a routine to Say the given string ! 563: as it is to define that string separately. ! 564: However, there are other string functions, such as ! 565: .I $eqst ! 566: and ! 567: .I $substr, ! 568: for which it may be useful to predefine strings. ! 569: .PP ! 570: .B Example: ! 571: .br ! 572: err="Nothing happens.\en"; ! 573: .br ! 574: MagicWord = "ShaZam"; ! 575: .sp ! 576: .IP "\fIname\fR = \fIroutine\fR" 8 ! 577: .sp ! 578: Assigns ! 579: .I name ! 580: as equivalent to ! 581: .I routine ! 582: .PP ! 583: .B Example: ! 584: sayer=($say "Nothing happens.\en"); ! 585: .IP "INCLUDE ""\fIfilename\fR""" 8 ! 586: .sp ! 587: .B ! 588: (\s-2UNIX\s+2 implementation only) ! 589: .R ! 590: Causes input to be read from the named file. ! 591: .RE ! 592: .NH ! 593: Routines ! 594: .PP ! 595: A routine is a list of one or more "forms". Forms are of three types: ! 596: .RS ! 597: .NH 2 ! 598: Conditional Forms ! 599: .IP "(\fIform1\fB : \fIform form\fR ... [: \fIelseform elseform\fR ...])" 8 ! 600: .PP ! 601: If ! 602: .I form1 ! 603: evaluates to ! 604: nonzero, the subsequent \fIform\fRs are executed in ! 605: sequence. Otherwise, the list of \fIelseform\fRs is executed in sequence. ! 606: Note that ! 607: the second colon, and the subsequent \fIelseform\fRs, are optional. ! 608: .PP ! 609: .B Example: ! 610: .PP ! 611: .DS ! 612: (TRUE : ($say "Always do me") : ($say "Never do me")) ! 613: .DE ! 614: .NH 2 ! 615: Simple Looping Forms ! 616: .IP "(WHILE \fIform1\fR : \fIform form ... \fR)" 8 ! 617: .PP ! 618: If \fIform1\fR evaluates ! 619: to nonzero, the subsequent \fIform\fRs are evaluated ! 620: in sequence. This process is repeated until such ! 621: a time as \fIform1\fR is found to evaluate to zero. ! 622: .PP ! 623: .B Example: ! 624: .PP ! 625: .DS ! 626: (WHILE ($eq ($loc .ME) JewlRoom) : (TRYmv .ME Prison)) ! 627: .DE ! 628: .NH 2 ! 629: Basic Function Forms ! 630: .IP "(\fIfunction arg1 arg2\fR ...)" 8 ! 631: .PP ! 632: This is the basic function call (note that all builtin functions ! 633: begin with the character $). The \fIfunction\fR is applied ! 634: to the \fIarg\fRs. An argument may be a number, ! 635: string, declared name, or another form. However, the function must ! 636: be a simple identifier, or a form which evaluates to a function ! 637: identifier ( ! 638: .I ! 639: e.g. ! 640: .R ! 641: ($ldesc xxx)). ! 642: In addition, three special argument types are recognized: ! 643: .PP ! 644: An argument such as "@\fInumber\fR" is interpreted as ! 645: "contents of global \fInumber\fR". ! 646: .PP ! 647: An argument such as "%\fInumber\fR" is interpreted as "the value of the ! 648: \fInumber\fR ! 649: argument to this function". ! 650: .PP ! 651: An argument such as "[\fIadj noun\fR]" must be used if the programmer wishes to ! 652: refer to an object with an associated adjective. ! 653: .RE ! 654: .NH ! 655: Program Comments ! 656: .PP ! 657: Comments may be placed freely anywhere in a DDL program. Comments ! 658: are surrounded by "curly braces" { like these }, but may NOT ! 659: be nested. A single right brace will close any and all open ! 660: comments. ! 661: .NH ! 662: The Parser ! 663: .PP ! 664: The \s-2DDL\s+2 run-time parser is the Player's only ! 665: interface to the world created by the \s-2DDL\s+2 ! 666: programmer. The parser recognizes four basic ! 667: forms of input "sentence": ! 668: .DS ! 669: VERB (e.g. "inventory") ! 670: VERB DIRECT-OBJECT (e.g. "take rock") ! 671: VERB DIRECT-OBJECT PREP INDIRECT-OBJECT ! 672: (e.g. "plant flower in vase") ! 673: VERB INDIRECT-OBJECT DIRECT-OBJECT ! 674: (e.g. "give the troll the red blanket" ! 675: or "Turn the lamp off" where "off" is an object) ! 676: .DE ! 677: .PP ! 678: Either a direct or indirect object may consist of ! 679: a simple noun, an adjective-noun pair, or either ! 680: type of noun phrase preceded by an article. Additionally, ! 681: a direct object may be a string delimited by double-quotes. ! 682: The parser attempts to resolve all ambiguous noun references, ! 683: and then sets up the globals, ! 684: .I Dobj, ! 685: .I Iobj, ! 686: .I Prep, ! 687: and ! 688: .I Verb ! 689: with the symbol-table values associated with the appropriate ! 690: verb or object. For an object this is an index into the ! 691: Object Table; for a verb it is an index into the Verb table. ! 692: A string typed as a direct object will be stored as an index ! 693: into an internal temporary-string table, but its value ! 694: will be negated so that the programmer can detect that a ! 695: string has been typed, knowing that all strings (and only strings) ! 696: have a numeric value less than zero. ! 697: .PP ! 698: When a syntactically invalid line is typed, the parser ! 699: prints a (hopefully) helpful error message and accepts ! 700: new input. A new turn is ! 701: .I not ! 702: begun. A similar action is taken when a nonsense word ! 703: is typed. ! 704: .PP ! 705: Several commands may be typed on one line, separated by ! 706: commas. However, this is considered as identical to ! 707: separating them by new-lines; they are dealt with on ! 708: separate turn cycles (and extra prompts may be printed). ! 709: .bp ! 710: .NH ! 711: Built-in Functions ! 712: .PP ! 713: The following functions are built-in functions available to the ! 714: \s-2DDL\s+2 ! 715: programmer. These functions are the heart of the ! 716: \s-2DDL\s+2 ! 717: system and are ! 718: the means whereby the ! 719: \s-2DDL\s+2 ! 720: routines manipulate all system data. Thus, ! 721: these functions completely describe the facilities of the ! 722: \s-2DDL\s+2 ! 723: system. ! 724: .PP ! 725: The arguments to functions are here shown as "\fIobj\fR and ! 726: the like. In fact, any function may take any value as an argument. ! 727: Mentioning the name of a symbol simply gives its symbol-table ! 728: value. For an object, for example, this is its index in the object ! 729: table. So, while it may be valid to say "($say window)", this will ! 730: only print the message whose message number happens to be the ! 731: same as the object index of the "window". Note that the parser correctly ! 732: assigns such symbol-table values to the variables ! 733: .I ! 734: Dobj, Iobj, Prep, ! 735: .R ! 736: and ! 737: .I Verb. ! 738: .NH 2 ! 739: Functions on objects ! 740: .IP "\fB$loc \fR" 8 ! 741: ($loc \fIobj\fR) \(-> The container of \fIobj\fR. ! 742: .IP "\fB$cont \fR" 8 ! 743: ($cont \fIobj\fR) \(-> First item contained in \fIobj\fR. ! 744: .IP "\fB$link \fR" 8 ! 745: ($link \fIobj\fR) \(-> The next object in the same node as \fIobj\fR. ! 746: .IP "\fB$ldesc \fR" 8 ! 747: ($ldesc \fIobj\fR) \(-> The routine ID for the long description of \fIobj\fR. ! 748: .IP "\fB$sdesc \fR" 8 ! 749: ($sdesc \fIobj\fR) \(-> The routine ID for the short description of \fIobj\fR. ! 750: .IP "\fB$rtn \fR" 8 ! 751: ($rtn \fIobj\fR) \(-> The ACTION routine for \fIobj\fR. ! 752: .IP "\fB$prop \fR" 8 ! 753: ($prop \fIobj\fR \fIpropnum\fR) \(-> returns the value of the \fIpropnum\fR'th property ! 754: of \fIobj\fR. ! 755: .NH 2 ! 756: Arithmetic Funcions ! 757: .IP "\fB$plus \fR" 8 ! 758: ($plus \fIarg1\fR \fIarg2\fR) \(-> \fIarg1\fR+\fIarg2\fR ! 759: .IP "\fB$minus \fR" 8 ! 760: ($minus \fIarg1\fR \fIarg2\fR) \(-> \fIarg1\fR\-\fIarg2\fR ! 761: .IP "\fB$times \fR" 8 ! 762: ($times \fIarg1\fR \fIarg2\fR) \(-> \fIarg1\fR*\fIarg2\fR ! 763: .IP "\fB$quotient \fR" 8 ! 764: ($quotient \fInum den\fR) \(-> [\fInum\fR/\fIden\fR] ! 765: .IP "\fB$remainder \fR" 8 ! 766: ($remainder \fInum den\fR) \(-> \fInum\fB mod \fIden\fR ! 767: .IP "\fB$rand \fR" 8 ! 768: ($rand \fIarg\fR) \(-> Random integer between 1 and \fIarg\fR inclusive ! 769: .NH 2 ! 770: Boolean Functions ! 771: .IP "\fB$and \fR" 8 ! 772: ($and \fIa b\fR) \(-> \fIa\fB (bitwise AND) \fIb\fR ! 773: .IP "\fB$or \fR" 8 ! 774: ($or \fIa b\fR) \(-> \fIa\fB (bitwise OR) \fIb\fR ! 775: .IP "\fB$not \fR" 8 ! 776: ($not \fIx\fR) \(-> \s-2IF\s+2 \fIx\fR nonzero \s-2THEN\s+2 zero \s-2ELSE\s+2 one. ! 777: .IP "\fB$yorn \fR" 8 ! 778: ($yorn) \(-> Waits for the Player to type a line of input. Returns ! 779: one if the Player types "yes" or "y" and zero otherwise. ! 780: .IP "\fB$pct \fR" 8 ! 781: ($pct \fIprob\fR) \(-> Returns one, \fIprob\fR% of the time, zero otherwise. ! 782: .IP "\fB$eq \fR" 8 ! 783: ($eq \fIarg1\fR \fIarg2\fR) \(-> 1 if \fIarg1\fR equals \fIarg2\fR, zero otherwise. ! 784: .IP "\fB$ne \fR" 8 ! 785: ($ne \fIarg1\fR \fIarg2\fR) \(-> IF \fIarg1\fR ~= \fIarg2\fR THEN one ELSE zero. ! 786: .IP "\fB$lt \fR" 8 ! 787: ($lt \fIarg1\fR \fIarg2\fR) \(-> 1 if \fIarg1\fR < \fIarg2\fR, zero otherwise. ! 788: .IP "\fB$gt \fR" 8 ! 789: ($gt \fIarg1\fR \fIarg2\fR) \(-> 1 if \fIarg1\fR > \fIarg2\fR, zero otherwise. ! 790: .IP "\fB$le \fR" 8 ! 791: ($le \fIarg1\fR \fIarg2\fR) \(-> 1 if \fIarg1\fR <= \fIarg2\fR, zero otherwise. ! 792: .IP "\fB$ge \fR" 8 ! 793: ($ge \fIarg1\fR \fIarg2\fR) \(-> 1 if \fIarg1\fR >= \fIarg2\fR, zero otherwise. ! 794: .NH 2 ! 795: Builtin Procedures (no return value) ! 796: .IP "\fB$setg \fR" 8 ! 797: ($setg \fIglobalnumber value\fR) \(-> No return value. Sets the ! 798: contents of global #\fIglobalnumber\fR to \fIvalue\fR. ! 799: .IP "\fB$setp \fR" 8 ! 800: ($setp \fIobj propnum value\fR) \(-> No return value. Sets the \fIpropnum\fR'th ! 801: property of \fIobj\fR to \fIvalue\fR. Note that properties 1-16 may only contain 0 or 1. ! 802: .IP "\fB$move \fR" 8 ! 803: ($move \fIobj dest\fR) \(-> No return value. Causes \fIobj\fR to be placed ! 804: inside \fIdest\fR, and adjusts pointers accordingly. \fBDanger\fR: No checking is ! 805: performed to verify that $move is not being used to violate the tree structure ! 806: of the object list (eg ($move obj obj)). ! 807: Bad results are likely if this occurs. ! 808: .IP "\fB$say \fR" 8 ! 809: ($say \fImsg\fR) \(-> No return value. Types \fImsg\fR. ! 810: .IP "\fB$name \fR" 8 ! 811: ($name \fIobj\fR) \(-> No return value. Types the (5-letter) name of \fIobj\fR. ! 812: .IP "\fB$num \fR" 8 ! 813: ($num \fIx\fR) \(-> No return value. Types the number \fIx\fR. ! 814: .IP "\fB$exit \fR" 8 ! 815: ($exit \fIn\fR) \(-> Leave present routine. ($exit 1) causes the current ! 816: "turn" to be prematurely terminated and the next turn to be initiated ! 817: at the Demon phase. ($exit 0) returns to the driver to begin the next phase. ! 818: .IP "\fB$rtrn \fR" 8 ! 819: ($rtrn \fIn\fR) \(-> Exits to the calling routine, returning value '\fIn\fR' TO ! 820: THE CALLING FUNCTION. ! 821: .IP "\fB$spec \fR" 8 ! 822: ($spec \fIcode arg1 arg2 arg3 arg4\fR) \(-> Performs a special function as ! 823: follows: ! 824: .TS ! 825: center box; ! 826: c | c. ! 827: code function ! 828: = ! 829: 3 Terminate this run of DDL ! 830: _ ! 831: 4 Save a game ! 832: _ ! 833: 5 Restore a game ! 834: _ ! 835: 6 Fork a shell with arguments \fIarg1 \- arg4\fR ! 836: _ ! 837: 7 Preserve unknown words in file \fIarg1\fR ! 838: .TE ! 839: .PP ! 840: Functions 4 and 5 prompt for a file name in which the saved game is ! 841: kept. ! 842: Function 6 is a \s-2UNIX\s+2-specific function. ! 843: Function 7 causes any unknown words encountered by the parser ! 844: to be preserved in a file for later perusal by the ! 845: \s-2DDL\s+2 ! 846: programmer. It ! 847: would be used to learn about things players have tried unsuccessfully ! 848: that should be dealt with. The file must already exist, and must ! 849: be specified as a string. ! 850: .PP ! 851: ALL arguments must be specified, even if zero. ! 852: .NH 2 ! 853: Global-value functions ! 854: .IP "\fB$glob \fR" 8 ! 855: ($glob \fIn\fR) \(-> Value of global \fIn\fR. Equivalent to @\fIn\fR. ! 856: .IP "\fB$verb \fR" 8 ! 857: ($verb) \(-> The ID of the verb returned by the parser (zero if none). ! 858: Typically used in comparisons, it is equivalent to @Verb. ! 859: .IP "\fB$dobj \fR" 8 ! 860: ($dobj) \(-> The ID of the direct object returned by the parser ! 861: (zero if none). Equivalent to @Dobj. ! 862: .IP "\fB$iobj \fR" 8 ! 863: ($dobj) \(-> The ID of the indirect object returned by the parser ! 864: (zero if none). Equivalent to @Iobj. ! 865: .sp ! 866: .B Note: ! 867: There is no ($prep) corresponding to @Prep. ! 868: .NH 2 ! 869: Transition Procedures ! 870: .IP "\fB$setv \fR" 8 ! 871: ($setv \fIv1 v2 v3 v4 v5 v6 v7 v8 v9 v10\fR) \(-> sets the values in ! 872: the internal vector VECVERB to the values \fIv1\fR thru \fIv10\fR. These are ! 873: used by routines $hit and $miss. ! 874: .IP "\fB$hit \fR" 8 ! 875: ($hit \fImover d1 d2 d3 d4 d5 d6 d7 d8 d9 d10\fR) \(-> No return value. ! 876: Compares ($verb) with the values in builtin vector VECVERB. When ($verb) ! 877: is found to match the nth entry in VECVERB, ($move \fImover d[n]\fR) is executed. ! 878: Note that \fImover\fR is what gets moved to d[n]; this argument is naturally ! 879: absent from $setv and $miss. ! 880: .IP "\fB$miss \fR" 8 ! 881: ($miss \fIr1 r2 r3 r4 r5 r6 r7 r8 r9 r10\fR) \(-> no return value. ! 882: Compares ($verb) to VECVERB as $hit does. When a match to the nth ! 883: entry in VECVERB is found, routine \fIr\fR[n] is called. An attempt to ! 884: call routine 0 does nothing. ! 885: .NH 2 ! 886: String Functions ! 887: .PP ! 888: There are two varieties of strings. Constant strings defined ! 889: by the \s-2DDL\s+2 programmer are permanent, and have a numeric "value" ! 890: greater than zero (which is in fact a table index). Strings ! 891: typed by the Player as a direct object, and strings produced ! 892: by the functions $subs and $read are temporary, have a numeric ! 893: "value" less than zero (which allows the programmer to determine ! 894: if the direct object is in fact a string), and are purged by ! 895: having their index values recycled at the beginning of every turn. ! 896: No more than 200 such strings may be generated on a given turn. ! 897: String functions (including ! 898: .B $say ! 899: ) automatically understand both varieties of strings; the ! 900: \s-2DDL\s+2 programmer should not attempt to un-negate ! 901: direct-object-type strings. ! 902: .IP "\fB$eqst\fR" 8 ! 903: ($eqst \fIarg1 arg2\fR) \(-> 1 iff the strings specified by the ! 904: two \fIarg\fRs are equal, zero otherwise. ! 905: .IP "\fB$subs\fR" 8 ! 906: ($subs \fIstr index length\fR) \(-> a string consisting of the ! 907: substring of \fIstr\fR, starting at character \fIindex\fR ! 908: (with an origin of Zero for the beginning of the string), for ! 909: the specified \fIlength\fR. A \fIlength\fR of zero causes ! 910: all the remaining characters starting at \fIindex\fR to be ! 911: taken. ! 912: .IP "\fB$leng\fR" 8 ! 913: ($leng \fIstr\fR) \(-> The length of string \fIstr\fR. ! 914: .IP "\fB$read\fR" 8 ! 915: ($read) \(-> Causes \s-2DDL\s+2 to pause and wait for input from ! 916: the Player. Returns the string the player typed, without the ! 917: trailing newline. ! 918: .NH 2 ! 919: Demons and Fuses ! 920: .IP "\fB$sdem \fR" 8 ! 921: ($sdem n) \(-> Activates routine n as a Demon, to be executed every ! 922: turn. At least one such Demon should exist, to Look at the Player's ! 923: current location, and to increment the turn counter ! 924: .IP "\fB$ddem \fR" 8 ! 925: ($ddem n) \(-> Removes routine n from the active Demon list. For ! 926: example, ($ddem Kount) undoes the action of ($sdem Kount). ! 927: .IP "\fB$sfus \fR" 8 ! 928: ($sfus rout n) \(-> Causes routine "rout" to be executed (one ! 929: time only) after n turns. Such a routine is called a Fuse. ! 930: .IP "\fB$dfus \fR" 8 ! 931: ($dfus rout) \(-> Causes routine rout to be taken off the ! 932: pending fuse list. ! 933: .IP "\fB$itun \fR" 8 ! 934: ($itun) \(-> Increments the turn counter. This is a builtin function ! 935: because fuses depend upon the turn counter. The ! 936: \s-2DDL\s+2 ! 937: programmer has the ! 938: option to "slow time" by refraining from incrementing the turn counter. ! 939: .IP "\fB$gtun \fR" 8 ! 940: ($gtun) \(-> Returns the current turn counter value.
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.