home *** CD-ROM | disk | FTP | other *** search
/ CP/M / CPM_CDROM.iso / cpm / draco / draco-1.ark / QUEST.DOC < prev    next >
Text File  |  1986-11-12  |  19KB  |  325 lines

  1.      I will describe the various routines in sections, but first a few 
  2. points about the whole set. None of the files have carriage control, so 
  3. if you want to copy them to the printer, you should specify @-CC on 
  4. *PRINT*. All of the files (except this one) are Draco source files. None 
  5. of you will be too familiar with the language, but it's sufficiently 
  6. like C and Pascal that you shouldn't have trouble with it. Data types 
  7. 'ushort', 'word', 'short' and 'int' can all be thought of as Pascal 
  8. integers (the distinction between 8 bit and 16 bit and between signed 
  9. and unsigned is useful on micros which don't support that stuff very 
  10. efficiently, but is not relevant on the Amdahl). The 'nonrec' in the 
  11. procedure headers can be ignored - it's like a compiler directive. The 
  12. enumeration types 'enum' are like the same things in C and Pascal. The 
  13. 'union' types are C-style unions, which are like Pascal's variant 
  14. records except that the choice of which is present is made externally. 
  15. The most difficult conversion problem will be that of handling global 
  16. variables - each of the 3 library source files has it's own internal 
  17. global variables which are not meant to be visible by anyone else (much 
  18. like modules and packages). Pascal has no such feature, so the globals 
  19. will have to be combined into one big batch. Perhaps the cleanest way is 
  20. to have one file of all global declarations which can be $CONTINUEd with 
  21. to sort of fudge 'include'ing them. I've kept all externally visible 
  22. library routine names to 8 characters or less, but some internal 
  23. routines have longer names which will have to be shrunk for MTS. Also, I 
  24. don't think I've relied on upper/lower case distinction anywhere. Draco 
  25. strings are like C strings - they consist of a bunch of characters with 
  26. a special marker ('\e' in Draco) at the end. Things in double quotes
  27. (e.g. "hello") are that kind of string. Their data type is '*char' which 
  28. is pointer to character. The '&' operator in Draco takes the address of 
  29. whatever it is applied to. Thus if 'buffer' is an array of 10 characters
  30. (type '[10]char'), then '&buffer[0]' is the address of the first 
  31. character in the array and is of type '*char'.
  32.  
  33. QCRT.DRC - CRT routines.
  34.  
  35.      These routines handle a 24 line by 80 column screen in the manner 
  36. which we discussed earlier. Even though the sizes are parameterized as 
  37. constants (NLINES and NCOLUMNS), it is not likely that the code would 
  38. work properly with a different size screen. All routines whose names 
  39. begin with 'CRT_' are in my terminal independent CRT library, which 
  40. allows programs which use it to be user configured for most terminal 
  41. types. The routines used are:
  42.  
  43.     CRT_ClearScreen() - clear the screen & leave cursor at (0, 0)
  44.     CRT_Move(ushort line, column) - move the cursor to the indicated
  45.     (0-origin) line and column on the screen
  46.     CRT_EnterHighLight() - output after this will be highlighted, e.g. 
  47.     in reverse video
  48.     CRT_ExitHighLight() - output after this will be normal
  49.     CRT_ClearTail() - the current line from the cursor to the last 
  50.     column is cleared - the cursor is not moved
  51.     CRT_ClearToEnd(ushort line) - the cursor is moved to the beginning 
  52.     of the given line and the screen is cleared from there on down
  53.     CRT_PutChars(*char string) - the given string is output to the 
  54.     screen at the current cursor position
  55.     CRT_PutChar(char ch) - the character is output to the screen
  56.     CRT_GetChar()char - a character is read from the terminal. This 
  57.     routine returns '\e' until a key is pressed
  58.     CRT_GetLine(*char buffer; ushort length) - this routine reads an 
  59.     input line of the given maximum length into the buffer. Input 
  60.     line editing (backspace, line delete) is enabled.
  61.  
  62.      The upper left-hand corner of the screen, 11 lines by 38 columns, is
  63. used to display an 11 line by 19 column region of a "scenery map" which 
  64. is a sort of bird's eye view of the region around the player character
  65. (PC) or group. Each 'cell' in the map is represented by two characters, 
  66. side by side. The CRT routines maintain this view by calling a user-
  67. supplied scenery generator, which, given the line and column 
  68. co-ordinate, returns the pair of characters to display for that position.
  69. Also maintained is a list of 'movable objects' which are not considered 
  70. part of the scenery. Each has a pair of characters to display. They are 
  71. displayed 'over top of' the scenery, and the last such specified at a 
  72. given position is the one displayed. Each has an identifier by which the 
  73. user programmer can refer to it. The one with identifier = 0 is assumed 
  74. to be the PC or group, and if it is moved to or off of the edge of the 
  75. viewing area, then the entire map view is windowed (which will entail a 
  76. number of calls to the user-supplied scenery generator).
  77.  
  78.      The upper right-hand corner of the screen, 11 lines by 40 columns, 
  79. is used to display various status indicators needed by the scenario. 
  80. There are three kinds of status indicators: numeric, string and string- 
  81. list. These are set up by calling the appropriate routine with the 
  82. header for the item, it's position in the status area (line, column of 
  83. the first character of the header), and the item's size. These routines 
  84. are also passed the address of the actual variable which records the 
  85. current value, so that a simple call to 'scUpdate' can update the status 
  86. display directly. All routines return an identifier by which the status 
  87. indicator can be referred. String-list items are used for things such as 
  88. the list of things the PC is carrying - the update routine handles 
  89. correct formatting for multi-line display with separating commas. 
  90. Instead of being given the address of the list header, the 'scMult' 
  91. routine is passed a procedure which it is to call to get successive 
  92. strings to display. 
  93.  
  94.      The bottom 12 lines of the screen are used for text input/output as
  95. occurs in most Adventure style games. When the bottom of the screen is 
  96. reached, the area is cleared and I/O continues on the first line of the 
  97. region. If the bottom is reached during output, then the output pauses 
  98. until the end-user types a key to continue (my version displays 'MORE' 
  99. in reverse video down the right-hand edge of the region). The output 
  100. routine handles one character at a time. This allows me to use it as a 
  101. Draco text output channel through which I can 'write' or 'writeln' 
  102. whatever I need to output. This can't be done in Pascal, but so far the 
  103. only things I've needed to output are character strings. Output in this 
  104. way will automatically do word breaks at the correct place. (This means 
  105. that, unless special output formats are needed, text can be output in 
  106. one big continuous stream, and will be automagically broken on word 
  107. boundaries.)
  108.  
  109.      All CRT routines have names beginning with 'sc'. They are:
  110.  
  111. scInit() - this must be called once before any other calls.
  112.  
  113. Map area routines:
  114.  
  115. scNewMap(proc(int line, column)[2]char scenery; word oldObj)word - this 
  116.     fancy header indicates that 'scNewMap' has 2 parameters and returns 
  117.     a result. The first parameter is a procedure which takes two integer 
  118.     parameters and returns an array of 2 characters - this is the 
  119.     scenery generator mentioned above. The second parameter is the list 
  120.     of "movable objects" associated with the map. This is usually just 
  121.     0, but is used when a scenario involves more than one map (it 
  122.     preserves the "movable objects" between uses of the map). The value 
  123.     returned is the "movable objects" list that used to be active. This 
  124.     routine must be called before the map area is used for anything.
  125. scWindow(int line, column) - forces the map area to be redrawn, centered 
  126.     on the given co-ordinates.
  127. scNew(int id, line, column; [2]char chars) - this routine is used to 
  128.     create a new "movable object". The id is used to refer to the entry 
  129.     when moving or deleting it. The line and column are where the object 
  130.     is now, and the two characters are what to display for it.
  131. scMove(int id, line, column) - the specified "movable object" is moved 
  132.     to the given location and redisplayed (if within the window).
  133. scDelete(int id) - the specified "movable object" is removed and can no 
  134.     longer be referenced.
  135.  
  136. Status area routines:
  137.  
  138. scNumber(*char name; ushort line, column, length; *int ptr)int - this 
  139.     routine is used to create a numeric status display. 'name' is the 
  140.     string to use for a header, 'line' and 'column' specify where in the 
  141.     status area to display the item, 'length' is the number of spaces to 
  142.     use for the numeric display (format is 'HEADER: xxxx'), and ptr is 
  143.     the address of the variable which is being displayed. (This address 
  144.     is saved away so that calls to 'scUpdate' can cause a re-display 
  145.     without having to pass in the new value.) The returned value is an 
  146.     identifier by which the status item can be referred.
  147. scString(*char name; ushort line, column, length; **char ptr)int - this 
  148.     routine is used to create a string status display. 'length' is the 
  149.     length of the string to be used (it will be padded on the right or 
  150.     truncated as needed). 'ptr' points to the string variable.
  151. scMult(*char name; ushort line, column, lines;
  152.        proc(bool first)*char gen)int - this routine is used to create a 
  153.     string-list status display. 'lines' is the number of lines reserved 
  154.     for this item (successive lines start in the 3rd column of the 
  155.     status display area). 'gen' is a procedure to call to get the items 
  156.     to be displayed in the list. It has a parameter telling it to start 
  157.     over since, if the items won't fit in the available space, the 
  158.     display process will prematurely stop calling it. If the items won't 
  159.     fit in the available lines, the last one is followed by '..' to 
  160.     indicate that there were more items.
  161. scUpdate(int id) - the specified status item is re-displayed. Once the 
  162.     display items are set up, this is the only display item routine that 
  163.     will be needed.
  164.  
  165. ***NOTE*** In going over this stuff, I've notice that I'm quite 
  166. inconsistent about who generates id's and when they are used. The status 
  167. area routines (and the grammar rules) should be GIVEN id's by the user 
  168. program. Then an 'scRemove(int id)' can be easily added.
  169.  
  170. Later note: this HAS been done, but I'm too lazy to change this writeup.
  171.  
  172. Text I/O routines:
  173.  
  174. scPut(char ch) - this routine is called to output a character in the 
  175.     text area. Word break and pagination is handled as discussed above. 
  176.     The characters '\r' and '\n' (Carriage return and linefeed) are used 
  177.     to signal the need for a forced newline.
  178. scPrompt(*char prompt) - this routine is called to specify the prompt to 
  179.     use on input.
  180. scRead(*char buffer) - an input line is read into the passed buffer. If 
  181.     any text was left to be output (it is buffered up to allow for the 
  182.     word-break processing) it is output first and a new line started. 
  183.     Any prompt is output before the read is done.
  184.  
  185. QPARSE.DRC - the parser.
  186.  
  187.      The parser is fairly simple but will handle a variety of input 
  188. styles, ranging from the simple 'get book' to the more complex 'Put the 
  189. magic sword into the glass trophy case.' No provisions are currently 
  190. present for having multiple commands on one line unless the grammar 
  191. specifies it directly (quite cumbersome). Prefixes, consisting of words 
  192. before an initial ':' can be picked off, but this facility will probably 
  193. not be used (see later). These routines handle the dictionary, which 
  194. contains words, along with their id (should be unique) and type (the 
  195. parser places no interpretation on types, but they are needed). The 
  196. words are stored directly as given (any characters can be used), but 
  197. when the parsing occurs, case will be ignored. Also, when parsing, 
  198. spaces are used as word separators, so having 'words' with spaces in 
  199. them will not work.
  200.  
  201.      The grammar parsed consists of a number of sentence forms, each of 
  202. which is simply a list of elements. An element can be a specific word 
  203. which is required, a specific word-type which is required, an optional 
  204. specific word, an optional word-type or a sequence of words of a given 
  205. type. For example, the grammar sentence
  206.  
  207.     give [ARTICLE] ADJECTIVE* NOUN to [ARTICLE] ADJECTIVE* NOUN
  208.     [PUNCTUATION]
  209.  
  210. could be used to handle the verb 'give'. Input sentences like
  211.  
  212.     Give the big red rose to the ugly dwarf.
  213.     give sword to troll
  214.  
  215. would be accepted (provided the words were in the dictionary and had 
  216. been flagged with the appropriate types). The various sentence forms are 
  217. tried one at a time to match the input commands, thus the ones given 
  218. first will take precedence over later ones in case of ambiguity.
  219.  
  220.     All parser routine names start with 'ps'. They are:
  221.  
  222. psInit(bool prefixEnabled) - must be called once before any other parser 
  223.     routines are used. If 'prefixEnabled' is true, then prefixes ending 
  224.     with ':' will be picked off of input sentences, otherwise they are 
  225.     handled as part of the input sentence. Even when such prefixes are 
  226.     used (e.g. to talk to NPC's), it is probably better to have separate 
  227.     grammar rules for the things that can be said to NPC's, instead of 
  228.     having these things mixed in with the rules for direct commands. The 
  229.     whole area needs more thought, e.g. how do we send messages to other 
  230.     players?
  231. psWord(*char txt; int id, typ) - the given word is added to the 
  232.     dictionary with the given id and word-type. More than one entry with 
  233.     the same id can be added - they are synonyms. Punctuation 'words' 
  234.     are added in the same way.
  235. psgBegin() - called to start the specification of a grammar rule.
  236. psgWord(FORMTYPE form; int data) - called to add an element to a grammar 
  237.     rule. FORMTYPE is an enumeration type with values REQID, REQTYPE, 
  238.     OPTID, OPTTYPE and MULTIPLE which is included in Q.G. The five 
  239.     element types were discussed above (required word of given id, 
  240.     required word of given type, optional word of given id, optional 
  241.     word of given type, multiple words of given type). The 'data' 
  242.     parameter is either the id or word-type, as needed.
  243. psgEnd() - called to signal the end of a grammar rule. Grammar rules can 
  244.     be added at any time, as can dictionary entries; thus the language 
  245.     can grow as the game progresses.
  246. psFind(*char txt)int - looks a word up in the dictionary. Returns the id 
  247.     of the word, or 0 if the word isn't found (thus id = 0 should not be 
  248.     used for any word).
  249. psGet(int id)*char - returns the text of the identified word
  250. psType(int id)int - returns the word-type of the identified word
  251. psParse(*char sentence)int - this routine parses the given input string 
  252.     according to the currently existing dictionary and grammar rules. It 
  253.     returns: -1 if some word in the input is unknown (call pspBad to get 
  254.     the text of the word); 0 if all words were known but the input 
  255.     didn't match any of the grammar rules; else the grammar rule number 
  256.     of the matched rule (assigned starting at 1 and going up as the 
  257.     rules are created using the 'psg' routines). For a successful match, 
  258.     'pspWord' and 'pspPref' can be used to find more details.
  259. pspBad()*char - called after pspParse has returned -1 to get the text of 
  260.     the word which wasn't in the dictionary. (The parser stops as soon 
  261.     as it finds one, so there will only be the one.)
  262. pspWord(int pos)int - returns the id of the word(s) that matched the 
  263.     'pos'th position in the successful grammar rule. For OPTional 
  264.     elements, 0 is returned if no word was there. For MULTIPLE elements, 
  265.     successive calls to 'pspWord' with the same 'pos' will return the 
  266.     various words that matched. No more (or none at all) is signalled by 
  267.     'pspWord' returning 0.
  268. pspPref()int - After psParse when prefixes are enabled, successive calls 
  269.     to this routine will return the id's of the words that were part of 
  270.     the prefix (the stuff before the first ':'). To handle prefixes like
  271.     'Dan, Joe:', comma should be made a word and will be dutifully 
  272.     returned by pspPref. (The ':' is thrown away.) pspPref returns 0 
  273.     when there are no more prefix words (if there were any at all).
  274.  
  275. QLIST.DRC - list handling routines.
  276.  
  277.      These routines are used for handling semantic information. They 
  278. care nothing about meanings - they are just general tools. If we come up 
  279. with better ways to handle general semantic information, I'm quite 
  280. willing to abandon the whole set. One set of routines (names start with 
  281. 'l') simply handles lists of integers (adding, appending, deleting, etc.)
  282. Another set handles properties (essentially arbitrary boolean
  283. (true/false) flags) associated with identifiers. A third set handles
  284. attribute-value pairs associated with identifiers (things like (size 2),
  285. (weight 20), (color red), etc.). More complicated things are used in AI,
  286. (e.g. (BROTHER-OF Sam Joe)), but we probably won't need them.
  287.  
  288. lInit() - this routine must be called before any others in this set.
  289. getId()int - called to get a unique integer id. The values returned on 
  290.     consecutive calls are just 1, 2, 3, etc. Note that this routine was 
  291.     never used in the sample scenario program, since all id's were 
  292.     needed to be known in several places.
  293.  
  294. Simple list handling routines.
  295.  
  296. Type INTLIST given in Q.G defines the elements of the lists. A list 
  297. variable is of type *INTLIST.
  298.  
  299. lAdd(**INTLIST pil; int n) - the value 'n' is added to the front of the 
  300.     list. No check is made to see if it is already in the list.
  301. lAppend(**INTLIST pil; int n) - the value 'n' is appended to the end of 
  302.     the list. No check is made to see if it is already in the list.
  303. lDelete(**INTLIST pil; int n) - the first occurrence (if any) of the 
  304.     value 'n' is deleted from the list.
  305. lGet(*INTLIST il; int n)int - the value of the nth element of the list 
  306.     is returned (if any, else 0).
  307. lIn(*INTLIST il; int n)bool - returns 'true' if the value 'n' is in the 
  308.     list, else returns 'false'.
  309.  
  310. Property handling routines.
  311.  
  312. putProp(int id, prop) - associates property 'prop' with item 'id'.
  313. getProp(int id, prop)bool - returns 'true' if property 'prop' is 
  314.     associated with item 'id', else returns 'false'.
  315. delProp(int id, prop) - ensures that property 'prop' is not associated 
  316.     with item 'id'.
  317.  
  318. Attribute-value handling routines.
  319.  
  320. putAttr(int id, attr, val) - associates attribute 'attr' with value 
  321.     'val' with item 'id'. Any previous association is replaced.
  322. getAttr(int id, attr)int - returns the value for attribute 'attr' 
  323.     associated with item 'id', else 0 if none.
  324. delAttr(int id, attr) - dissassociates attribute 'attr' from item 'id'.
  325.