home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / tads2os2.zip / TADSVER.DOS < prev    next >
Text File  |  1994-10-31  |  99KB  |  2,099 lines

  1. This file contains a list of changes that have been made to TADS
  2. since the version 2.1.0 release.  Most of the changes are fixes to
  3. bugs, so they don't change the documented behavior, but a few, as
  4. explained below, add new functionality to TADS.  Releases are
  5. listed with the most recent release first; each release incorporates
  6. all new features and bug fixes of each prior release unless
  7. otherwise stated.
  8.  
  9. Note:  changes from version 2.0 up to 2.1.0 are not included in
  10. this file in order to keep its size under control.  The revisions
  11. from 2.0 through 2.1.0 are available in the file TADSV200.DOS, which
  12. can be found on the High Energy BBS.
  13.  
  14.  
  15. 2.2.0  10/30/94  new features, enhancements, bug fixes
  16.  
  17.   - TADS now has support for reading and writing files.  This new
  18.     feature is intended to let you save information independently
  19.     of the game-saving mechanism, which allows you to transfer
  20.     information between sessions of a game, or even between two
  21.     different games.  The TADS file operations are not designed
  22.     as general-purpose file system operations; in particular,
  23.     these new functions don't have any provisions for creating or
  24.     reading formatted files, or for exchanging information with
  25.     programs other than TADS games.
  26.  
  27.     To open a file, use the fopen() function.  This function takes
  28.     two arguments:  a single-quoted string giving the name of the
  29.     file to open, using local file system conventions, and a "mode."
  30.     (For  maximum portability, you should avoid using volume names,
  31.     directories, folders, or other path information in filenames.)
  32.     The mode argument is one of these single-quoted string values:
  33.  
  34.         r    open file for reading; file must already exist
  35.         r+   open file for reading and writing; the file is
  36.              created if it doesn't already exist
  37.         w    create a new file for writing; the file is deleted
  38.              if it already exists
  39.         w+   create a new file for reading and writing; the file
  40.              is deleted if it already exists
  41.  
  42.     The return value of fopen() is a "file handle"; this is simply
  43.     a number that you you to perform subsequent operations on the
  44.     file.   For example, this opens a new file called TEST.OUT for
  45.     writing:
  46.  
  47.         fnum := fopen('test.out', 'w');
  48.  
  49.     To close an open file, use fclose():
  50.  
  51.         fclose(fnum);
  52.  
  53.     Note that the TADS runtime allows only a limited number of
  54.     files (currently 10) to be open simultaneously, so you should
  55.     close a file when you're done with it.
  56.  
  57.     To write to a file, use fwrite().  This function takes a file
  58.     handle, and a value to write; the value can be a string, a number,
  59.     or true.  The value can't be nil (this is because the fread() function
  60.     returns nil to indicate failure; if you could write nil to a file,
  61.     there would be no way to distinguish reading a valid nil from an
  62.     error condition).  fwrite() stores the value, along with information
  63.     on its type.
  64.  
  65.     The fwrite() function returns nil on success, true on failure.  If
  66.     the function returns true, it usually means that the disk is full.
  67.  
  68.        if (fwrite(fnum, 'string value!')
  69.            or fwrite(fnum, 123))
  70.            "Error writing file!";
  71.  
  72.     If the file is open for reading, you can read from the file with
  73.     the fread() function.  This function takes a file handle, and it
  74.     returns a value it reads from the file.  The value returned is
  75.     of the same type as the value originally written at this position
  76.     in the file with fwrite().  If this function returns nil, it
  77.     indicates that an error occurred; this usually means that no more
  78.     information is in the file (you've read past the end of the file).
  79.  
  80.        res := fread(fnum);
  81.        say(res);
  82.  
  83.     You can get the current byte position in the file with the ftell()
  84.     function:
  85.  
  86.        "The current seek position is << ftell(fnum) >>. ";
  87.  
  88.     The ftell() function returns a number giving the byte position
  89.     that will be read or written by the next file operation.
  90.  
  91.     You can set the file position with fseek() and fseekeof().  The
  92.     fseek() function moves the file position to a particular byte
  93.     position, relative to the beginning of the file.  For example,
  94.     this seeks to the very beginning of a file:
  95.  
  96.        fseek(fnum, 0);
  97.  
  98.     The fseekeof() function positions the file at its end:
  99.  
  100.        fseekeof(fnum);
  101.  
  102.     Note that you must be careful with fseek().  You should only seek
  103.     to positions that you obtained with the ftell() function; other
  104.     positions may be in the middle of a string or a number in the
  105.     file, so seeking to an arbitrary location and writing could
  106.     render the file unusable by partially overwriting existing data.
  107.  
  108.   - You can now "capture" displayed text to a string.  This new feature
  109.     allows you to examine and manipulate text displays, no matter how they
  110.     are generated.  To activate capturing, use the new built-in function
  111.     outcapture():
  112.  
  113.         stat := outcapture(true);
  114.  
  115.     This starts capturing text.  The return value is a status code that
  116.     you use in the subsequent call to end capturing; you don't need to do
  117.     anything with this status code except pass it to outcapture() when
  118.     you're finished capturing output.
  119.  
  120.     While capturing is in effect, everything that your game attempts to
  121.     display -- through double-quoted strings or through the say() built-in
  122.     function -- is hidden from the user and instead stored in a string.
  123.     Once outcapture(true) is called, no text will be displayed to the
  124.     user until you call this function:
  125.  
  126.         str := outcapture(stat);
  127.  
  128.     The second outcapture() call turns off capturing, and returns a string
  129.     that contains all of the text that was generated since the corresponding
  130.     outcapture(true).
  131.  
  132.     Note that the system automatically turns off capturing any time it
  133.     prompts the user for information.  The system turns off capturing
  134.     when it starts a new command, or when it needs to prompt the user
  135.     for information during a command, such as for disambiguation or to
  136.     request a missing direct or indirect object.  When the system turns
  137.     off output capturing, it clears the capture buffer, so any subsequent
  138.     call to outcapture(stat) will return an empty string.  You can capture
  139.     text only over the course of a single command line.
  140.  
  141.     The outcapture() function can be useful if you want to save some
  142.     text for later.  It's also useful if you want to be able to examine
  143.     the text that would be generated by a method such as sdesc or ldesc.
  144.     Since these methods directly display text, you can't directly obtain
  145.     a string representation of their values; using outcapture(), however,
  146.     you can let them "display" their values into a string that you can
  147.     then examine.
  148.  
  149.     Note that the status value returned from outcapture(true) allows you
  150.     to nest calls to outcapture().  Since the outcapture(stat) call
  151.     restores the capturing status that was in effect on the corresponding
  152.     call to outcapture(true), you don't have to worry when using outcapture()
  153.     about whether any of the methods you're calling are also using it.
  154.  
  155.   - TADS now allows you to create and delete objects dynamically
  156.     at run-time.  This is done through two new operators:  "new"
  157.     and "delete".
  158.  
  159.     To create a new object, use this syntax:
  160.  
  161.         x := new bookItem;
  162.  
  163.     This dynamically creates a new object whose superclass is bookItem.
  164.     When this statement is executed, the runtime creates a new object,
  165.     assigns its superclass to be bookItem, and executes the "construct"
  166.     method in the new object; this method can perform any creation-time
  167.     setup that's desired.  The default thing.construct in adv.t simply
  168.     moves the new object into its location -- this is necessary so that
  169.     the "contents" list of the location is updated to include the new
  170.     object.
  171.  
  172.     A new object inherits all of the vocabulary of its superclass.
  173.  
  174.     To destroy an object you have created, use this syntax:
  175.  
  176.         delete x;
  177.  
  178.     This first calls the "destruct" method of the object to notify it
  179.     that it is about to be deleted, then destroys the object.  Further
  180.     references to the object are illegal, since its memory has been
  181.     released (and thus may be given to another object).  The default
  182.     thing.destruct in adv.t moves the object into nil, which removes it
  183.     from its container's "contents" list -- this is necessary so that
  184.     the reference to the object in that list is removed.
  185.  
  186.     Only objects created with "new" can be destroyed with "delete".
  187.     Objects that are defined statically in your game's source file
  188.     cannot be deleted at run-time.
  189.  
  190.     Object creation and deletion works correctly with the UNDO
  191.     mechanism.  If the player uses UNDO after a move that created an
  192.     object, the object will be destroyed; likewise, if a player uses
  193.     UNDO after a turn that deletes an object, the object will be
  194.     re-created with the same property values it had prior to deletion.
  195.     Similarly, dynamically-created objects are preserved across SAVE
  196.     and RESTORE operations.
  197.  
  198.     Note that TADS does not perform any garbage collection on
  199.     dynamically-created objects.  The system is not capable of
  200.     determining whether an object is accessible or not.  Hence, if
  201.     you lose track of any objects you create with "new", they will
  202.     remain in memory forever -- they will even be saved along with
  203.     saved games and restored when the games are restored.  You must
  204.     be careful to keep track of all objects you create to avoid
  205.     filling all available memory (and the swap file) with unreachable
  206.     objects.
  207.  
  208.   - It is now possible to dynamically add to and delete from the
  209.     vocabulary words of an object.  You can also get the vocabulary
  210.     words of an object at run-time.
  211.  
  212.     To add to an object's vocabulary, use the new "addword" built-in
  213.     function.  This function takes three arguments:  an object, a
  214.     vocabulary property pointer, and a word to add.  For example,
  215.     to add 'red' as an adjective to the object myBook, you would
  216.     do this:
  217.  
  218.         addword(myBook, &adjective, 'red');
  219.  
  220.     To delete the same word, you would write a similar call to the
  221.     new built-in function "delword":
  222.  
  223.         delword(myBook, &adjective, 'red');
  224.  
  225.     You can add to and delete from the words of any object, including
  226.     both static objects (explicitly defined in your source code) and
  227.     dynamically-created objects (created with the "new" operator).
  228.  
  229.     Changes made by addword and delword are tracked correctly by the
  230.     UNDO mechanism, and are saved and restored along with saved games.
  231.  
  232.     To get the words belonging to an object, use the new "getwords"
  233.     built-in function.  This function takes two arguments:  an object,
  234.     and a property pointer; it returns a list of (single-quoted)
  235.     strings, which are the vocabulary words for the object.  For
  236.     example, assume we define myBook as follows:
  237.  
  238.         myBook:  item
  239.             sdesc = "small red book"
  240.             adjective = 'small' 'red' 'tiny'
  241.             noun = 'book'
  242.             location = room2
  243.         ;
  244.  
  245.     Also assume we haven't made any calls to addword() or delword() for
  246.     myBook.  In this case,
  247.  
  248.         getwords(myBook, &adjective)
  249.  
  250.     would return this list:
  251.  
  252.         ['small' 'red' 'tiny']
  253.  
  254.     Note that the order of the words in the list is not predictable,
  255.     so you shouldn't expect the words to be in the same order as they
  256.     were when you defined them in the source file, or in the same
  257.     order as they were added with addword().
  258.  
  259.   - We've added a new function that lets you get information on a verb.
  260.     The new function is verbinfo().  This function lets you get the
  261.     verification and action properties for a verb.  The new function
  262.     takes one or two arguments:  the first is the deepverb object whose
  263.     information you want to retrieve; the optional second argument is
  264.     a preposition object.  If you call verbinfo() with only the verb
  265.     argument, it returns the verification and action properties that
  266.     are defined with the doAction definition for the verb.  If you
  267.     also include the preposition argument, it returns the properties
  268.     that are defined with the ioAction definition for that preposition.
  269.  
  270.     The value returned by this function is a list.  If you call verbinfo()
  271.     with only the deepverb argument, the list has two elements:
  272.  
  273.       [1]   direct object verification property pointer (verDoXxxx)
  274.       [2]   direct object action property pointer (doXxxx)
  275.  
  276.     If you call verbinfo() with both the verb and preposition arguments,
  277.     the return value is a list with four elements:
  278.  
  279.       [1]   direct object verification property pointer (verDoXxxx)
  280.       [2]   indirect object verification property pointer (verIoXxxx)
  281.       [3]   indirect object action property pointer (ioXxxx)
  282.       [4]   true if ioAction has [disambigDobjFirst] flag, nil otherwise
  283.  
  284.     In either case, if no matching doAction or ioAction definition
  285.     exists for the verb, this function returns nil.
  286.  
  287.     Note that it is possible that additional flags (similar to
  288.     disambigDobjFirst) may be added in the future; the returned list
  289.     may be expanded to include information on any such added flags.
  290.     So, for compatibility with future versions, we recommend that you
  291.     don't write conditional code based on the length of the list.
  292.     The lists will never shrink, but they may expand.
  293.  
  294.     For the removeVerb object defined in adv.t, you would get these
  295.     results:
  296.  
  297.       verbinfo(removeVerb)
  298.         = [&verDoUnwear &doUnwear]
  299.  
  300.       verbinfo(removeVerb, fromPrep)
  301.         = [&verDoRemoveFrom &verIoRemoveFrom &ioRemoveFrom nil]
  302.  
  303.   - The ability to create new objects at run-time leads to some
  304.     interesting problems involving indistinguishable objects.  Although
  305.     you should generally use addword (see below) to make your newly-created
  306.     objects distinguishable from one another, this will not always be
  307.     desirable; for example, if you create new gold pieces that serve
  308.     as currency, you will probably not want them to be uniquely named.
  309.  
  310.     To support indistinguishable objects, especially those created
  311.     dynamically at run-time, the system now has a property that you
  312.     can set to indicate to the parser that an object does not need to
  313.     be distinguished from others of the same class.  The new property
  314.     is "isEquivalent".  When isEquivalent returns true for an object,
  315.     all other objects with the same immediate superclass are considered
  316.     interchangeable by the parser.  When a player uses one of these
  317.     objects in a command, the parser will simply pick one arbitrarily
  318.     and use it, without asking the player which one.
  319.  
  320.     If a player uses a noun that is ambiguous with multiple equivalent
  321.     items and one or more other items, the parser will need to
  322.     disambiguate the objects as usual.  In such cases, the parser's
  323.     question will list the distinguishable items only once.  For
  324.     example, assume we have five gold coins that are all equivalent
  325.     (in other words, they all have isEquivalent set to true, and they
  326.     all are immediate subclasses of the same class).  Assume further
  327.     that a silver coin and a bronze coin are also present in the room.
  328.  
  329.        Treasure Room
  330.            You see a bronze coin, five gold coins, and a silver
  331.        coin here.
  332.  
  333.        >get coin
  334.        Which coin do you mean, the bronze coin, a gold coin, or
  335.        the silver coin?
  336.  
  337.     Note that the objects which appear only once are listed with "the"
  338.     (using the thedesc property), while the indistinguishable objects
  339.     are listed only once, with "a" (using the adesc property).
  340.  
  341.   - The new property pluraldesc has been added to thing in adv.t.
  342.     The definition in thing simply adds an "s" to the end of the
  343.     sdesc property.  This new property is used by listcont(obj)
  344.     when multiple equivalent objects are present in a list; see the
  345.     information on the changes to listcont(obj) for details.
  346.  
  347.   - The adv.t functions listcont(obj) and itemcnt(list) have been
  348.     changed to support indistinguishable objects.  To support this
  349.     new functionality, the new functions isIndistinguishable(obj1, obj2)
  350.     and sayPrefixCount(cnt), and the new property pluraldesc, have
  351.     been added to adv.t.
  352.  
  353.     isIndistinguishable(obj1, obj2) returns true if the two objects
  354.     obj1 and obj2 are equivalent for the purposes of listing.  The
  355.     two objects are considered equivalent if both have the same
  356.     first superclass (the return value of the new built-in function
  357.     firstsc(obj)), either they are both being worn or neither is
  358.     worn, and either both are lit lightsources or neither is.  This
  359.     function doesn't test the isEquivalent property of either object,
  360.     since it's assumed that it will only be called if an object has
  361.     already been found whose isEquivalent property is set.
  362.  
  363.     sayPrefixCount(cnt) displays a number.  If the parameter cnt is
  364.     a small number (from one to twenty), the spelled-out number will
  365.     be displayed (for example, "five" will displayed if cnt = 5).  If
  366.     the count is larger, the number will be displayed as digits ("35"
  367.     will be displayed if cnt = 35).  This function is used by
  368.     listcont(obj) to show the number of equivalent items when more
  369.     than one equivalent item is being listed.
  370.  
  371.     itemcnt(list) now returns the number of distinguishable items in
  372.     the list that are to be listed.  For each item in the list whose
  373.     isEquivalent property is true, itemcnt(list) checks each other
  374.     item in the list, and counts each set of equivalent items only once.
  375.     Hence, if a list consists entirely of equivalent items, itemcnt(list)
  376.     will return at most 1 (it will return 0 if none of the items are
  377.     listable).
  378.  
  379.     listcont(obj) will list each set of indistinguishable items in the
  380.     contents list only once, and will show the number of each such item.
  381.     To display the number, the new function sayPrefixCount(cnt) is
  382.     used.  For example, if a room contains a silver coin, a bronze coin,
  383.     and five gold coins (all with the isListed property set to true),
  384.     listcont(room) will display this:
  385.  
  386.        a silver coin, a bronze coin, and five gold coins
  387.  
  388.   - A new built-in function has been added to make it possible to
  389.     implement the functionality of the new listcont method.  The new
  390.     function, firstsc(obj), returns the first immediate superclass of
  391.     the given object (or nil if the object has no superclass).  This
  392.     function, along with the isEquivalent property, can be used to
  393.     determine if two objects should be considered indistinguishable.
  394.  
  395.   - A new special word has been added:  ANY, which is equivalent to
  396.     EITHER.  These words are at the end of the original specialWords
  397.     list; for compatibility with past versions, a specialWords list
  398.     that omits this position is still legal, and indicates that the
  399.     default ('any' = 'either') should be used for this slot.
  400.  
  401.     This special word slot is used by the parser during disambiguation.
  402.     Whenever the parser asks the player to choose an object from a list
  403.     of ambiguous objects, it will accept ANY:
  404.  
  405.         >take coin
  406.         Which coin do you mean, the silver coin, the bronze coin, or
  407.         the gold coin?
  408.  
  409.         >any
  410.         silver coin:  Taken.
  411.  
  412.     When ANY is used in these cases, the parser will simply pick one
  413.     of the objects arbitrarily.  Note that it displays the chosen
  414.     object in the same manner as it would if multiple objects were
  415.     being used.
  416.  
  417.     In addition, the parser will accept noun phrases that start with
  418.     ANY to indicate that any object matching the given noun phrase is
  419.     acceptable; the parser will choose one of the objects arbitrarily
  420.     in these cases.  For example:
  421.  
  422.         >take any coin
  423.         silver coin:  Taken.
  424.  
  425.         >look at any of the coins
  426.         bronze coin:  It's a valuable 1964 Tadsmid, worth over
  427.         .0004 cents on today's scrap bronze market.
  428.  
  429.     The player can also specify the number of items to take.  When
  430.     a number of items is specified, it must be applied to a plural
  431.     noun phrase, and it means the same thing as "any," except that
  432.     the parser (arbitrarily) chooses the given number of items rather
  433.     than just one.  For example:
  434.  
  435.     >look at 3 coins
  436.     >look at any 3 coins
  437.     >look at 3 of the coins
  438.     >look at any 3 of the coins
  439.  
  440.     As a special case, a count of "1" can be used with a singular
  441.     noun phrase.  It means the same thing as "any."
  442.  
  443.         >look at 1 coin
  444.  
  445.   - A new convenience feature, similar to doSynonym and ioSynonym but
  446.     somewhat easier to use, has been added.  You can now specify that
  447.     a method in one object should instead be sent to another object.
  448.     An example:
  449.  
  450.         desk: fixeditem
  451.             noun = 'desk'
  452.             sdesc = "desk"
  453.             location = office
  454.             doOpen -> deskDrawer
  455.             doClose -> deskDrawer
  456.         ;
  457.  
  458.     This specifies that doOpen, verDoOpen, doClose, and verDoClose
  459.     calls should be sent to the deskDrawer object when received by
  460.     the desk.  Note that this should only be used for standard verb
  461.     handler methods, because it redirects both the method indicated
  462.     and its verXoVerb equivalent.
  463.  
  464.   - The parser calls a new method, multisdesc, when displaying the
  465.     name of an object that's part of a list of objects.  Previously,
  466.     the parser simply used sdesc in these cases.  The default adv.t
  467.     definition of thing.multisdesc simply calls the object's sdesc.
  468.     This new method is intended to allow you greater control over
  469.     the display in situations like this:
  470.  
  471.       >get all
  472.       book:  Taken.
  473.       rug:  That's much too heavy to carry.
  474.  
  475.     The object names listed before the colons are now displayed
  476.     with multisdesc.
  477.  
  478.     For compatibility with old games, if an object being listed does
  479.     not define or inherit a multisdesc property, its sdesc is used
  480.     instead.  This ensures that games compiled with previous versions
  481.     of adv.t will continue working properly.
  482.  
  483.   - A new user-defined function that the parser calls has been added.
  484.     This new function is called preparseCmd(), and is similar to
  485.     preparse().  Whereas preparse() is called once for an entire
  486.     command line, and is called with the original, unfiltered text
  487.     of the player's command line, preparseCmd() is called separately
  488.     for each command on a command line if more then one command is
  489.     entered.  Furthermore, preparseCmd() is called after the command
  490.     has been "tokenized" (broken into individual words).  Whereas the
  491.     argument to preparse() is a string with the entire command line,
  492.     the argument to preparseCmd() is a list, each entry of which is
  493.     a (single-quoted) string giving an individual word.  Using the new
  494.     function, you can exert much greater control over how a command
  495.     is parsed, including rewriting a command entirely.
  496.  
  497.     preparseCmd() is called immediately before Me.roomCheck() is called
  498.     for the command.  This call is made prior to any disambiguation or
  499.     object defaulting.
  500.  
  501.     If preparseCmd() returns nil, the command is abandoned (but no
  502.     error message is displayed), and no fuses or daemons are run.  If
  503.     the function returns true, the command proceeds as normal.  Any
  504.     remaining commands on the same line are executed regardless of the
  505.     return value from preparseCmd().  (If you need to cancel the entire
  506.     rest of the command line, one approach would be to set a property
  507.     in the global object to indicate to preparseCmd() that all commands
  508.     are to be ignored; preparseCmd() would always check this property
  509.     before doing anything else, and return nil if it were set.  You
  510.     could clear this property in preparse() so that commands always
  511.     start off enabled.)
  512.  
  513.     In addition, preparseCmd() can return a list of (single-quoted)
  514.     strings, in which case the parser starts over parsing the list
  515.     instead of the original command.  The list is limited to a maximum
  516.     of 128 characters, with one additional character of overhead per
  517.     word -- in other words, you can't make the new command longer
  518.     than the original command, which is limited to the same maximum
  519.     when entered by the player in the first place.  However, you can
  520.     otherwise rewrite the command entirely.  If you want to include
  521.     any special words in the new command, use the conventions described
  522.     below (for example, if you want to include 'and' in the new command,
  523.     use ',' instead).  After the new command inserted by preparseCmd()
  524.     has been processed, the parser will resume processing any remaining
  525.     commands on the player's original command line.
  526.  
  527.     The new command list returned by preparseCmd() can contain multiple
  528.     commands.  Simply separate the commands with commas (',') in your
  529.     list.
  530.  
  531.     If preparseCmd() returns a list, preparseCmd() will be invoked on
  532.     the new command.  However, preparseCmd() is not allowed to return
  533.     another new command in these cases -- if it does, the parser will
  534.     assume that preparseCmd() is looping, and will generate an error.
  535.  
  536.     Several new parseError codes have been added to respond to error
  537.     conditions that can arise from preparseCmd():
  538.  
  539.         32  Internal game error: preparseCmd returned an invalid list
  540.         33  Internal game error: preparseCmd command too long
  541.         34  Internal gmae error: preparseCmd loop
  542.  
  543.     The sample implementation of preparseCmd() below simply lists all
  544.     of the words in the current command and displays a newline, then
  545.     allows the command to proceed as usual.
  546.  
  547.         #pragma C+
  548.         preparseCmd: function(cmd)
  549.     {
  550.         local i, tot;
  551.     
  552.         for (i = 1, tot = length(cmd) ; i <= tot ; ++i)
  553.             "<<cmd[i]>> ";
  554.         "\n";
  555.         
  556.             return true;
  557.     }
  558.  
  559.     Note that the parser performs conversions of the special words.
  560.     These conversions will show up in the list as follows:
  561.  
  562.         "and"   becomes  ","
  563.         "all"   becomes  "A"
  564.         "but"   becomes  "X"
  565.         "it"    becomes  "I"
  566.         "them"  becomes  "T"
  567.         "him"   becomes  "M"
  568.         "her"   becomes  "R"
  569.         "any"   becomes  "Y"
  570.  
  571.     Here are some examples using the preparseCmd() function above.
  572.     (The actual response of the commands has been removed -- only the
  573.     text displayed by preparseCmd() is shown.)
  574.  
  575.         >look at all
  576.         look at A
  577.  
  578.         >examine him; take everything except the box and the book and go north
  579.         examine M
  580.         take A X the box , the book
  581.         go north
  582.  
  583.     preparseCmd() is called even for commands that the parser doesn't
  584.     understand.  This allows you to rewrite commands that TADS wouldn't
  585.     normally understand and put them into a format that's acceptable to
  586.     the parser.  For example, the preparseCmd() example below will
  587.     take sentences of the form "tell <actor> to <command>", and convert
  588.     them to the normal TADS syntax, "<actor>, <command>".
  589.         
  590.         #pragma C+
  591.         preparseCmd: function(cmd)
  592.     {
  593.         local i, tot, to_loc, actor, the_rest;
  594.  
  595.             tot = length(cmd);
  596.  
  597.         /* check to see if it starts with "tell" */
  598.         if (tot > 3 && cmd[1] == 'tell')
  599.         {
  600.             /* see if there's a word "to" */
  601.         for (i = 1, tot = length(cmd) ; i <= tot ; ++i)
  602.         {
  603.             if (cmd[i] == 'to')
  604.                 to_loc = i;
  605.         }
  606.  
  607.         /* if there's a "to", convert the command */
  608.         if (to_loc != nil && to_loc > 2)
  609.         {
  610.             /* find the parts before and after the 'to' */
  611.             for (i = 2, actor = [] ; i < to_loc ; ++i)
  612.                 actor += cmd[i];
  613.             for (the_rest = [], i = to_loc + 1 ; i <= tot ; ++i)
  614.                 the_rest += cmd[i];
  615.  
  616.             /* convert it to "actor, command" */
  617.             return actor + ',' + the_rest;
  618.         }
  619.         }
  620.  
  621.             /* otherwise, process the command as normal */
  622.             return true;
  623.         }
  624.  
  625.     When the parser doesn't know how to handle a sentence, it calls
  626.     preparseCmd with the entire rest of the command (which will include
  627.     everything before the next THEN or period), and processing is the
  628.     same as in any other case.  If preparseCmd() returns nil in this
  629.     case, the command is cancelled as usual without any further
  630.     processing by the parser.  If preparseCmd() returns true when the
  631.     sentence is not recognized by TADS, the parser will display the
  632.     usual message (parseError code 18, "I don't understand that
  633.     sentence").  If preparseCmd() returns a list of strings, the
  634.     command is replaced with the list, and the parser starts over
  635.     processing the new command.
  636.  
  637.   - Several new parseError codes have been added.
  638.  
  639.     In order to produce better messages when actors are involved,
  640.     the system now attempts to figure out whether an object in a
  641.     command refers to an actor, and if so, to determine whether the
  642.     actor should be called "him" or "her".  Previously, this
  643.     one-size-fits-all message was generated:
  644.  
  645.        What do you want to <verb> it <prep>?
  646.  
  647.     for example:
  648.  
  649.        >hit bill
  650.        What do you want to hit it with?
  651.  
  652.     Although it's not always possible to determine which object
  653.     should be used in these cases (because disambiguation will not
  654.     be possible until the indirect object is known), the system will
  655.     make its best guess.  To do so, it looks at all of the objects
  656.     that might be involved, based on the vocabulary.  If the player
  657.     appears to mean multiple objects, " them " will be used -- this
  658.     is message number 144 for parseError:
  659.  
  660.        >throw ball and bat
  661.        What do you want to throw them at?        <- message 144
  662.                                 ------
  663.  
  664.     If only one object appears to be intended, the parser will try
  665.     to figure out whether the object is male, female, or neuter,
  666.     using the isHim and isHer properties (these properties are not
  667.     new; they have been around since before TADS 2.0).  If all of
  668.     the objects that match a single noun phrase have isHim and
  669.     not isHer, " him " will be used -- this is parseError message
  670.     number 145:
  671.  
  672.       >hit bill
  673.       What do you want to hit him with?          <- message 145
  674.                              -----
  675.  
  676.     If they all have isHer and not isHim, " her " will be used
  677.     (message number 146):
  678.  
  679.       >hit jill
  680.       What do you want to hit her with?          <- message 146
  681.                              -----
  682.  
  683.     If both are set, the system equivocates with " them ", message
  684.     number 147 (note that this is the same default text as message
  685.     144, but it's distinguished as a separate message number in
  686.     case a game author wants a more suitable word in this case,
  687.     especially in a non-English language):
  688.  
  689.       >hit hermaphrodite
  690.       What do you want to hit them with?         <- message 147
  691.                              ------
  692.  
  693.     If not all of the objects involved have isHim and/or isHer
  694.     set, the system uses "it" (message 141) as in previous versions.
  695.  
  696.     Another change to the processing for this message involves
  697.     actors.  If an actor is specified in the command, the system
  698.     now builds a replacement for message 140.  First, message
  699.     148 is displayed, which has the default text "What do you want ".
  700.     Then, the actor's thedesc is invoked to display the actor's
  701.     name.  Finally, message 149 (default text " to ") is displayed,
  702.     and the rest of the message is built as before.
  703.  
  704.       >guard, throw ball
  705.       What do you want the guard to throw it at?
  706.       -----------------         ----
  707.          message 148             149
  708.  
  709.   - The functionality of the parseAskobj function has been extended
  710.     so that you can generate the same sort of message that the parser
  711.     now generates when a missing object is needed for a command directed
  712.     to an actor.  To provide the new functionality, the parser now calls
  713.     a function called parseAskobjActor.  This function is exactly the
  714.     same as parseAskobj, except that it takes the actor as the first
  715.     parameter, the verb as the second parameter, and the preposition
  716.     as an optional third parameter (which is only present when asking
  717.     for an indirect object).
  718.  
  719.     If your game defines parseAskobjActor, the system ignores parseAskobj
  720.     and calls the new function instead.  If parseAskobjActor is not defined,
  721.     but parseAskobj is defined, the system calls parseAskobj as it did in
  722.     past versions.  If neither function is defined, the system generates
  723.     the message itself as described above.  You should use parseAskobjActor
  724.     rather than parseAskobj for new games, since it gives you more
  725.     information.
  726.  
  727.     Here's an example of parseAskobjActor, which generates roughly the
  728.     same message as the system would (but it doesn't do any of the checking
  729.     of isHim and isHer to determine which pronoun to use -- this function
  730.     simply uses "it").
  731.  
  732.     parseAskobjActor: function(a, v, ...)
  733.     {
  734.         if (argcount == 3)
  735.         {
  736.             "What do you want ";
  737.                 if (a <> Me) a.thedesc;
  738.         " to <<v.sdesc>> it <<getarg(3).sdesc>>?";
  739.         }
  740.         else
  741.         {
  742.         "What do you want ";
  743.             if (a <> Me) a.thedesc;
  744.         " to <<v.sdesc>>?";
  745.         }
  746.     }
  747.  
  748.   - The parser has been changed slightly to allow a command to specify
  749.     an actor in any command within a single line containing multiple
  750.     commands.  Previously, if an actor was to be specified, the actor
  751.     had to be specified at the very beginning of the command.  This
  752.     restriction has been removed, which allows commands like this:
  753.  
  754.       >joe, north.  bob, south.  bill, east, take book, west.
  755.  
  756.     Note that, as in past versions, once an actor is specified, the
  757.     actor remains in effect for subsequent commands.  Since you could
  758.     only specify one actor for an entire command line in past versions,
  759.     this meant that the actor was used for every command on the line;
  760.     with this new version, an actor remains in effect until another
  761.     actor is specified.  So, in the command above, "north" is directed
  762.     to Joe, "south" is directed to Bob, and "east, take book, west"
  763.     is directed to Bill.
  764.  
  765.   - The maximum number of notifiers has been increased to 200.  The
  766.     maximum number of daemons and fuses has been increased to 100 each.
  767.  
  768.   - The maximum number of ambiguous words matching a particular
  769.     vocabulary word has been increased to 200.  This should relieve
  770.     problems that some people have reported with the error message
  771.     "The word 'foo' refers to too many objects".
  772.  
  773.   - The compiler now supports most of the remaining C operators:
  774.  
  775.         a % b      - returns the remainder of dividing a by b
  776.         a %= b     - sets a to a % b
  777.         a != b     - equivalent to a <> b
  778.         !a         - equivalent to (not a)
  779.         a & b      - bitwise AND
  780.         a &= b     - sets a to the bitwise AND of a and b
  781.         a | b      - bitwise OR
  782.         a |= b     - sets a to the bitwise OR of a and b
  783.         a && b     - equivalent to (a and b)
  784.         a || b     - equivalent to (a or b)
  785.         a ^ b      - bitwise XOR of a and b
  786.         a ^= b     - sets a to the bitwise XOR of a and b
  787.         ~a         - bitwise negation of a
  788.         a << b     - a shifted left by b bits
  789.         a <<= b    - shifts a left by b bits
  790.         a >> b     - a shifted right by b bits
  791.         a >>= b    - shifts a right by b bits
  792.  
  793.     Note a slight complication involving the >> operator:  you can't
  794.     use this operator from within an embedded string expression, because
  795.     it would be confused by the parser for the end of the expression.
  796.     It doesn't help to use parentheses, since the embedded string
  797.     processing is essentially a textual substitution mechanism which
  798.     happens without knowledge of the expression context (and is thus
  799.     unaware of parenthesization).  For example, this would be illegal:
  800.  
  801.        myprop = "x divided by 128 is << (x >> 7) >>!"     // wrong
  802.  
  803.     You would have to code this instead as:
  804.  
  805.        myprop = { "x divided by 128 is "; x >> 7; "!"; }  // right
  806.  
  807.     Another slight complication arises from the use of the & operator
  808.     in lists.  Since TADS allows list elements to appear without any
  809.     separating punctuation (except whitespace), you can have a list
  810.     that looks like this:
  811.  
  812.        mylist = [&sdesc &adesc &thedesc]
  813.  
  814.     This construct is still legal, and is still interpreted with the
  815.     "&" operators as unary operators, not bitwise AND operators.
  816.     However, the parser now warns when such a definition is used; see
  817.     the description of the new warning TADS-357 below for details.
  818.  
  819.   - The compiler will generate a new warning when it detects a unary
  820.     operator within a list that could also be interpreted as a binary
  821.     operator.  For example, in this list,
  822.  
  823.        list2 = [5 -2 -6 -7]
  824.  
  825.     the "-" operators could be interpreted either as unary negation
  826.     operators, which would result in a list with four elements (the
  827.     numbers 5, -2, -6, and -7), or as binary subtraction operators,
  828.     which would result in a list with only one element (the number
  829.     -10).  This same problem arises with the operators "+" and "&",
  830.     since these also have a unary and binary interpretation which
  831.     depends on context.
  832.  
  833.     In these cases, the compiler interprets the operators as unary
  834.     operators, and issues a warning to let you know that the usage
  835.     was ambiguous.  The warning is TADS-357:
  836.  
  837.       TADS-357: warning: operator '-' intepreted as unary in list
  838.  
  839.     Note that this is a change from the previous version for the '+'
  840.     and '-' operators.  If your game depends on building lists from
  841.     calculated numeric constants, you will need to change your code;
  842.     we don't expect that any games actually depend on the old behavior.
  843.  
  844.     If you really do want the operators in these cases interpreted
  845.     as binary operators, use parentheses:
  846.  
  847.        list2 = [(5 -2 -6 -7)]
  848.  
  849.     The parentheses tell the compiler that the expression is to be
  850.     interpreted as a single list element.
  851.  
  852.     If you want the unary interpretation, and you want to suppress
  853.     the warning, use commas between the list elements:
  854.  
  855.        list2 = [5, -2, -6, -7]
  856.  
  857.     This doesn't change the interpretation, but it does suppress the
  858.     warning, because it removes the ambiguity:  when the commas are
  859.     present, there is no way the '-' operators could be interpreted
  860.     as binary operators.
  861.  
  862.     You can suppress the TADS-357 warning if you wish using a new -v
  863.     suboption.  Specify -v-abin in your compiler options to turn off
  864.     the warning ("abin" is short for "ambiguous binary operator", which
  865.     is the meaning of the warning).  You may want to suppress this
  866.     warning when compiling code written prior to this version of TADS,
  867.     since the warning is generated in case you wanted the new meaning
  868.     of the & operator.
  869.  
  870.   - A new compiler command-line option has been added:  -C, a toggle
  871.     option, which turns on and off C-language operator compilation.
  872.     By default, C operator mode is off (-C-), which makes the compiler
  873.     use the normal TADS operators.  Specifying -C+ turns on C operator
  874.     mode; specifying -C- disables C operator mode.
  875.  
  876.     When C-language operator mode is in effect, two operators are
  877.     affected:  the assignment operator becomes '=', and the equality
  878.     comparison operator becomes '=='.  With normal TADS operator mode
  879.     in effect, assignment is ':=' and equality is '='.  If you are
  880.     a C programmer, and you're unhappy with the slight variation in
  881.     operator notation between TADS and C, you can use -C+ to make TADS
  882.     behave more like a real language.  Thanks to the #pragma C options
  883.     (see below), C operator mode has no effect on your choice of
  884.     header files -- you can use the same old adv.t and other header
  885.     files unchanged, and still use C-style operators in your code.
  886.  
  887.   - A new preprocessor command has been added:  #pragma.  This special
  888.     directive can be used to specify certain compiler options from
  889.     within your source code.  Currently, the only #pragma option available
  890.     is the C operator mode option.  Use #pragma C+ to turn on C operator
  891.     mode, and #pragma C- to turn it off.
  892.  
  893.     The #pragma C+ and #pragma C- settings are local to a particular
  894.     file.  If a file is included by another file, the #pragma C settings
  895.     specified in the included file will be in effect only until the end
  896.     of the included file; the including file's #pragma C settings that
  897.     were in effect before including the other file will be restored at
  898.     the end of the included file.  adv.t and std.t now start with a
  899.     #pragma C- command -- this allows adv.t and std.t to be included
  900.     from a file with C-style operators (and thus a #pragma C+ or
  901.     command-line C operator mode setting).  Since the enclosing file's
  902.     #pragma C option will be restored after the inclusion, files with
  903.     different operator modes can be freely intermixed with #include, as
  904.     long as each included file specifies its desired mode with a
  905.     #pragma C directive.
  906.  
  907.   - The precedence of the comparison operators has been changed to
  908.     be the same as that used by C.  Previously, all of the comparison
  909.     operators were at the same precedence; starting with this version,
  910.     == and <> (and thus !=) are at the same level of precedence, and
  911.     associate left to right as before, but <, >, <=, and >= are one
  912.     level higher in precedence.  The following type of expression will
  913.     be affected:
  914.  
  915.           a > 1 <> b > 1
  916.  
  917.     Previously, this grouped as:
  918.  
  919.           (((a > 1) <> b) > 1   // obsolete
  920.  
  921.     This now groups as:
  922.  
  923.           (a > 1) <> (b > 1)    // current behavior
  924.  
  925.     This shouldn't affect any existing code, since the old interpretation
  926.     should always have resulted in an error (because a truth value, true
  927.     or nil, can not be compared in magnitude to a number or other type).
  928.  
  929.   - Limited conditional compilation and preprocessor text substitution
  930.     (#define) support has been added to the compiler.  The following
  931.     preprocessor directives are now available:
  932.  
  933.       #define symbol value
  934.       #undef symbol
  935.       #ifdef symbol
  936.       #ifndef symbol
  937.       #else
  938.       #endif
  939.  
  940.     #define is used to assign a value to a preprocessor symbol.  The
  941.     "value" is simply text that will be substituted verbatim for the
  942.     symbol whenever it occurs in your file (other than within quoted
  943.     strings).  For example:
  944.  
  945.       #define TEST say('hello from TEST!')
  946.  
  947.       myfunc: function
  948.       {
  949.          TEST;
  950.       }
  951.  
  952.     The symbol TEST is replaced with its definition, so the function
  953.     myfunc() displays "hello from TEST!" when called.
  954.  
  955.     Preprocessor symbols defined with #define are in a separate
  956.     namespace from all other symbols in your program.  Unlike a
  957.     standard C preprocessor, no arguments are allowed in #define
  958.     macros.
  959.  
  960.     #undef deletes a previously #define'd symbol.  You can #undef
  961.     the special symbols defined automatically by the compiler if
  962.     you wish (see below).
  963.  
  964.     #ifdef tests to see if a preprocessor symbol is defined.  If it
  965.     is, the lines following the #ifdef line, and up to the corresponding
  966.     #else or #endif, are included; otherwise, they are ignored.
  967.  
  968.     #ifndef is the opposite of #ifdef:  #ifndef tests to see if the
  969.     symbol is NOT defined.  If the symbol is undefined, the lines
  970.     following the #ifndef line up to the corresponding #else or
  971.     #endif are included; otherwise, they are ignored.
  972.  
  973.     #else indicates that the lines between the #else and #endif are
  974.     to be included if an only if the corresponding #ifdef (or #ifndef)
  975.     failed.  #else is optional.  At most one #else is allowed per
  976.     conditional.
  977.  
  978.     #endif terminates a conditional block.  Exactly one #endif must appear
  979.     for each conditional (#ifdef or #ifndef).
  980.  
  981.     You can use #ifdef to compile certain parts of your code
  982.     conditionally.  For example, if you want to include a verb only
  983.     for your debugging version of a game, but you want to remove it
  984.     from the final version, you could do something like this:
  985.  
  986.       #ifdef __DEBUG
  987.       magicVerb:  deepverb
  988.          verb = 'xyzzy'
  989.          action(actor) =
  990.          {
  991.          }
  992.       ;
  993.       #endif
  994.  
  995.     Note that __DEBUG is especially handy for this sort of thing,
  996.     because the compiler automatically defines this symbol when
  997.     debugging (-ds) is turned no (see below).
  998.  
  999.   - The compiler automatically defines several preprocessor symbols.
  1000.     These symbols can be used or tested within your code as needed.
  1001.  
  1002.     __TADS_VERSION_MAJOR is defined to a number indicating the major
  1003.     version number of the compiler (in the present system, 2).
  1004.  
  1005.     __TADS_VERSION_MINOR is defined to a number indicating the minor
  1006.     version number (in the present system, 2).
  1007.  
  1008.     __TADS_SYSTEM is defined to a string (single-quoted) identifying
  1009.     the operating system the compiler is running on.  In addition, the
  1010.     same identifier contained in the string is defined as a preprocessor
  1011.     symbol itself (its value is always 1; it is intended that it will
  1012.     be tested with #ifdef, and not otherwise used).  For example, if
  1013.     __TADS_SYSTEM is 'MSDOS', the symbol MSDOS will be defined to 1.
  1014.     If __TADS_SYSTEM is 'Macintosh', the symbol Macintosh will be
  1015.     defined to 1.
  1016.  
  1017.     __DEBUG is defined to 1 if debugging is turned on for this
  1018.     compilation (with the -ds compiler option).  Otherwise, this symbol
  1019.     is not automatically defined.  You can test the existence of __DEBUG
  1020.     with #ifdef to conditionally include code only when you are compiling
  1021.     for debugging.  This might be useful if you want to include certain
  1022.     commands only in the debugging version of your game, and want to
  1023.     remove them when you actually deliver the game to players.
  1024.  
  1025.     If this set of symbols were entered manually with #define statements,
  1026.     the definitions might look like this:
  1027.  
  1028.       #define __TADS_VERSION_MAJOR  2
  1029.       #define __TADS_VERSION_MINOR  2
  1030.       #define __TADS_SYSTEM         'MSDOS'
  1031.       #define MSDOS
  1032.  
  1033.     __DATE__ is defined as a single-quoted string giving the system date
  1034.     when the compilation began, in the format "Jan 01 1980".
  1035.  
  1036.     __TIME__ is defined as a single-quoted string giving the system time
  1037.     when the compilation began, in a 24-hour format, "13:40:50".
  1038.  
  1039.     __FILE__ is defined as a single-quoted string giving the file being
  1040.     scanned at the point where the __FILE__ macro is encountered.  Each
  1041.     time you use __FILE__, it will have the correct value for that point
  1042.     in your source code.
  1043.  
  1044.     __LINE__ is defined as a number giving the line number at the point
  1045.     where the __LINE__ macro is encountered.  Each time you use __LINE__,
  1046.     it will have the correct value for that point in your source code.
  1047.  
  1048.   - The compiler has two new options that give you further control
  1049.     over preprocessor symbols.  The -D option allows you to define
  1050.     a preprocessor symbol from the command line.  For example, to
  1051.     define TEST to 5 from the command line, you could do this:
  1052.  
  1053.       tc -i/tads/include -DTEST=5 mygame.t
  1054.  
  1055.     Note that if you omit the equals sign, the default definition
  1056.     of the symbol will be 1:
  1057.  
  1058.       tc -i/tads/include -DTEST mygame.t
  1059.  
  1060.     This defines TEST to 1.
  1061.  
  1062.     The -U option undefines a predefined symbol.  You can use this to
  1063.     undefine one of the symbols automatically defined by the compiler.
  1064.     You can also use it to undefine a symbol defined in a precompiled
  1065.     header, if you're loading one; -U is applied after the precompiled
  1066.     header is loaded, so it will undefine symbols loaded from the file.
  1067.     For example, to compile for debugging, but leave __DEBUG undefined,
  1068.     you could do this:
  1069.  
  1070.       tc -ds -U__DEBUG mygame.t
  1071.  
  1072.     The -U option is applied after all -D options, so you can also use
  1073.     it to undefine a symbol placed earlier on the command line.  This
  1074.     may be useful if you are using a configuation file (CONFIG.TC)
  1075.     that contains -D options for symbols you sometimes want to undefine.
  1076.  
  1077.   - The compiler has a new preprocessor directive, #error, which allows
  1078.     you to generate your own error during compilation.  If a #error
  1079.     directive is encountered, any text after the #error is displayed
  1080.     as a compiler error; an occurrence of #error is counted as an actual
  1081.     compilation error, so compilation will fail if #error is encountered.
  1082.     For example:
  1083.  
  1084.        #ifndef TEST
  1085.        # error TEST is not defined!
  1086.        #endif
  1087.  
  1088.     If the preprocessor symbol TEST is not defined at the point when
  1089.     this sequence is encountered, the compiler will display an error:
  1090.  
  1091.       mygame.t(181): error TADS-124: TEST is not defined!
  1092.  
  1093.   - The runtime has a new debugging feature that may help you track
  1094.     down problems with word definitions.  You can make the player
  1095.     command parser generate a number of status messages as it analyzes
  1096.     a player's command; these messages provide information on how the
  1097.     parser is interpreting the words in the command.
  1098.  
  1099.     To activate this new debug mode, use the debugTrace function with
  1100.     these arguments:
  1101.  
  1102.        debugTrace(1, true);
  1103.  
  1104.     To turn the debug mode off, call with nil instead of true.  This
  1105.     debugTrace function is always available, even when running under
  1106.     the normal runtime; the function returns no value when called with
  1107.     these arguments.
  1108.  
  1109.   - The built-in function incturn() has been extended to allow you
  1110.     to run a series of turns all at once.  You can now specify a numeric
  1111.     argument to incturn(); the argument gives the number of turns that
  1112.     should pass.  An argument of 1 causes incturn() to behave as usual.
  1113.  
  1114.     When an argument higher than 1 is given to incturn(), the function
  1115.     runs all of the fuses that are set to burn down within the number
  1116.     of turns specified, but not after that number of turns.  Note that
  1117.     the normal incturn() has never actually executed any fuses, but
  1118.     simply burns down all fuses by one more turn.
  1119.  
  1120.     For example, if you call incturn(2), the system will first run
  1121.     any fuses that are set to burn down after 1 turn, then will shorten
  1122.     all remaining fuses by one more turn.
  1123.  
  1124.   - A new built-in function, skipturn(), has been added.  This new
  1125.     function takes a numeric argument specifying the number of turns
  1126.     to skip; it must be at least 1.  skipturn(n) is similar to incturn(n),
  1127.     except that it does not run any of the fuses that burn down during
  1128.     the 'n' turns -- instead, it simply removes them without running
  1129.     them.
  1130.  
  1131.   - A new built-in function allows you to force capitalization off --
  1132.     this function, nocaps(), is the opposite of caps().  If you call
  1133.     caps() then call nocaps(), the next character is lower-case; if
  1134.     you call nocaps() then caps(), the next character is capitalized.
  1135.  
  1136.     Along with nocaps(), the special sequence \v has been added.  Using
  1137.     this sequence in a displayed string is equivalent to calling
  1138.     nocaps(); this sequence is analogous to \^, which is equivalent
  1139.     to calling caps().
  1140.  
  1141.   - A new built-in function has been added to clear the screen:
  1142.     clearscreen(), which takes no arguments and has no return value,
  1143.     simply clears the screen.  This routine may do nothing on some
  1144.     platforms; for example, in -plain mode on DOS, clearscreen() has
  1145.     no effect.
  1146.  
  1147.   - The parser is now capable of disambiguating direct objects before
  1148.     indirect objects.  By default, everything works as it always has --
  1149.     in a two-object command, the indirect object is disambiguated first,
  1150.     and then the direct object is disambiguated in the presence of the
  1151.     known indirect object.
  1152.  
  1153.     It is now possible, however, to specify that the reverse should be
  1154.     done.  To do this, you use a new special flags syntax when defining
  1155.     your verb:
  1156.  
  1157.        tellVerb: deepverb
  1158.           verb = 'tell'
  1159.           desc = "tell"
  1160.           ioAction(aboutPrep) = [disambigDobjFirst] 'TellAbout'
  1161.        ;
  1162.  
  1163.     The new special flags are placed in square brackets between the
  1164.     equals sign and the property template for the verb definition.
  1165.     The flags currently accepted are:
  1166.  
  1167.        disambigDobjFirst
  1168.        disambigIobjFirst
  1169.  
  1170.     Note that disambigIobjFirst is provided for completeness only; it
  1171.     is never needed, because it is the default setting.
  1172.  
  1173.     When the disambigDobjFirst flag is specified, it means that the
  1174.     command should have its direct object disambiguated before its
  1175.     indirect object.
  1176.  
  1177.     When the disambiguation order is reversed, the normal argument
  1178.     lists for verDoTellAbout and verIoTellAbout are interchanged.
  1179.     For our example, the prototypes for the verifier methods become:
  1180.  
  1181.        verDoTellAbout(actor)
  1182.        verIoTellAbout(actor, dobj)
  1183.  
  1184.     Normally, verIoVerb would not receive the direct object as an
  1185.     argument, because the direct object would not be known at the time
  1186.     of the verIoVerb call; and verDoVerb would receive the indirect
  1187.     object as an argument, because it would be known by the time the
  1188.     direct object was being tested.  When the disambiguation order is
  1189.     reversed, however, so are the prototypes to these functions.
  1190.  
  1191.     The actual action method, ioTellAbout(actor, dobj), remains
  1192.     unchanged.  All other methods also remain the same.
  1193.  
  1194.     When the direct object is disambiguated first, the player is not
  1195.     allowed to use multiple direct objects (or multiple indirect objects)
  1196.     in the command.  If the player tries to do so, the new parseError
  1197.     message number 28 is displayed:
  1198.  
  1199.        >tell bob and bill about gun
  1200.        You can't use multiple objects with this command.
  1201.  
  1202.   - Note that a .GAM file format change was required to support the
  1203.     extra information needed for the disambigDobjFirst flag.  The TADS
  1204.     file format is now format "C".  The compiler is still capable of
  1205.     producing formats A or B, in case you need to generate .GAM files
  1206.     that can be played with versions prior to 2.2; however, if you
  1207.     use a format prior to C, you will not be allowed to use the
  1208.     disambigDobjFirst flag (or any other similar flags that may be
  1209.     added in the future).
  1210.  
  1211.   - Two new methods have been added to disambiguate actors.  Previously,
  1212.     the system validated and disambiguated an actor by pretending that
  1213.     you were attempting to take the actor -- takeVerb.validDo and the
  1214.     actor's verDoTake were used to validate and disambiguate the actor,
  1215.     when all you wanted to do was speak to him.  This did not always
  1216.     produce satisfactory results, and in particular did not allow for
  1217.     such situations as talking over a radio to an actor in another room.
  1218.     To provide better control over actor validation and disambiguation,
  1219.     the system for testing actors has been enhanced.
  1220.  
  1221.     First, to validate an actor, the system now uses the method
  1222.     validActor in the actor object itself.  This method takes no
  1223.     arguments; it returns true if the object is valid as an actor in
  1224.     a command, nil otherwise.  This method is called before the verb
  1225.     or any of the objects involved in the sentence are known.  Its
  1226.     function is not to determine whether the actor wants to receive
  1227.     the command, or even if the object can be used as an actor
  1228.     (actorAction is the place to do both of these tests), but rather
  1229.     simply to determine if the object can be addressed by the player
  1230.     at all.  This method should return true if the actor is accessible
  1231.     by voice command (or whatever other means you want to provide for
  1232.     giving commands) to the player.  The default thing.validActor in
  1233.     adv.t returns true if the object is reachable by Me, which provides
  1234.     roughly the same behavior as the old takeVerb-based mechanism.
  1235.  
  1236.     Second, to disambiguate an actor, the new preferredActor method
  1237.     has been added.  This method is called if an actor is ambiguous.
  1238.     As with validActor, it doesn't take any arguments, and it returns
  1239.     true if the object is "preferred" as an actor, nil otherwise.  If
  1240.     exactly one ambiguous object's preferredActor method returns true,
  1241.     the parser will use that object as the actor without further
  1242.     questioning the player; otherwise, the system will ask the player
  1243.     to disambiguate the noun as normal.  In adv.t, movableActor defines
  1244.     preferredActor = true.
  1245.  
  1246.     An example of how these might be used:
  1247.  
  1248.        Sleeping Compartment
  1249.           You are in a sleeping compartment on a moving train.
  1250.        A pair of bunks is along each wall.
  1251.           There is a copper wire here.
  1252.           The train conductor is standing in the doorway, asking for
  1253.        your ticket.
  1254.  
  1255.        >look at conductor
  1256.        Which conductor do you mean, the copper wire, or the train
  1257.        conductor?
  1258.  
  1259.        >copper
  1260.        It's a piece of wire, about a foot long.
  1261.  
  1262.        >conductor, where is ivan?
  1263.        "Your ticket, please," is all the conductor has to say.
  1264.  
  1265.     In this sequence, when the command is addressed to "conductor", the
  1266.     parser matches both the copper wire and the train conductor.  It
  1267.     checks validActor in each of them -- both return true, since both
  1268.     are accessible to the player.  (As described above, even though the
  1269.     copper wire couldn't possibly be an actor, it is valid as an actor
  1270.     at this point -- it's not until its actorAction that we will decide
  1271.     that there's no point in talking to it.)
  1272.  
  1273.     So, the parser has an ambiguous actor.  The parser tries to
  1274.     disambiguate the actor by testing preferredActor in each object.
  1275.     The copper wire's preferredActor returns nil; the train conductor's,
  1276.     however, returns true, because the conductor is a movableActor
  1277.     object.  The parser now has only one object, and thus doesn't
  1278.     need to ask the player for further information.
  1279.  
  1280.     For compatibility with games compiled with previous versions of
  1281.     adv.t, the parser will continue to use the old mechanism (involving
  1282.     the takeVerb) if validActor is not defined in your game.  Each time
  1283.     an actor is used, the parser checks to see if the first object in
  1284.     the list of possible actor objects has a validActor method defined;
  1285.     if not, the parser uses the old mechanism.  If you use the new adv.t,
  1286.     all objects will at least inherit a validActor method (from thing),
  1287.     so testing for the presence of this method in any object lets the
  1288.     parser determine if the new mechanism can be used with the game.
  1289.  
  1290.   - A new parseError message has been added:  number 27, whose default
  1291.     text is "You can't repeat that command."  This message is displayed
  1292.     when the player types AGAIN, but the parser can't repeat the command;
  1293.     this is the case if one of the objects involved in the command is
  1294.     no longer accessible.
  1295.  
  1296.   - A new parseError message has been added, related to validActor
  1297.     (see above).  This new message, number 31, is used when none of
  1298.     the objects matching the vocabulary for an actor in a player's
  1299.     command can be used as an actor.  The default text of this message
  1300.     is "You can't talk to that."  For example, if there is no object
  1301.     matching the vocabulary "guard" whose validActor method returns
  1302.     true, but an object named "guard" is visible to the player, the
  1303.     message is used:
  1304.  
  1305.       Security Room
  1306.           You are inside a small cubicle.  A thick, laser-proof
  1307.       (as you now know from your ill-fated attempt) glass door
  1308.       (closed) is to the north.  Through the door you can see
  1309.       a guard standing watch.
  1310.  
  1311.       >guard, open door
  1312.       You can't talk to that.
  1313.  
  1314.     This message is used for actors in place of the standard cantReach
  1315.     processing done for direct and indirect objects under these conditions.
  1316.  
  1317.   - A new parseError code, number 29, has been added.  The default
  1318.     message is "I think you left something out after 'any of'", and
  1319.     is used when the player uses "any of" in a sentence, but doesn't
  1320.     follow it with anything.
  1321.  
  1322.   - Using the same word as both a plural and a noun works much better
  1323.     now.  The parser will first attempt to use such a word as a plural;
  1324.     if no objects match the plural usage, the parser will try to use
  1325.     the word as a noun instead.
  1326.  
  1327.   - "of" can now be used as a preposition.  In previous versions of
  1328.     the run-time, "of" was exclusively a special word that was embedded
  1329.     in noun phrases (such as "pile of paper").  The runtime will still
  1330.     allow "of" to be used in noun phrases as before, but it also will
  1331.     treat "of" as an ordinary word when, based on the context, it does
  1332.     not appear to be part of a noun phrase.
  1333.  
  1334.     The parser will still attempt to treat "of" as part of a noun
  1335.     phrase whenever it matches an object.  For example, if you have
  1336.     an object with nouns matching "pile of paper", then the following
  1337.     interpretations will apply:
  1338.  
  1339.         accuse bob of murder   ->  dobj = bob, iobj = murder, prep = of
  1340.         accuse pile of paper   ->  dobj = pile of paper
  1341.  
  1342.     Note that ofPrep, defining "of" as a preposition, has been added
  1343.     to adv.t.
  1344.  
  1345.   - All of the system verbs that use "abort" have been modified
  1346.     slightly in adv.t to make it easier to augment their behavior
  1347.     with the 'modify' statement.  All of the processing other than
  1348.     the "abort" has been moved out of the doVerb (or action) method
  1349.     in each case, and put into a new method.  For example, saveVerb's
  1350.     action routine now looks like this:
  1351.  
  1352.         action( actor ) =
  1353.         {
  1354.         self.saveGame(actor);
  1355.         abort;
  1356.     }
  1357.  
  1358.     The new method saveVerb.saveGame(actor) now performs all of the
  1359.     processing that the action(actor) method previously performed.
  1360.  
  1361.     The benefit of this change is that you can now modify the
  1362.     saveGame(actor) method, and inherit the original behavior,
  1363.     without having to worry about an "abort" interfering with the
  1364.     order of operations.  For example:
  1365.  
  1366.         modify restoreVerb
  1367.             restoreGame(actor) =
  1368.             {
  1369.                 // restore the game as usual - check for success
  1370.                 if (inherited.restoreGame(actor))
  1371.                 {
  1372.                     // re-randomize the puzzle
  1373.             "The carnival hawker flashes a mischevious
  1374.             smile at you.  \"There's no use trying to
  1375.             guess the answer,\" he says.  \"I changed
  1376.             around the shells while you were busy
  1377.             restoring!\"";
  1378.             puzzle.answer := rand(100);
  1379.                 }
  1380.             }
  1381.         ;
  1382.  
  1383.  
  1384.   - The format mask fmtMe has been added.  You can now use %me% in
  1385.     messages to refer to the actor.  For basicMe, fmtMe is set to
  1386.     the message "me"; for other actors, it is set to the actor's
  1387.     thedesc.  In adv.t, thing.ldesc has been changed to use %me%:
  1388.     "It looks like an ordinary <<sdesc>> to %me%."  This makes the
  1389.     default sentence somewhat more adaptable if you ask another
  1390.     actor to describe something:
  1391.  
  1392.         >guard, look at the card
  1393.         It looks like an ordinary card to the guard.
  1394.  
  1395.   - AGAIN, WAIT, and SLEEP are now darkVerb's in adv.t.
  1396.  
  1397.   - A new verb, breakVerb, has been added to adv.t.  The vocabulary
  1398.     words for this verb are 'break', 'destroy', and 'ruin', and it
  1399.     provides a single-object command "break <direct-object>".  The
  1400.     thing class has been adjusted so that verDoBreak(actor) validates
  1401.     breaking any object, but doBreak(actor) simply displays "You'll have
  1402.     to tell me how to do that."  If you want to make a breakable object,
  1403.     simply override doBreak(actor) so that it breaks the object (you may
  1404.     also want to override verDoBreak(actor) so that it doesn't allow a
  1405.     broken object to be broken again).
  1406.  
  1407.   - "there" has been added a synonym for "it" in the specialWords list
  1408.     in adv.t.  This allows sentences like this:
  1409.  
  1410.         >get box.  put ball in there.
  1411.  
  1412.   - lightsource now has a doTurnnon method in adv.t.  This method will
  1413.     show the room's description if the room becomes lit as a result
  1414.     of turning on the lightsource.  Note that lightsource, by default,
  1415.     has no verDoTurnon, so you can't turn a generic light source on
  1416.     and off.  However, if you add switchItem to the superclass list of
  1417.     a lightsource object, you will have a light source that you can
  1418.     turn on and off, and which will have this new behavior.  Note that
  1419.     you should put lightsource in the superclass list prior to
  1420.     switchItem, so that lightsource.doTurnon overrides switchItem.doTurnon:
  1421.  
  1422.         flashlight:  lightsource, switchItem
  1423.             sdesc = "flashlight"
  1424.             noun = 'flashlight' 'light'
  1425.             adjective = 'flash'
  1426.             location = tunnel
  1427.         ;
  1428.  
  1429.   - verIoGiveTo and ioGiveTo have been added to movableActor in adv.t.
  1430.     verIoGiveTo rejects the command if the actor is the same as the
  1431.     indirect object, otherwise the command is accepted.  ioGiveTo
  1432.     always rejects the offer.  In addition, ioGiveTo has been added
  1433.     to basicMe; the method always accepts anything from another actor,
  1434.     because this method will only be called in response to commands
  1435.     such as:
  1436.  
  1437.         >guard, give me the key
  1438.  
  1439.   - A small problem with thing.isVisible in adv.t has been fixed.  If
  1440.     the vantage is inside the object, and the object's contents are
  1441.     visible, isVisible returns true.  This is is needed in certain
  1442.     situations involving nested rooms.
  1443.  
  1444.   - moveableActor.travelTo(room) in adv.t has been corrected so
  1445.     that it does nothing when room = nil, which is the case when the
  1446.     actor can't travel in the desired direction.  Previously, the
  1447.     "noexit" message would be displayed, but then the actor would
  1448.     be moved into a nil location.
  1449.  
  1450.   - moveableActor now has a roomCheck method in adv.t.  The method
  1451.     is the same as basicMe's roomCheck method; its omission in
  1452.     previous versions was an oversight.
  1453.  
  1454.   - The showcontcont function in adv.t has been corrected so that
  1455.     the isqsurface flag is checked correctly.
  1456.  
  1457.   - A new class, seethruItem, has been added to adv.t.  This class is
  1458.     intended for objects such as windows or magnifying glasses which
  1459.     the player can look through.  Each object of this class should
  1460.     define an appropriate thrudesc method, which displays what the
  1461.     player sees when looking through this object.
  1462.  
  1463.     Note that a seethruItem is not the same as a transparentItem.
  1464.     The class transparentItem is intended for objects, such as glass
  1465.     bottles, whose contents are visible, whereas seethruItem is intended
  1466.     for objects that are not containers but which the player can look
  1467.     through.
  1468.  
  1469.   - The compiler now sets an error code on exit.  If you are using
  1470.     a MAKE utility or other program-building tool, you can use the
  1471.     exit code.  On success, the compiler uses exit code 0; if any
  1472.     errors occurred, a non-zero exit code is used.
  1473.  
  1474.   - The compiler no longer creates a .GAM file if errors occurred
  1475.     during compilation.  If a .GAM file of the same name exists
  1476.     prior to a compilation, and errors occur, the original .GAM
  1477.     file is unaffected (it is not deleted or overwritten).  Although
  1478.     the compiler previously produced a .GAM file even when an error
  1479.     occurred, this .GAM file was not generally usable; to avoid
  1480.     confusion, the compiler no longer produces a .GAM file at all
  1481.     when an error occurs.
  1482.  
  1483.   - The compiler performs more checking for invalid -m parameters.
  1484.     When -m parameters are entered that exceed the compiler's internal
  1485.     limits, it will report an error and abort the compilation.  The
  1486.     affected options are -mp, -ml, and -ms.  The runtime similarly
  1487.     checks its parameters more carefully now.
  1488.  
  1489.   - The DOS runtime no longer displays anything on the status line at
  1490.     startup.  It initializes both the left portion (which normally is
  1491.     used to display the location) and the right portion (which is
  1492.     normally used to display the score and turn count) to empty
  1493.     strings.  To ensure that a score is properly displayed at the
  1494.     start of the first turn, we added a call to scoreStatus(0, 0) in
  1495.     the "init" function defined in std.t.
  1496.  
  1497.   - The DOS runtime now has a plain ASCII mode.  In this mode, the
  1498.     runtime uses only DOS character input and output functions,
  1499.     performs no highlighting or cursor positioning, and does not
  1500.     display a status line.  Command editing and screen scrollback
  1501.     are also disabled (although normal DOS keyboard editing can be
  1502.     used, and any loaded command editor, such as DOSKEY, will be
  1503.     active).  This mode is intended for people with a special need
  1504.     to use direct DOS character I/O, such as persons using a voice
  1505.     synthesizer.  To invoke this mode, specify -plain in the runtime
  1506.     command options:
  1507.  
  1508.           tr -plain mygame
  1509.  
  1510.     Note that .EXE files produced by MAKETRX can be used in this
  1511.     manner as well; simply specify -plain with the game program:
  1512.  
  1513.           deep -plain
  1514.  
  1515.   - The DOS runtime now uses the control-left-arrow and
  1516.     control-right-arrow to move the cursor left and right by one
  1517.     word in the command editor.  This behavior is consistent with
  1518.     most other DOS command editors.
  1519.  
  1520.   - $$ABEND can now be used after a question from the parser, such
  1521.     as during disambiguation and when OOPS is permitted.
  1522.  
  1523.   - The runtime handles hyphenation better.  Multiple hyphens will
  1524.     no longer be split across lines -- so if you use two hyphens
  1525.     together for a dash, both hyphens will always be grouped on one
  1526.     line.  Furthermore, the runtime formatter will never put a dash
  1527.     at the very start of a line; if a line must be split at a dash,
  1528.     the formatter will put the dash at the end of the line, then
  1529.     break the line, and will back up and split at the previous word
  1530.     if necessary.
  1531.  
  1532.   - The runtime will now properly convert "\" sequences in askfile()
  1533.     prompts properly.  If you use a \n, \t, \', \", or \\ sequence
  1534.     in a prompt to askfile(), the sequence will be displayed as the
  1535.     appropriate character.  (For the DOS runtime, this only matters
  1536.     in -plain mode, because the DOS file selector in the normal full-
  1537.     screen mode doesn't use the prompt string.)
  1538.  
  1539.   - The DOS runtime's file selector dialog incorrectly interpreted
  1540.     the Alt keys for disks in the last version -- Alt-B selected the A
  1541.     drive, Alt-C selected the B drive, and so forth.  This has been
  1542.     corrected.
  1543.  
  1544.   - The MAKETRX command now takes an additional argument that lets
  1545.     you specify the run-time command options that should be used when
  1546.     the game is executed.  MAKETRX still accepts the original command
  1547.     formats; using one of the old-style command formats will not bind
  1548.     any command options into the resulting .EXE file.
  1549.  
  1550.     To specify command options for your game executable, you must
  1551.     first create a file.  Use the same format as CONFIG.TR -- simply
  1552.     enter your options into the file as you would on the TR command
  1553.     line; separate options by newlines or spaces.  For example, to
  1554.     specify a minimal cache size and a swap file of SWAP.DAT, you
  1555.     could make your CONFIG.TR file look like this:
  1556.  
  1557.         -m0 -tf swap.dat
  1558.  
  1559.     Once you've created a file with your command options, specify
  1560.     that file to MAKETRX by using it as the first parameter on the
  1561.     command line, prefixed with an "at" sign (@):
  1562.  
  1563.         maketrx @config.tr mygame
  1564.  
  1565.     The @config option can be used with any of the original command
  1566.     formats for MAKETRX.  Once the config file is bound into your
  1567.     executable, its options will be used every time a player runs
  1568.     your game's .EXE file.  Note that you may want to avoid specifying
  1569.     anything specific to your system, such as drives or directories,
  1570.     since that may prevent the game from working properly on someone
  1571.     else's system.
  1572.  
  1573.   - The new sentence parsing for the form VERB PREP IOBJ DOBJ
  1574.     (introduced in 2.1.1) causes a subtle problem:  if you create
  1575.     an object with an adjective that is also a preposition, the
  1576.     system attempts to interpret sentences with a single-word verb
  1577.     that refers to the object as VERB PREP IOBJ.  The result is
  1578.     this:
  1579.  
  1580.        >push off button
  1581.        What do you want to push?
  1582.  
  1583.     This is because the parser is interpreting the sentence as
  1584.     "push something off button", and needs to know the "something".
  1585.     This problem has been corrected.  Now, the parser will check this
  1586.     type of case to see if the preposition can also be used as an
  1587.     adjective, and if so, checks to see if a noun (possibly preceded
  1588.     by one or more adjectives) follows; if this test is met, the word
  1589.     will be interpreted as an adjective, as it should be.
  1590.  
  1591.   - The parser now correctly distinguishes between cases involving
  1592.     a word that is defined as both a preposition and an adjective.
  1593.     The parser previously did not accept sentences such as this:
  1594.  
  1595.       >enter south wall
  1596.  
  1597.     when 'south' was defined as an adjective.  Because 'south' was
  1598.     also defined as a preposition (in adv.t), the parser attempted
  1599.     to interpret this sentence as though 'enter south' were a verb
  1600.     (in the same manner as 'pick up' or 'put down').  The parser
  1601.     now checks to make sure that 'enter south' is a valid combination
  1602.     verb; if it's not, and 'south' is also defined as another part of
  1603.     speech, the parser assumes that 'enter' is the verb, and treats
  1604.     'south' as an adjective.
  1605.  
  1606.   - The parser previously asked to disambiguate a direct object twice
  1607.     if askio(prep) was used.  For example:
  1608.  
  1609.        >unlock door
  1610.        Which door do you mean, the large door, or the small door?
  1611.  
  1612.        >large
  1613.        What do you want to unlock it with?
  1614.  
  1615.        >key
  1616.        Which key do you mean, the silver key, or the gold key?
  1617.  
  1618.        >gold
  1619.        Which door do you mean, the large door, or the small door?
  1620.  
  1621.        >large
  1622.        The door unlocks with a satisfying click.
  1623.  
  1624.     This has been corrected -- the parser now only asks once about
  1625.     the door.
  1626.  
  1627.   - The parser did not previously accept a word during disambiguation
  1628.     if the word was defined as both a noun and an adjective.  For
  1629.     example, if you've defined objects "violet paper", "violet banana",
  1630.     and "paper towel", and the parser asked you this:
  1631.  
  1632.        >x violet
  1633.        Which violet do you mean, the violet paper, or the violet banana?
  1634.  
  1635.     then you couldn't respond with "paper".  This has been corrected.
  1636.  
  1637.   - The inputkey() function now clears the "more" line counter.  So,
  1638.     when inputkey() is called, a "more" prompt will not show up until
  1639.     another screenful of text has been displayed.
  1640.  
  1641.   - "local" statements that occur out of context (i.e., as other than
  1642.     the first statements after an open brace) now generate better
  1643.     diagnostics.
  1644.  
  1645.   - Dividing by zero is now flagged as a run-time error.
  1646.  
  1647.   - A problem involving the embedded string << >> notation has been
  1648.     corrected.  Under certain circumstances, if one expression used
  1649.     in an embedded string invoked another string with an embedded
  1650.     expression, an error occurred (usually "invalid type for built-in
  1651.     function").  This should no longer occur.
  1652.  
  1653.   - The system did not properly handle lists containing function
  1654.     pointers.  This has been corrected.
  1655.  
  1656.   - A problem involving pre-compiled headers and 'modify' has been
  1657.     corrected.  Several people have encountered problems that generally
  1658.     were manifested as "assert" failures in mcm.c (the cache manager)
  1659.     when using 'modify' and pre-compiled headers; these should no
  1660.     longer occur.
  1661.  
  1662.   - An internal cache corruption occurred under certain obscure
  1663.     circumstances involving 'modify'.  This has been corrected.
  1664.  
  1665.   - A note on roomCheck:  if you return nil from roomCheck, fuses
  1666.     and daemons are NOT run; in this sense, returning nil from roomCheck
  1667.     is equivalent to using abort in other methods.  (This is not a
  1668.     change -- it's always worked this way -- but this behavior is
  1669.     not mentioned in the TADS Author's Manual.)
  1670.  
  1671.   - A note on using << >> embedded strings:  If you put a newline
  1672.     immediately before the << of an embedded string, any spaces between
  1673.     the last non-space character preceding the << and the << will be
  1674.     lost.  If you want a space before the <<, do not put it on a new
  1675.     line.  Instead, you can put it at the end of the line, and put
  1676.     the embedded expression itself on the next line.  For example:
  1677.  
  1678.         embeddedString = "embedded string"
  1679.         sdesc = "This is a message with an
  1680.                  <<self.embeddedString>>!"     // wrong
  1681.  
  1682.     This will display as follows:
  1683.  
  1684.         This is a message with anembedded string!
  1685.  
  1686.     If you intend a space to precede the embedded string, you should
  1687.     write this as follows:
  1688.  
  1689.         sdesc = "This is a message with an <<
  1690.                 self.embeddedString>>!";      // right
  1691.  
  1692.     (This is not a change, but simply a note for game developers who
  1693.     have encountered this problem.)
  1694.  
  1695.  
  1696.  
  1697. 2.1.2  11/22/93  enhancements, bug fixes
  1698.  
  1699.   - You can now detect when the player uses multiple direct objects
  1700.     with a verb, and reject such commands.  Whenever the player uses
  1701.     multiple direct objects with a command (or uses "all", even if it
  1702.     results in a single object being used), the parser calls the
  1703.     verb object's rejectMultiDobj(prep) method.  If you don't wish to
  1704.     take any special action for multiple direct objects used with a
  1705.     particular verb, simply return nil from this method (or don't
  1706.     define the method at all for the verb).  If you want to prevent
  1707.     multiple direct objects from being used, however, you should display
  1708.     an appropriate message, and return true.  The parser will skip the
  1709.     command entirely.  Note that the parser doesn't display any additional
  1710.     message when rejectMultiDobj(prep) returns true; the method should
  1711.     display whatever message is desired.  The "prep" parameter is the
  1712.     preposition object used with the command; it will be nil if no
  1713.     indirect object is present.  An example:
  1714.  
  1715.         modify inspectVerb
  1716.             rejectMultiDobj(prep) =
  1717.             {
  1718.                 "You can only look at one thing at a time.";
  1719.                 return true;
  1720.             }
  1721.  
  1722.     The verb's rejectMultiDobj(prep) method is called immediately
  1723.     before the actor's actorAction method.  Note that the parser will
  1724.     continue processing any remaining commands on the line, and will
  1725.     then run daemons and fuses as normal, even if rejectMultiDobj(prep)
  1726.     returns true; if you want to stop the current turn altogether, use
  1727.     abort.
  1728.  
  1729.   - The player command parser now gives you greater control over object
  1730.     validation error reporting.  In previous versions, if an object was
  1731.     visible but did not pass the validIo/validDo test, the parser called
  1732.     the object's cantReach method to report the error (see the note below
  1733.     about an additional change to object.cantReach processing).
  1734.  
  1735.     Now, however, the parser will call verb.cantReach instead, if the
  1736.     command's deepverb object defines (or inherits) a cantReach method.
  1737.     If the verb does not have a cantReach method at all, the parser
  1738.     will use the old behavior instead.  The new cantReach method should
  1739.     be defined as follows:
  1740.  
  1741.        myVerb: deepverb
  1742.            verb = 'whatever'
  1743.            cantReach(actor, dolist, iolist, prep) =
  1744.            {
  1745.                // your code here
  1746.            }
  1747.        ;
  1748.  
  1749.     This method doesn't return a value; it simply displays the appropriate
  1750.     message explaining why the object can't be used with the command.
  1751.     verb.cantReach is used only when the objects are visible (that is,
  1752.     object.isVisible(actor) returned true for each object in the list).
  1753.  
  1754.     Only one of dolist or iolist will be non-nil.  If the direct object
  1755.     of the command refers to one or more objects that are visible but
  1756.     can't be used (according to validDo), dolist will be a list of all
  1757.     such objects, and iolist will be nil.  Otherwise, iolist will be a
  1758.     list of such objects used for the indirect object, and dolist will
  1759.     be nil.
  1760.  
  1761.     adv.t has not been changed to use verb.cantReach.  This change has
  1762.     been made to provide finer control for game authors implementing
  1763.     their own verbs and object validation procedures.
  1764.  
  1765.   - The player command parser had an odd quirk when ambiguous nouns
  1766.     were used with transparent items.  If the player used a command
  1767.     containing a noun that referred to multiple objects that were
  1768.     visible but were not valid for the verb (for example:  "take trophy"
  1769.     in a room containing a closed glass trophy case containing a bowling
  1770.     trophy and a tennis trophy), the parser asked the normal disambiguation
  1771.     question.  This was not really necessary, because the parser already
  1772.     knew that the objects were invalid.  This has been changed; the parser
  1773.     now simply uses the cantReach message for *each* object that is
  1774.     visible and matches the vocabulary, using the usual multiple-word
  1775.     format:
  1776.         bowling trophy:  You'll have to open the glass case first.
  1777.         tennis trophy:  You'll have to open the glass case first.
  1778.  
  1779.     This new behavior should have no effect on your game code.  Note
  1780.     that it is entirely irrelevant if you use the new verb.cantReach
  1781.     feature described above.
  1782.  
  1783.   - The compiler sports a new case sensitivity option.  By default,
  1784.     the compiler is case-sensitive, as it has been in past versions.
  1785.     However, the new toggle option allows you to change this.  Specify
  1786.     -case- to turn off case sensitivity (the default is -case+).  Note
  1787.     that this is a toggle option, so simply using -case will reverse
  1788.     the current case sensitivity (which is useful if you use a CONFIG.TC
  1789.     file that sets a non-default case option).  When case sensitivity
  1790.     is turned off, the compiler will treat upper- and lower-case letters
  1791.     in symbols (names of objects, properties, functions, and local
  1792.     variables) as equivalent.  Hence, foodItem = fooditem = FoodItem,
  1793.     and so on.
  1794.  
  1795.     If you create a pre-compiled header with -w, any compilation which
  1796.     reads that binary header with -l will use the same case sensitivity
  1797.     as was in effect when the header was pre-compiled.  The -case option
  1798.     is ignored when a pre-compiled header is loaded.  Likewise, the
  1799.     debugger uses the same case sensitivity that was in effect when the
  1800.     game being debugged was compiled.
  1801.  
  1802.   - The debugger's command set is no longer case-sensitive (hence,
  1803.     BP = Bp = bP = bp).
  1804.  
  1805.   - adv.t has a new darkVerb class.  This is a type of deepVerb that
  1806.     can be used in the dark.  The darkroom class has been changed to
  1807.     accept any verb of class darkVerb in its roomAction and roomCheck
  1808.     methods.  The travel verbs and system verbs have all been made
  1809.     darkVerb objects, so darkroom only needs to check the single
  1810.     verb type.
  1811.  
  1812.     In a related change, turnOnVerb and dropVerb have been changed to
  1813.     be darkVerb objects, allowing the player to turn on an object or
  1814.     drop it in the dark.  The verDoTurnon method in switchItem has
  1815.     been changed so that it checks to see if the player is in a dark
  1816.     room; if so, the item can only be turned on if the player is already
  1817.     carrying the object.  This allows the player to turn on a light
  1818.     source that's already being carried, but doesn't allow the player
  1819.     to pick up a light source in a dark room.
  1820.  
  1821.   - The compiler issues a new warning message (TADS-452) if you
  1822.     use the same verb with two deepverb objects.  The parser can only
  1823.     choose a single deepverb object for any verb typed by the player,
  1824.     so you should never define the same 'verb' vocabulary word in more
  1825.     than one deepverb object.  In past versions, the compiler did not
  1826.     flag this as a warning.
  1827.  
  1828.   - Several improvements have been made for numbers in player
  1829.     commands.  First, multiple numbers are now allowed in a single
  1830.     commands; for example, the player can now say "press 1, 2, 3,
  1831.     4 on keypad," and the numbers are set in numObj.value, one by
  1832.     one.  Second, the sdesc, adesc, and thedesc properties of
  1833.     basicNumObj have been improved to show the number's value.
  1834.  
  1835.   - Similar improvements to those for numbers have been made for
  1836.     strings.  Multiple strings are now allowed in a single command,
  1837.     and the basicStrObj properties sdesc, adesc, and thedesc have
  1838.     been improved to show the string's value.
  1839.  
  1840.   - specialWords has been enhanced.  First, in past versions, if a
  1841.     game contained multiple specialWords statements, the word lists
  1842.     were additive -- all specialWords lists were used in the game.
  1843.     This has been changed so that each specialWords statement replaces
  1844.     any previous list in effect.  However, you now can explicitly add
  1845.     to the specialWords list, without removing any of the previously
  1846.     defined words, by using "modify specialWords".  When you use
  1847.     'modify', you can use nil in any word slot if you do not wish
  1848.     to add any words for that slot.  Finally, you can use "replace
  1849.     specialWords" to make the replacement explicit; this is the default
  1850.     if neither 'modify' nor 'replace' is specified, but the compiler
  1851.     will now issue a warning (which is harmless) if you use specialWords
  1852.     without 'replace' or 'modify' and a previous specialWords list is
  1853.     already in effect.
  1854.  
  1855.   - The words "one" and "ones" (or their equivalent for your game,
  1856.     if you've changed them with specialWords) are no longer considered
  1857.     reserved words within normal commands.  This allows you to use
  1858.     objects such as a "one dollar bill"; previous versions rejected
  1859.     player commands containing "one" or "ones".  These words are now
  1860.     considered special only during the parsing of a response to a
  1861.     disambiguation question, when they can be used in place of a
  1862.     noun ("the red one" can be used in answer to "Which book do you
  1863.     mean...").
  1864.  
  1865.   - The hider class has been changed so that 'it' or 'them' (as
  1866.     appropriate) are set to the object or objects found when
  1867.     searching the hider.
  1868.  
  1869.   - The verDoPutIn and verDoPutOn messages in thing and surface
  1870.     (respectively) have been improved for the somewhat obscure case
  1871.     of attempted circular containment - that is, putting an object
  1872.     into a container, when the container is already in the first object
  1873.     (either directly or by virtue of being inside another object which
  1874.     is inside the first object, or inside an object which is inside an
  1875.     object which is inside the first object, and so on).  The new
  1876.     method thing.circularMessage(iobj) is called in these cases to
  1877.     display an appropriate message; the default implementation of this
  1878.     method displays the complete list of containers of the direct
  1879.     object out to the indirect object.  For example, if you have a
  1880.     crate which contains a box, and you try to "put crate in box",
  1881.     the message is "You can't put the crate in the box, because
  1882.     the box is already in the crate."
  1883.  
  1884.   - The default doTake method has been changed to include the weight
  1885.     of any contents of the item being taken, in addition to the item
  1886.     itself, to determine if the actor's inventory is too heavy.
  1887.     The old doTake method only included the weight of the object
  1888.     being taken, not counting its contents.
  1889.  
  1890.   - The Actor class has been changed to add a travelTo method.  You
  1891.     can now move any actor (Me included) with travelTo(destination).
  1892.     The default Actor.travelTo method moves the actor; it announces
  1893.     the departure of the actor if the actor was in the same location as
  1894.     Me before leaving (and the location is lit); and it announces the
  1895.     arrival of the actor if the actor is moving into the same location
  1896.     as the player (and the location is lit).  The departure message
  1897.     is generated with a call to self.sayLeaving, and the arrival
  1898.     message is generated with self.sayArriving.  The default versions
  1899.     of these methods simply display "Thedesc leaves the area" and
  1900.     "Thedesc enters the area", respectively; you can override these
  1901.     methods if a more specific message is desired.
  1902.  
  1903.   - When modifying a class object with 'modify', the modified object
  1904.     was not a class unless the 'class' keyword was included with the
  1905.     'modify' statement ("modify class foo" rather than "modify foo").
  1906.     This has been corrected; a modified class is still a class.
  1907.  
  1908.   - outhide(true) now returns a status indicator, which is a value that
  1909.     can be used in a subsequent call to outhide() to return output
  1910.     hiding to the state it was in before the outhide(true).  This
  1911.     allows you to nest text hiding.  When you use the nested form
  1912.     (which you do simply by using the return value of outhide(true) as
  1913.     the parameter - in place of nil - to the subsequent call to outhide()),
  1914.     the value returned by the second outhide() indicates whether any
  1915.     text output occurred ONLY BETWEEN THE NESTED CALLS.  For example:
  1916.     
  1917.      old_stat1 := outhide(true);
  1918.      "This is some hidden text.";
  1919.      old_stat2 := outhide(true);
  1920.      // write no text here
  1921.      new_stat2 := outhide(old_stat2);
  1922.      new_stat1 := outhide(old_stat1);
  1923.  
  1924.     Because outhide(old_stat2) indicates whether any output occurred
  1925.     during the NESTED outhide(true), new_stat2 = nil.  However, new_stat1
  1926.     = true, since output occurred after the first outhide(true).  Consider
  1927.     another sequence:
  1928.  
  1929.      old_stat1 := outhide(true);
  1930.      // write no text here
  1931.      old_stat2 := outhide(true);
  1932.      "This is some hidden text.";
  1933.      new_stat2 := outhide(old_stat2);
  1934.      new_stat1 := outhide(old_stat1);
  1935.  
  1936.     In this case, both new_stat1 and new_stat2 will be true, because
  1937.     hidden output occurred within both nested sections.
  1938.  
  1939.     The general form of a nested hidden output section looks like this:
  1940.  
  1941.          {
  1942.             local original_hide_stat;
  1943.         local nested_stat;
  1944.  
  1945.             original_hide_stat := outhide(true);
  1946.             // do whatever you want to do while output is hidden
  1947.         nested_stat := outhide(original_hide_stat);
  1948.      }
  1949.  
  1950.     Now nested_stat will indicate whether any output occurred during
  1951.     the nested outhide() - that is, between the outhide(true) and
  1952.     the outhide(original_hide_stat).  In addition, output hiding will
  1953.     be returned to the same state it was in prior to the original
  1954.     outhide(true).
  1955.  
  1956.   - The random number generator has been improved.  Many people have
  1957.     complained about the many undesirable properties of the old
  1958.     generator, especially when small upper limits were used.  The
  1959.     interface to the new random number generator is the same as
  1960.     before - call rand(upper_limit), which will return a uniformly
  1961.     distributed random number from 1 to upper_limit, inclusive.
  1962.  
  1963.     Note that the old random number generator will still be used if
  1964.     you don't call randomize().  This allows test scripts (which require
  1965.     a fixed sequence of random numbers in order to be repeatable) that
  1966.     were written with older versions to continue to operate unchanged.
  1967.     If you want numbers from the improved generator, be sure to call
  1968.     randomize().
  1969.  
  1970.   - When 'modify' was used on an object, the compiler sometimes did
  1971.     not correctly apply the original object's vocabulary and location
  1972.     to the new object.  This has been corrected.
  1973.  
  1974.   - restore() and undo() have been changed so that they always cancel
  1975.     all pending commands on the command line.  In the past, if the
  1976.     player typed several commands, and something happened (such as
  1977.     the player character dying) during one of the commands that led to
  1978.     an undo() or restore(), the remaining commands were still
  1979.     executed.  This has been fixed.
  1980.  
  1981.   - If you explicitly set an object's location to nil in its object
  1982.     definition, and the object inherited a location from a superclass,
  1983.     the system incorrectly placed the object in the contents list of
  1984.     the object named in the location inherited from the object's
  1985.     superclass.  This has been corrected.
  1986.  
  1987.   - "abort" can now be used within a daemon or fuse, and the
  1988.     expected behavior will occur.  In the past, "abort" within
  1989.     a fuse (or daemon) merely exited from the current fuse,
  1990.     but the remaining fuses and daemons were still executed.
  1991.     Now, "abort" will cause the entire turn to end; no more
  1992.     fuses or daemons will be executed on the current turn.
  1993.  
  1994.  
  1995. 2.1.1  09/09/93  enhancements
  1996.  
  1997.   - You can now access objwords(1) while deciding whether to use a
  1998.     default direct object in doDefault.  This is useful mostly if
  1999.     you want to prevent players from being able to use "all" with
  2000.     certain verbs, but still want to generate a default direct object
  2001.     for the verbs.  To do this, you can detect when objwords(1) = ['A']
  2002.     ('A' is the parser's internal code for "all", which saves you the
  2003.     trouble of checking for "everything" and shorter abbreviations as
  2004.     well as "all"):
  2005.  
  2006.       doDefault(actor, prep, iobj) =
  2007.       {
  2008.           if (objwords(1) = ['A'])
  2009.           {
  2010.               global.allMessage := 'You can\'t use "all" with this verb.';
  2011.           return [];
  2012.           }
  2013.  
  2014.       /* your normal default object code goes here */
  2015.       }
  2016.  
  2017.     If you wish, you can also suppress the default message that the
  2018.     parser will generate ("I don't see what you're referring to").
  2019.     To do this, you'll have to write your own parseError() function
  2020.     and detect when an "all" violation has occurred (cleverly using the
  2021.     global.allMessage, which we set above for this purpose):
  2022.  
  2023.       parseError: function(str, num)
  2024.       {
  2025.           // if there's an allMessage waiting, use it instead of the default
  2026.           if (global.allMessage <> nil)
  2027.       {
  2028.           local r;
  2029.  
  2030.           r := global.allMessage;
  2031.           global.allMessage := nil;
  2032.           return r;
  2033.       }
  2034.       else
  2035.           return nil;
  2036.       }
  2037.     
  2038.   - The compiler's error message format has been changed slightly
  2039.     to work better with editors and workbench programs that scan error
  2040.     logs to go to lines with errors.  The format is now:
  2041.  
  2042.         file(line): error TADS-xxxx: message
  2043.  
  2044.     For example:
  2045.  
  2046.         deep.t(1151): error TADS-300: expected colon
  2047.  
  2048.  
  2049.   - The parser now accepts sentences of the form VERB PREP IOBJ DOBJ,
  2050.     where the PREP is *not* part of the verb.  For example, GIVE TO THE
  2051.     MAN THE BALL.  This change has two benefits.  First, while this
  2052.     type of sentence is not common in English, some other languages
  2053.     allow this type of phrasing, so the parser is now somewhat more
  2054.     adaptable to non-English languages.  Second, this allows for
  2055.     object defaulting and command completion when specifying just the
  2056.     indirect object, which was not possible before.  For example, if
  2057.     the player types ASK FOR A BEER, the parser will be able to attempt
  2058.     to provide a default (if one is available), or at least ask for the
  2059.     direct object.  Previous versions would simply say "I don't understand
  2060.     that sentence."  Note that the parser still attempts to combine the
  2061.     verb and preposition into a single phrase; the new action happens
  2062.     only when the verb and preposition don't go together (that is, they
  2063.     haven't been defined together as a "verb =" property of a deepverb).
  2064.     For example, suppose that a line like this appears in a deepverb:
  2065.  
  2066.         verb = 'pick up'
  2067.  
  2068.     In this case, PICK UP THE BOX will use THE BOX as the direct object,
  2069.     just as in previous versions.  Only when the verb-preposition combination
  2070.     is not specifically defined in a verb will the new phrasing be used.
  2071.  
  2072.   - When no preposition is specified between the direct and indirect objects,
  2073.     the parser will now evaluate a new property, nilPrep, in the deepverb
  2074.     object.  This property should return the preposition object that should
  2075.     be used as the preposition between the objects.  Previous versions of
  2076.     TADS always looked for an object that defined the word 'to' as a
  2077.     "preposition =" property.  While 'to' is almost always the correctly
  2078.     the correct preposition to substitute in English, it's obviously the
  2079.     wrong word in other languages; furthermore, the correct word in other
  2080.     languages is sometimes a function of verb.  If no nilPrep property is
  2081.     defined for the deepverb, the parser will still use the object whose
  2082.     "preposition =" property matches the word 'to'.
  2083.  
  2084.   - The class transparentItem in adv.t has been modified so it works better
  2085.     when you define an object that inherits from both transparentItem and
  2086.     container or openable.  First, an ldesc has been added so that the
  2087.     contents of a transparentItem are listed by default with the ldesc.
  2088.     Second, the "look in" command now works on a transparentItem.  In
  2089.     addition, the openable class has been changed so that the "look in"
  2090.     command can be used when an openable is also a transparentItem, even
  2091.     when the openable is closed (because you should be able to see the
  2092.     contents of a transparentItem regardless of whether it's open or closed).
  2093.     Thanks to Ron Hale-Evans for pointing out this problem and finding the
  2094.     solution.
  2095.  
  2096.  
  2097. Please consult TADSV200.DOS (available on the High Energy BBS) for
  2098. information on earlier releases.
  2099.