
Summary of Platypus release 4+
==============================

    Send questions, comments, and bug reports to platypushome@yahoo.com.

    This documentation assumes at least a basic familiarity with Inform and
    its standard library. It primarily covers differences between the standard
    library and Platypus. The Reference provides a somewhat more thorough 
    listing of attributes, properties, and so forth.

    Conventions followed in this document:

      Attribute:          -light-
      Class, or member:   [Actors]
      Global variables:   =actor=
      Obsolete:           lockable*
      Property:           +description+
      Property routine:   +parse_name()+
      Routine:            InDark()
      Rewind:             [<<]

    Of course, you should not type any of these symbols when actually using
    these identifiers, except for the underscores and the parentheses after a
    routine call. (And you can't use obsolete things at all.)

    [Square brackets] also indicate optional parameters in routine calls.

    I apologize in advance for any omissions or inaccuracies, however, for
    legal reasons I disavow any and all responsibility for any resulting
    apocalyptic mayhem.


-1. Acknowledgements

    My gratitude to everyone who has given me feedback on Platypus, and
    specifically John Bytheway, Nate Cull, Dmitry Ferentsev, Aponar Kestrel,
    Michael A. Krehan, Andrew MacKinnon, Iain Merrick, A. O. Muiz, Taro
    Ogawa, Dan Schmidt, and especially Daniel Barkalow and Gary Poster.
    
    Andrew Plotkin performed the dark, ancient rituals which summoned forth
    the mighty Glulx and created the biplatform library. He also created Glk,
    but I'll try to forgive him.

    And to Graham Nelson, for Inform and its standard library, without which
    we'd all be using TADS. Ewwwww.
    
    We now return you to your regularly scheduled documentation.
    

0. Contents

     1. Attributes
     2. Properties
     3. Rooms
     4. Actors and Actions
     5. Containers
     6. Finding Paths
     7. Tasks and Footnotes
     8. Scoring
     9. Gizmos and Cogs
    10. The Runtime Dictionary
    11. Useful Routines
    12. Parsing
    13. List-writing
    14. New and Modified Commands
    15. Things Not Yet Covered


1. Attributes

    a) Some attributes have been eliminated:

        Attribute               Instead,
        ---------               --------
        absent*                 move the object out of FloatingHome, or
                                create it in Storage
        door*                   just give it a +door_to+ property
        lockable*               just give it a +with_key+ property
        scenery*                use -concealed- and -static-
        scored*                 give it a +points+ property

    b) Some have been added:

        Attribute               This object...
        ---------               --------------
        -activedaemon-          has a running daemon.
        -activetimer-           has a running timer.
        -hider-                 can hold things -under- it.
        -inside-                is inside its parent.
        -known-                 is known to the player.
        -quotedmode-            has first-person action output.
        -secret-                is permanently unknown to the player.
        -upon-                  is on top of its parent.
        -under-                 is underneath its parent.

    c) The enterable* attribute has become a property routine, 
       +allow_entry()+. See below.

    d) A complete list of attributes can be found in the Reference.

2. Properties

    a) All of the direction properties (n_to*, w_to*, etc.) have been replaced
       by +dirs+ (see below.)

       Three other properties have also been removed: life* (use +respond()+
       or +respond_indirect()+ instead), capacity* (see +carrying_capacity+,
       +inside_capacity+, +upon_capacity+, and +under_capacity+ below), and
       door_dir*, which is not needed.

    b) Many have been added:

        Property                Use
        --------                ---
        +adjective+             Holds adjectives (dictionary words) describing
                                object. (See also section 12g below.)

        +allow_entry()+         Called with -upon-, -inside-, or -under- as a 
                                parameter. Should return true if the object
                                can be entered in the specified way.

        +allow_push()+          Called with a direction object parameter, 
                                should return true if object can be pushed out 
                                that exit.

        +allow_take()+          (For animates) Can return true to allow this 
                                creature to be held.

        +carrying_capacity+     (For [Actors]) how much can be carried.

        +disambiguate()+        Called when parser is trying to choose an 
                                object based on player input. Takes no 
                                parameters, but can look at global 
                                =action_to_be=.

        +dirs+ / +dirs()+       (For [Rooms]) This property, which can be an 
                                array or a routine, replaces the direction
                                properties (see section 3c below).

        +perform()+             (For [Actors]) Called to cause the actor to
                                perform the specified action.

        +fpsa+                  (For [Rooms]) Used by FindPath() (see section 
                                6 below).

        +guide_path()+          (Primarily for [Actors]) called when 
                                FindPath() is about to look for a path for
                                this object. By setting +fpsa+ property of
                                [Rooms] to 0, can exclude them from
                                consideration.

        +inside_capacity+       (For containers) How much this object can 
                                hold -inside-.

        +join_scope()+          Used by [ScopeCogs] (see below).

        +location+              (For [Actors]) current location (see below).

        +messages()+            (For [Actors] or [MessageCogs]) Provides 
                                action messages. (see section 4f below).

        +moveYN()+              (For floating objects) Takes a room as a
                                parameter. If provided and returns false, is 
                                not present in the given room (in spite of
                                that room's +shared+).
                                
                                Note that as of release 4, floating objects
                                are no longer moved around, making the name
                                of this property archaic.

        +points+                Number of points awarded for entering room,
                                holding object, or accomplishing task.

        +possessive+            Holds possessives (dictionary words) 
                                describing possessed (held) objects (e.g. 
                                'fred^s').

        +shared+                (For [Rooms]) list of floating objects present 
                                here.

        +startup()+             Called when the game first starts. Used to 
                                initialize this object (or anything else).

        +upon_capacity+         (For supporters) How much this object can 
                                hold -upon- it.

        +under_capacity+        (For hiders) How much this object can hold 
                                -under- it.

        +words()+               Can be used instead of the +name+ and 
                                +adjective+ properties. Called with a word
                                and should return 0 if it does not match
                                the object, +name+ if it is a name of the
                                object, and +adjective+ if it is an adjective.

    c) There are ten reaction properties, organized into groupings based on
       when they are called, and for what objects:

        Stage 1                   Stage 2             Stage 3
        -------                   -------             -------
        meddle_early              (Action is          meddle
        respond_early              determined to be   respond
        respond_early_indirect     possible)          respond_indirect

        Stage 4
        -------
        (Action occurs)

        Stage 5                   Stage 6             Stage 7
        -------                   -------             -------
        meddle_late               (Action result      meddle_late_late
        respond_late               is printed)        (always called)
        respond_late_indirect

       The four meddle properties are called for all objects in scope.
       The respond properties are called for the direct object, and the
       respond...indirect properties are called for the indirect object.

       When an action is invoked, the following sequence is observed. The
       library stops executing the action immediately when any of the routines
       returns true, jumping to step 17:

       1. GamePreRoutine() is called (if provided).

       2. If the =actor= is the =player=, the player's +orders()+ routine is 
          called (if provided).

       3. +meddle_early()+ routines are called for all objects in scope. (This 
          is equivalent to react_before*.)

       4. +respond_early()+ is called for the direct object (if any). (This is 
          equivalent to before*).

       5. +respond_early_indirect()+ is called for the indirect object (if 
          any).

       6. The library determines whether the action is possible (for example, 
          testing whether ##Take is being called for a -static- object).
          Implicit actions may be invoked at this point. If the action is not 
          possible, a suitable message is printed and the library stops here.

       7. GameOnRoutine() is called (if provided).

       8. +meddle()+ routines are called for all objects in scope.

       9. +respond()+ is called for the direct object (if any).

      10. +respond_indirect()+ is called for the indirect object (if any).

      11. The library performs the default behavior for the action. For 
          example, moving an object to the =actor= for a ##Take action.

      12. +meddle_late()+ routines are called for all objects in scope. (This 
          is equivalent to react_after*.)

      13. +respond_late()+ is called for the direct object (if any). (This is 
          equivalent to after*.)

      14. +respond_late_indirect()+ is called for the indirect object (if 
          any).

      15. GamePostRoutine() is called. If =deadflag= is set by this point,
          the library stops here.

      16. The library prints the appropriate default (or +messages()+ 
          provided) message for the completed action.

      17. +meddle_late_late()+ routines are called for all objects in scope.

    d) Some less-used non-additive properties have been made individual 
       rather than common.

    e) You may have any number of active timers and daemons. The -activetimer-
       and -activedaemon- attributes indicate that an object's timer and/or
       daemon are running. (Thus, "give thing activedaemon" is the same as
       calling StartDaemon(thing).)

    f) add_to_scope has been made additive.

    g) A more complete list of properties can be found in the Reference.


3. Rooms

    a) Rooms should be ofclass [Rooms].

    b) [Rooms] can now be in scope. +name+ and +adjective+ properties should
       contain the actual names and adjectives of the room. Note that
       +respond_early()+ and +respond_late()+ affect only actions performed on
       the room itself (unlike the before* and after* properties of the
       standard library). However, you can use +meddle_early()+, +meddle()+,
       and +meddle_late()+ to trap any action in the room, even if the room is
       not in scope (e.g. in the dark, or when the character is inside an 
       opaque container).
       
       Declaring constant DONT_SCOPE_ROOMS prevents rooms from being placed in
       scope except for GO TO and meddle-property reasons.

    c) Direction properties such as n_to* and sw_to* are gone. Use the +dirs+ 
       property instead, which takes two forms:

       As an array, +dirs+ contains a list of one or more direction objects
       (ndir, sedir, outdir, etc.), each of which is followed by the room
       object in that direction (or a door object, or a string). For example:

        dirs udir At_Complex_Junction
             wdir In_Bedquilt
             edir At_Witts_End;

       You can also list more than one direction object before a particular
       location:
       
        dirs ndir udir Foyer
             edir Narrow_Space;
             
       In the above example, both ndir and udir lead to Foyer.

       As a routine, +dirs()+ accepts one parameter, a direction object, and
       returns a room, 0, 1, or a string. If 1 is returned, it is assumed that
       the situation has been handled and the library silently cancels the
       action. 0 results in a "can't go that way" message (either generic or
       provided by +cant_go+). If a string is returned, it is printed if and
       only if the =player= is actually trying to go that way (and not some
       other actor). Make sure to check =finding_path= and =actor= when
       appropriate (see sections 4c and 6a). Example:

         dirs [ d;
             if (d == udir) return At_Complex_Junction;
             if (d == wdir) return In_Bedquilt;
             if (d == edir) return At_Witts_end;
         ];

    d) Darkness is no longer handled by moving the =player= object into the 
       "thedark" object. If the player is sitting in a teacup on the mantel in
       the library when the lights go out, the player is still sitting in a
       teacup on the mantel in the now-darkened library rather than hovering
       in an inky void nestled somewhere amidst the roots of Yggdrasil. The
       usual constraints of darkness still apply. InDark(player) will return 
       true if the player is in darkness.


4. Actors and Actions

        The ghost who returns to haunt his murderer need not be surprising;
        most of us play interactive FICTION game as a representation of
        reality.

                                                        - Markovian insight


    a) If you do not want to use the standard player object, set the constant
       PLAYER_OBJECT to your new player object prior to #including "Middle.h".
       This is not absolutely necessary; you can change the =player= at any
       time via ChangePlayer(). Setting the PLAYER_OBJECT constant to some
       other object has the effect of preventing the default player object
       from being compiled at all.

    b) Actors should be ofclass [Actors]. An "actor" is any character (that
       is, object) who will perform actions via +perform()+ (see following).
       The [Actors] class also provides the properties an object must have if
       you want to call FindPath() for it (see section 6). Otherwise, it is
       more efficient to simply use -animate-.

    c) Non-meta verbs can be used by any actor. To have an actor perform an 
       action call: xxxx.perform(##Action, noun, second), where xxxx is, of
       course, the actor. If you will be making action calls for NPCs, be sure
       to keep that in mind when programming +respond()+ routines and the
       like, since these are triggered no matter who the current actor is.
       Check the global =actor= to see who is performing the action.

    d) Take player proximity into consideration when an NPC is performing an 
       action. That is, you will not want to print "Fred opens the can of 
       peanut brittle, and a snake leaps out!" in a +respond()+ routine if
       Fred is in the attic and the player is in the basement. Use
       TestScope(Fred) to see if the player can see Fred. Standard action
       messages ("Fred takes the widget.") are automatically muted in such
       circumstances.

    e) +location+ is now a property of [Actors], NOT a global variable. Look, 
       but don't touch. Use MoveTo(actor, new location[, position]) to
       relocate [Actors] (or anything else, for that matter).

       Exception: you can define an actor with +location+ already set to the
       initial position of an actor, but remember to give the actor the
       -upon-, -inside-, or -under- attribute if appropriate. You can
       presupply any object as an initial +location+, but once the game is
       underway, +location+ will always hold the room the actor is in (and
       not, for instance, the chair she is sitting in). This is the same way 
       that the location* global variable works in the standard library.

    f) [Actors] have a +messages()+ property which is responsible for the text
       displayed when an actor performs an action. This works just like the
       +messages()+ property of a [MessageCogs] object (see section 9d) except 
       that it only applies to that actor. Generic, default messages are
       provided by the [Actors] class for standard actions. However, the
       *player's* default messages are currently still stored in the
       LanguageLM routine in English.h. (Actors::messages() returns false if
       the actor is the player, which causes the library to "fall down" to the
       LanguageLM() routine.)

    g) When creating your own actions, take advantage of the +messages()+ 
       property and call ActionMessages(action[, number[, object]]) in order 
       to print the correct message based on the current actor. Example:

        [ WhistleSub;
            if (OnRoutines()) rtrue;
            ActionMessage(##Whistle, 1);
        ];

        Actors Fred "Fred"
        with name 'fred',
             messages [;
                Whistle: "Fred whistles that song you can't stand.";
             ];

       This system ensures that no message will be printed if the action takes
       place where the player cannot perceive it. To provide a default 
       message, either create your own subclass of [Actors], or a 
       [MessageCogs] object (see section 9d below).

    h) Actions such as ##Scream, which are not dependant on sight, can be
       perceived (that is, will have their messages printed) and reacted to (via
       +meddle()+, etc.) even in darkness.

    i) Strings printed by +messages()+ properties can make use of certain 
       codes by enclosing them between #s. For example:

         with
             messages [;
                 Glorp: switch(lm_n) {
                     1: "#Actor# glorp#s# #obj# with #second#.";
                     2: "#Obj# #is# not glorpable.";
             ];

       The codes are as follows:

         #actor#   : If the =actor= is not the =player=, and the =actor= 
         or #a#      has not been named yet this turn, prints the name of the
                     =actor=. Otherwise, prints an appropriate pronoun.

         #his# or #its#  : Prints possessive pronoun fitting named object. 
                           (The "named object" is the last object specified by
                           an "#actor#", "#obj#", "#noun#", or "#second#"
                           print code. If no such code has been used, the
                           named object defaults to the =actor=.)

         #him# or #ito#    : Prints objective pronoun fitting...

         #he's# or #it's#    : Print contraction...

         #himself# or        : Prints reflexive pronoun...
         #itself#

         #is# or #are#,      : Print verb form...
         #has# or #have#

         #s#, #es#           : Prints verb ending if appropriate, as in 
                               "take#s#" or "toss#es#".

         #obj# or #o#    : Prints (the) lm_o, that is, the object that was
                           passed to ActionMessage().

         #noun# or #n#,  : Print (the) noun or (the) second.
         #second# or #d# 

         #b#, #r#, : Activate bold, roman, underline, and fixed-width
         #u#, #f#    font modes.

       Note that if a code begins with an uppercase letter, the resulting 
       output will also be capitalized.

       N.B.: In some cases, the last named object may not be the one you want. 
       For example, the message:

         "#Actor# #has# to put #second# down before #actor# can put things on
         top of #ito#."

       might result in:

         You have to put the tray down before you can put things on top of
         yourself.

       the last named object before #ito# was the actor, resulting in the
       above glitch. To get around this, you can change the "named object"
       without actually printing its name by extending the print code with
       "-a" for actor, "-o" for object (lm_o), "-n" for noun, or "-s" (or
       "-d") for second. So, the above message could be changed to:

         "#Actor# #has# to put #second# down before #actor# can put things on
         top of #ito-d#."

       resulting in:

         You have to put the tray down before you can put things on top of
         it.

       because the named object is changed to =second= before the code is
       translated.

       These extensions cannot be used with the "naming" codes: #actor#,
       #obj#, #noun#, and #second#. Or rather, -o and -s can be used, but they
       do something different.

       The library performs pronoun substitution on naming codes, for example,
       substituting "He" or "She" for #Actor# when the actor has just been
       named. In order to use the correct pronoun, it is necessary to know
       whether the thing named is subject or object. That is, whether to use a
       nominative pronoun such as "he" or an accusative one, such as "him". By
       default, a nominative pronoun is used if the print code begins with an
       uppercase letter (and is therefore presumably at the beginning of a
       sentence), and an accusative pronoun otherwise. This will not always 
       work:

         But #actor# can't do that.

       might yield

         But him can't do that.

       To fix this, there are three code extensions that can be used with the
       naming codes: -s for subject (forcing nominative pronouns), -o for
       object (forcing accusative or reflexive pronouns), and -x to prevent
       pronoun substitution altogether, always printing the name of the
       object. (Exceptions: if the object is the player and player_perspective
       is not THIRD_PERSON, or the object is the =actor= and has -quotedmode-,
       pronoun substitution will still take place.) So:

         But #actor-s# can't do that.

       If you wish to use print codes in text other than that printed by 
       messages, you can call HoldX(), print the text, and then call PrintX().
       Alternately, you can call PrintX([string]). Calls to HoldX() are not
       nested; once PrintX() is called, the text is no longer being buffered.
       
       Alternately, you can call PrintX(string[, object]) to print the given
       string using print codes. If object is supplied, it signifies the object
       to use for #object# and related codes.

       If you actually need to print an # in PrintX()-filtered text, you can
       do so by doubling it: ##.

       If you need to use accented characters in PrintX()-filtered text, you
       must use a slightly different syntax, always beginning with &:

       &<  = put a circumflex on the next letter: a,e,i,o,u,A,E,I,O,U
       &'  = put an acute accent on the next letter: a,e,i,o,u,y,A,E,I,O,U,Y
       &`  = put a grave accent on the next letter: a,e,i,o,u,A,E,I,O,U
       &:  = put a dieresis on the next letter: a,e,i,o,u,A,E,I,O,U
       &c  = put a cedilla on the next letter: c,C
       &-  = put a tilde on the next letter: a,n,o,A,N,O
       &/  = put a slash on the next letter: o,O
       &o  = put a ring on the next letter: a,A

       &ss              = German sz
       &<< &>>          = continental European quotation marks
       &ae &AE &oe &OE  = ligatures
       &th &Th &et &Et  = Icelandic accents
       &LL              = pound sign
       &!!              = inverted (Spanish) exclamation point
       &??              = inverted (Spanish) question mark

       &ct      = ^         ct is for "caret"
       &bs      = \         bs is for "backslash"
       &at      = @         at is for "a (squiggly) thing"
       &td      = ~         td is for "tilde"
       &&       = &

       Note that the accented character codes should *not* be placed in #...#.

       If a code after & is not recognized, an asterisk is printed instead. If
       the code is recognized, but can't be printed, a question mark is
       printed.

    j) The +allow_take()+ property, if provided by an [Animates] object, will 
       allow the current =actor= to pick the animate up if it returns true.


5. Containers

        In any coherent world, things are generally where they are not,
        there is a sort of theme park maintained by Witt & Co.

                                                        - Markovian insight


    a) Objects can now have things inside, on top of, and underneath them,
       possibly all three at the same time. The -upon-, -under-, and -inside-
       attributes indicate which position an object is in. However, objects
       which are merely in a room (i.e., on the ground) have none of these,
       nor do objects which are carried by an actor. Remember that -upon- and 
       -on- are two completely different attributes.

    b) If an object is a child of another object (container) which is neither 
       a room nor ofclass [Actors], and it does not have an appropriate 
       attribute (-upon-, -inside-, or -under-), it is not in scope, and will 
       be completely inaccessible. When creating objects inside (or upon or 
       under) other objects remember to give them the appropriate attribute. 
       (However, see 11a).

    c) The enterable* attribute has been replaced by the +allow_entry()+ 
       property. If provided, it will be called with the -upon-, -inside-, or
       -under- attribute. It should return true to indicate that the object
       can be entered in the specified fashion. It will only be called with an
       attribute appropriate to any containment class(es) it belongs to, so
       the parameter can be ignored if, for example, the object is a
       -supporter- but not a -container- or -hider-. If only certain [Actors]
       can enter the object, it is best to return true here and handle
       individual exclusions via +respond()+.

    d) This space intentionally left blank.

    e) Items which are -under- hiders do not show up in room descriptions 
       unless the -hider- is -transparent-.

    f) If a -hider- is picked up, anything -under- it is left behind.


6. Finding Paths

    a) The FindPath(starting room, destination, actor[, maximum moves]) 
       routine will find the shortest route between two [Rooms] for the given
       actor. The actor's +guide_path()+ property will be called first. By
       setting the +fpsa+ property of [Rooms] to 0, it can exclude them from
       consideration (so they won't be allowed in the path). If the routine
       returns false, no path could be found. The =finding_path= global will
       be set to the actor for whom the path is being found.

       Since this routine "probes" exits, it is essential to check the
       =finding_path= global in your +dirs()+ methods to prevent spurious
       messages or worse from happening for seemingly no reason. For example,
       if trying to go through a particular exit causes a trap to go off, you
       must check the =finding_path= global to make sure the trap is not
       triggered by FindPath().

    b) You can return strings from +dirs()+ methods rather than printing them
       directly. They'll only be printed if the =player= is actually trying to
       go through the exit, and will not be printed for FindPath() or NPCs.

    c) The path found, if any, will be stored in the actor's +path_moves+ (as
       direction objects) and +path_rooms+ property arrays. The number of
       steps in the path will be stored in the actor's +path_length+ property.
       +path_rooms+ contains the expected destinations that result from
       following the directions. Thus, if an NPC is following a path and a
       step does not result in the expected room, then something has gone
       wrong with the path (or the NPC has been blocked).


7. Tasks and Footnotes

    a) To create a task, just make an Object with a +points+ property and 
       a name (not +name+, but a "short name"). Example:

        Object opened_gate "opening the mysterious gate" with points 5;

       Then call Achieved(opened_gate) at the appropriate time.

    b) By giving your task objects +number+ properties, you can control the 
       order in which they appear in the full score. Tasks with lower numbers
       will appear before tasks with higher numbers. Tasks with the same
       number appear in the order in which they are Achieved(). Since +number+
       defaults to 0, you can give a task a negative number to force it to
       appear at the top of the list, for example.

    c) Also see Scoring, below.

    d) If you wish to use footnotes, you must #Include "footnotes.h" and your 
       footnote objects must be ofclass [Footnotes]:

        Footnotes example_footnote "Such as, ~If you shoplift something, they 
            seldom want it back.~";

       Then call Note(example_footnote) or use it as a print specifier:

        print "Peter prattles incessantly about the benefits of living in a 
               nudist colony.",(note) example_footnote;

    e) [Footnotes] provides the +number+ property. If you preset this (to a 
       positive value), you can "fix" the reference numbers for some or all of 
       your footnotes. Otherwise, they are numbered in the order in which they 
       are revealed to the player. (Obviously, you should not assign the same 
       number to more than one footnote. In fact, to do so is to precipitate
       the age of Ragnarok. Or possibly the age of Aquarius. I forget which.
       Better to play it safe.)

    f) If you give FootnoteGizmo -general-, note references will no longer 
       appear once their associated notes have been read.

    g) NOTE (number) or FOOTNOTE (number) are used by the player to view 
       notes.

    h) NOTES will list all of the notes the player has previously read.

    i) The library sets the -general- attribute of [Footnotes] whose 
       references have been displayed, and the -light- attribute of notes that 
       have been read.


8. Scoring

    a) The MAX_SCORE constant has been replaced by the =maximum_score= global.
       This is automatically calculated at startup based on the sum of all
       positive +points+ properties in the game. You can easily override this
       by setting maximum_score = 100 (or whatever) in your Initialise routine
       or a +startup()+ method.

    b) If you give a takeable object a +points+ property (with a number), the 
       player will receive the points upon first holding the item. If you give
       a room a +points+ property, the player will receive the points upon
       first entering the room.

    c) The "finding sundry items" and "visiting various places" lines (which
       appear if the player receives +points+ from a taking an item or
       entering a room with +points+) are treated as tasks numbered 30000 and
       30001, respectively. The +number+ properties of the finding_items and
       visiting_places objects can be changed (e.g. during startup) to
       relocate them in the list of achievements.

9. Gizmos and Cogs

    a) [Gizmos] and cogs are used to extend certain library functions. For
       instance, the SHOWOBJ command can be extended with a [ShowObjCogs]
       object, or the definition of scope can be extended with a [ScopeCogs]
       object.

    b) A [ShowObjCogs] object is used to tell ##ShowObj how to print the 
       values contained in a new property. For example:

        ShowObjCogs
          with
            knows_property [ prop;
                if (prop == bibble) rtrue;
            ],
            print_property [ prop val;
                print (name) val;
            ];

       This cog "teaches" ShowObj that the contents of the (fictional) 
       "bibble" property should be printed as an object.

       +knows_property()+ is passed one parameter, a property, and should
       return true if this cog knows how to display it.

       +print_property()+ is passed two parameters, a property and a value,
       and should print the value in the format appropriate to the property.

    c) A [ScopeCogs] object is used to bring into scope objects which would
       normally be out of scope. For example:

        ScopeCogs
          with
            join_scope [ act;
                if (act == Wibble) PlaceInScope(Wobble);
            ];

       This cog ensures that Wobble is always in scope to Wibble.
       +join_scope()+ is called with one parameter, an object (usually an
       actor) for which scope is being determined. It can use
       PlaceInScope(object) to add things to scope, and if it returns true,
       the cog itself is also put into scope.

    d) A [MessageCogs] object is used to override library messages. This is 
       only useful for the player's messages, or for new actions, because the
       +messages()+ property of an actor will supersede it. It works like the
       standard library's LibraryMessages object, except that you must use the
       +messages()+ property instead of before*. (See section 4f).

    e) Cogs only function when they are in the associated [Gizmos] object. The
       classes listed above are automatically moved into their associated
       [Gizmos] at startup, except those created as children of Storage. You
       can move cogs into and out of their [Gizmos] at any time to enable or
       disable them.

       For instance, if you need to change many of the default messages at a
       certain point in your IF, you could swap [MessageCogs] in and out. The
       [Gizmos] have matching names ending in Gizmo, e.g. MessageGizmo,
       ShowobjGizmo, etc.

    f) [Gizmos] is a class, however there is no "Cogs" class to which all cogs
       belong.

    g) Not all "cog" classes have names ending in "Cogs". For example, 
       the [Footnotes] class provided by the "footnotes.h" add-on is a cog
       class. (That is, all [Footnotes] objects are moved into FootnoteGizmo
       at startup, where they must be in order to be used.)


10. The Runtime Dictionary

    a) If you need to add words to the program's vocabulary while it is 
       running, you can use the Runtime Dictionary for this. Set the constant 
       RUNTIME_DICTIONARY_MAX_WORDS at the start of your program to the 
       maximum number of words you need to add to the dictionary. Then, call 
       AddWord(address, length) where address is the place in memory the word 
       is located (in characters) and length is the number of characters in 
       the word. For example, if you had:

        Array newWord -> 'c' 'a' 'r' 'g' 'o';

       And called:

        AddWord(newWord, 5);

       Then 'cargo' would become a dictionary word. If AddWord returns false,
       there is no room left in the Runtime Dictionary. Otherwise, it returns 
       the address of the new word. Note that if you try to add a word already 
       in the dictionary (initial or Runtime), AddWord returns the address of 
       the existing word.

    b) "nameable.h" makes use of the Runtime Dictionary to allow the player to
       give objects names during play.


11. Useful Routines

    a) SetDefaultObjectPositions() will go over all of the objects in the game 
       and automatically set the -upon-, -inside-, or -under- attribute for
       any object which is in a -supporter-, -container-, or -hider-
       and does not have any of the three attributes set. This is primarily
       intended to be called at startup, and is simply to save the effort of
       manually creating every object with an appropriate attribute.

       If the parent object has more than one containment attribute (e.g.
       -container- and -supporter-), -upon- takes precedence over -inside-,
       which takes precedence over -under-. If the parent object is ofclass
       [Gizmos], [Class], or [Rooms], then no attribute will be set for its
       children even if it also belongs to a containment class.
       SetDefaultPosition(object) works the same way, for the specified object
       only.

    b) MoveTo(object, destination[, position[, look flag]]) is the easiest 
       way to move objects around during play. MoveTo(object, destination)
       will move the given object to the destination object, clear the -upon-,
       -inside-, and -under- attributes, and call SetDefaultPosition(object).
       If the object is ofclass [Actors], its +location+ will be set.

       The position attribute can also be specified as a third parameter, if
       the destination has (or may have) more than one containment attribute. 
       Example: MoveTo(Fred, Freds_bed, upon).

       The "look flag" is only useful if moving the =player=. If 1, no
       location description is printed at all after moving the =player=. If 2,
       the usual description the player would get upon walking into a room
       (which may be shortened if moving to a room that has -visited-) is
       printed. Note that this is a fourth parameter; if you wish to set the
       look flag and do not want to specify a position attribute, use 0 as the
       third parameter, e.g. MoveTo(player, bedroom, 0, 2).

    c) InDark(object) returns true if the given object is in the dark.

    d) OffersLight() is no longer available. It is no longer possible to 
       answer the question of whether an object "offers light" in general or
       not, since it might offer light to something -upon- it but not to
       things -inside- it. You can instead use InDark() (see above), or
       HasLightSource() in conjunction with TestScope(), if necessary.

    e) DrawCompass(x-position) will draw a compass in the status line, which 
       must be at least 3 lines tall. =finding_path= is set to ExitsSub when
       DrawCompass() is checking exits.

    f) IndirectlyContains(object1, object2) returns 0 if object2 is not a 
       descendant of object1 (unless they are the same; see below). Otherwise,
       it returns the position of the child of object1 from which object2 is
       descended. For example:

           table
             !-----------------------!
           book (upon)            box (under)
                                     !
                                  kitten (inside)

       Then IndirectlyContains(table, kitten) == under.

       If the child of object1 has no position attribute, or object1 and
       object2 are the same, then the return value is -1.

    g) Also see the list of routines in the Reference.

12. Parsing

        But it's a lot easier for YOU to parse English than it is for a
        machine, because you've had a lot more practice at it, and you
        started life with a LALR grammar and one-token look-ahead.

                                                        - Markovian insight


    a) Descriptors have been reworked. There is now an entry point routine
       ParseDescriptors() which can be used to add to them. For example:

        [ ParseDescriptor obj wd fl;

            switch(wd)
            {   'sparkling', 'enchanted': if (obj has magic) rtrue;
                default: return -1;
            }
            rfalse;
        ];

       This creates a new descriptor (which is essentially a universal    
       adjective) which applies to any object with the (hypothetical) "magic" 
       attribute. The ParseDescriptor() routine takes three parameters: an 
       object, a word, and a flag. Allow for the flag, but ignore it. The 
       routine should return 1 (or true) if the word is a descriptor which 
       does apply to the object, 0 (false) if it's a descriptor that doesn't 
       apply, and -1 if it doesn't know the word at all. (Study the example 
       above.)

    b) Standard (already-defined) descriptors are 'open'/'opened', 'closed', 
       'worn', 'unworn', 'empty', 'my'/'mine'/'this'/'these', 'your', 
       'that'/'those', 'his', 'her', 'its', and 'their'.

    c) Early descriptors (which must come before the name of the object, not 
       as part of it) are 'one'...'twenty', 'the', 'a'/'an', 'any',
       'all'/'each'/'every'/'everything', 'both', 'another'/'other', and
       'some'.

    d) 'himself', 'herself', 'itself', and 'themselves' are understood in 
       certain contexts, e.g.: ASK SHEILA ABOUT HERSELF is the same as ASK 
       SHEILA ABOUT SHEILA.

    e) +parse_name()+ and ParseNoun() have been changed a bit. They can now
       return a count of adjectives as well as names, by multiplying the
       adjectives by 100 before adding them to the count. Adjectives are
       treated as "weaker" than names when the parser is trying to determine
       which object is being referred to. Also, if you add 10000 to the return
       value, this result is final: the parser will not attempt to match any
       further descriptors to the object, nor allow positional description (as
       described in the next entry).

       For more information on +parse_name()+ or ParseNoun(), see their
       respective entries in the Reference.

    f) Objects can be identified by their location, e.g.:

        >EXAMINE THE BOX ON THE TABLE
        >EXAMINE THE BAG IN THE BOX ON THE TABLE
        >PUT THE MARBLE IN THE BAG IN THE BOX ON THE TABLE

       and so forth.

    g) By default, it is possible to refer to objects using only adjectives
       (although names will take priority over them, so that 'orange' alone 
       might refer to a piece of fruit over an orange bowl, for instance). By 
       setting the constant WEAK_ADJECTIVES, you can prevent this, thus 
       requiring at least one +name+, TADS-fashion.


13. List-writing

    a) WriteListFrom() takes parameters in the form (object, style bitmap, 
       depth, attribute) where attribute is an attribute that is required for
       an object to be listed. (This is used for -upon-, -under-, etc.) If the
       attribute is -workflag-, it will be checked only for depth 0.

    b) The WORKFLAG_BIT is no longer available. Use the attribute parameter
       instead (see preceding entry).

    c) The NEWSTYLE_BIT produces a "new-style" list, e.g.:

        a sack (which is empty) and a box. In the box is a telescope.

       where contents are listed in separate sentences.

    d) The SORT_BIT will cause the list to be printed in alphabetical order by
       the objects' printed names.


14. New and Modified Commands

    a) The GO TO command can be used by the player to be automatically walked
       back to a previously-visited room. Only rooms the player has -visited- 
       are allowed on the path. The CONTINUE command will repeat the last
       GO TO command, and is useful if the player was interrupted while trying 
       to get there. ##GoToRoom only prints a message if called for an NPC. 
       Note that GoToRoomSub() makes use of FindPath() (see section 6).

    b) The EXITS command will give the player a list of exits. =finding_path= 
       is set to ExitsSub when it is checking exits. The list will indicate
       where a given exit goes, if the destination has the -visited-
       attribute.

    c) Inventory and Places lists are now sorted into alphabetical order. This
       can be changed for inventories by altering =invtall_style= and
       =invwide_style=.

    d) (Debugging command) DBDISTANCE will indicate how many moves away a 
       given room is, using the shortest path FindPath() can produce, e.g.:

        >DBDISTANCE LIBRARY
        3 rooms

    e) See also section 7h, i above.


15. Things Not Yet Covered

        Chess is an example of a game that breaks the coherence of its
        fictional world as a work of IF.

                                                        - Markovian insight


    a) The [Sacks] class takes the place of the old SACK_OBJECT. You can
       have as many as you like. (Note that these work for all [Actors] and
       not just the =player=.) Note that objects will only be put -inside- the
       sack, not -upon- it, even if it is also a supporter. Also, you can
       forgo the [Sacks] class altogether if you like and #Replace the
       IsASack() routine, which returns true for any object that... you know.
       Just be sure the object has -container-!

    b) In case you missed it, note that the direction objects now have names 
       ending in "dir" like ndir, swdir, etc.

    c) =action= is set to ##WhichOne when the player is asked "Which do you 
       mean..?" This might be useful if you want a +short_name()+ routine to 
       print "elvish sword" instead of "sword", for example.

    d) Instead of "@output_stream 3 xxxx;" and "@output_stream -3", you should 
       call OpenBuffer(xxxx) and CloseBuffer(). These calls can be nested to a 
       maximum depth of MAXIMUM_OPEN_BUFFERS (defaults to 5). You should not,
       however, nest calls to the same buffer (i.e. the "xxxx" above).

    e) "Narrative" mode (for lack of a better name) alters the way the results 
       of multiple-object commands are displayed. Instead of:

         >TAKE ALL
             table: The table is fixed in place.
             orange shirt: Taken.
             orange shirt: Taken.
             sack: Taken.
             red box: Taken.
             blue box: Taken.
             blue box: Taken.
             orange hat box: Taken.

       if the global =narrative_mode= is set to true, the output would be:

         You take four boxes (the orange hat box, the two blue boxes and 
         the red box), the sack and the two orange shirts, but the table is 
         fixed in place.

       This feature is a work in progress. First limitation: In order for it
       to work correctly, the meddle and respond property families
       (+meddle_early+, etc.) must return message codes instead of printing
       directly for any action that allows multiple objects. For example, do
       NOT code:

        respond [;
            Take: "You wouldn't touch that with a ten-foot pole!";
        ];

       But instead:

        respond [;
            Take: return ActionMessage(##Take, 9999);
        ];

        MessageCogs
          with
            messages [;
                Take: if (lm_n == 9999) "You wouldn't touch #obj# with a 
                      ten-foot pole!";
            ];

       Note that the example code given above is not NPC-friendly, because it 
       assumes the player ("You") will be the one trying to take the object. 
       (You could replace this with "#Actor#".) If the code were attached to 
       the red box, the previous example would become:

         You take three boxes (the orange hat box and the two blue boxes), the 
         sack and the two orange shirts, but the table is fixed in place, and 
         you wouldn't touch the red box with a ten-foot pole.

       The exclamation point is lost in this case, but would have been printed 
       if the player had entered TAKE THE RED BOX, as narrative mode would not 
       apply.

       Second limitation: If any implicit actions are generated by the
       command, the output will be, er, wrong. Thus, implicit actions for 
       standard multiple-object verbs are disabled when narrative mode is on.

       Third limitation: If the player is moved in the middle of the command,
       there will be no output from the command at all.

       You can test "if (multiflag)" to determine when a multiple-object
       command is being processed, and thus when narrative mode is in effect
       (assuming narrative_mode == true). (Most likely, you would use this
       test in a reaction or +messages()+ property.)

    f) The global variable =player_perspective= can be set to FIRST_PERSON, 
       SECOND_PERSON, or THIRD_PERSON to determine how the PC is referred to.

16. Things *Really* Not Yet Covered
