
Life and Times of the Inform Library                       1st February 1995
====================================

This modification history takes release 5/5 of the Inform library as a base. 
5/4 is similar but earlier Inform 5 releases are internally very different
(though largely compatible in use, except for the way "transparent" is done,
and the handling of plural nouns).  Anything from the dark ages of Inform 4
and before is obselete and behaves unapologetically differently.

Note that (1) most of what's below is for experts only, (2) this history
tends to over-dramatise minute changes (many of them recondite bug fixes)
and (3) a few lines in the Designer's Manual will one day need to be added,
but there's no hurry considering (1) and (2).

Thanks to Gareth Rees, Mike Threepoint, Torbj|rn Anderson, Brendon Wyber,
Robert Dickau, Brad Jones, David Wagner and many others.

Changes in Release 5/6 (941112)
===============================

1. The game banner is tidier and a line shorter (some people felt the old one
   overdone: use the command "version" for more code numbers)
2. EnglishNumber printing fixed up to work nicely across the whole range of
   signed integers (i.e. about plus-minus 30000), with "forty" correctly spelt
   this time: e.g. "minus twelve thousand, three hundred and eight"
3. The bug "the game crashes if you try to take what you're sitting on or in"
   is fixed
4. Two new bits are available for WriteListFrom styles.  ISARE_BIT prints
   " is " or " are " before the list, according to its size, and CONCEAL_BIT
   (which only works if WORKFLAG_BIT isn't used) misses off items which have
   "concealed" or "scenery"
5. Containers now aren't called "open" or "closed" in lists unless actually
   "openable": thus, messages like "a paper cup (which is open but empty)"
   will now read "a paper cup (empty)"
6. Concealed or scenery items now not mentioned inside vehicles or on top of
   things (see (4)!)
7. The "found_in" property is enhanced.  If an object O1 is given in the
   found_in list of O2 which isn't a room, then O2 is counted as being in the
   same room as O1, wherever that is at the moment.  (But be warned: this is
   only updated when the player changes rooms.)
   Moreover, the "found_in" property of O can instead of a list of places be
   a routine.  This returns true if O should be in location, false otherwise.
   For instance,

     Object Sun "Sun",
       with ....
            found_in
            [; if (location has light) rtrue;
            ],
       has  scenery;

   This saves bother with long lists of places, and also makes it much easier
   for objects to spread out or contract (like fire, or flooding) in play.
8. A bug making YesOrNo() corrupt a customised status line has been removed
9. Under earlier library files, returning 0 from a token-parsing routine
   was illegal and might hang the parser (see p. 41 in the Designer's Manual
   for the old specification).  Returning 0 is hereby legalised and indicates
   "accept the text the word marker has been skipped over, and count it as
   not specifying any particular object or number".  For example, given

     [ PolyAdj w;
       w=NextWord(); if (w=='on' or 'at' or 'in') return 0;
       return -1;
     ];

   the token PolyAdj will accept "on", "at" or "in" as alternative choices of
   adjective (and forget which one the player actually typed).
   Similarly,

     [ Anything w; 
       while (w~=-1) w=NextWord(); return 0;
     ];

   makes the token Anything accepts the entire rest of the line.
10. The grammar "shut off", "climb up", "close up", "dig", "dig with" has been
    added
11. Taste and Touch are now required to take objects: as a result the
    old TouchThing action has gone, and there is simply a Touch action.
    (Strictly speaking this is an incompatible change but hardly anyone has
    used these actions anyway.)
12. The Escape key now acts as Q to get out of menu displays (if your
    interpreter is well enough written to recognise an escape key)
13. A convenience (but also problem) is that the Receive fake action is
    generated both when the player tries to put an object in something, or
    on it.  This is no problem unless the recipient is trying to be both at
    once, in which case it may need to know why the Receive has been
    generated - i.e., which the player's trying to do.  The "right" solution
    would be to have two different fake actions, but that would be a rather
    incompatible change and make a certain amount of existing code work
    differently.  Instead, a variable called "receive_action" is set to either
    ##PutOn or ##Insert depending on which is causing the Receive to happen.
14. Several people have asked for easier ways to have several kinds of
    containment at once, all on the same object - on top, inside, under,
    behind, component parts of, etc.  For these (and other) purposes a brand
    new property called "add_to_scope" has been added.  Anything listed under
    this property is also in scope when the parent object is.  (This also has
    consequences for light considerations.)
    See the modest example "A Nasal Twinge" for two applications of this.
    Note for true scope hackers: this scope addition does _not_ occur if the
    object is moved into scope by the programmer explicitly calling
    PlaceInScope (since this must allow completely arbitrary scope
    selections), but that it does happen when objects are moved in scope
    by calls to ScopeWithin(domain).
    The "add_to_scope" property is aliased, so there's no cost in property
    consumption.
15. Trying to type "undo" on the very first turn now produces a more sensible
    error message.
16. 5/5 had an especially embarrassing bug - "go north" didn't work!  Which
    goes to show how thoroughly hooked on abbreviations we all are now,
    because hardly anybody noticed.
17. The initial room description (printed after the game banner) is now
    properly done with a Look action (in particular, before and after
    routines are invoked).  This is in case some horrid "before" hack is
    being applied to the description of the first location.
18. Likewise, the library now works correctly if the game begins in darkness
    (Steve Meretzky is fond of this trick - e.g. "Hitchhikers", "Sorcerer")
19. "out" used not to work properly in a dark room with an out map
    connection, but now does
20. A somewhat brutal test (Torbj|rn Anderson constructed 450 daemons!)
    revealed that the daemon/timer routines stored object numbers in bytes
    rather than words (thus getting them wrong in big games): not any more
    they don't
21. It is now legal to return 3 from a routine attached to DoMenu (which
    usually prints some text out, such as a hint: return values of 0 or 1
    make the game wait for a space then return to the menu, 2 makes the
    game return directly): this makes the game quit the menu altogether
    as if Q had been pressed (which is useful for juggling submenus around).

Changes in Release 5/6 (941117)
===============================

22. "You open the box, revealing ." bug fixed (when box is empty)
23. A character got seriously corrupted in the timers routines: fixing this
    was urgent, hence the rapid re-release

Changes in Release 5/7 (941214)
===============================

24. add_to_scope can now take a routine instead of a list of objects.
    This routine has to call AddToScope(obj) for each obj it wants to add
    to the scope. (It may not use ScopeWithin or any other scoping routines)
25. The direction objects now have the general-purpose "number" property
    provided, as it's sometimes convenient to have a scratch variable for
    each direction (when programming mazes, for instance).
26. If the constant WITHOUT_DIRECTIONS is defined before inclusion of the
    library files, then 10 of the default direction objects are not defined
    by the library.  The designer is expected to define alternative ones
    (and put them in the "compass" object); otherwise the game will be
    rather static.  (The "in" and "out" directions are still created, because
    they're needed for getting into and out of enterable objects.)
27. The routine ChangeDefault(property, value) dynamically changes the
    game's default value for that property (i.e. the value that property has
    for any object not explicitly giving a value of its own).  For instance,

      ChangeDefault(cant_go, "You're a Master Adventurer now, and still \
                              you walk into walls!");

28. The reverse-order form of "show" didn't work when addressed to a third
    party, as in

      charles, show diana the phone bill

    but now does.
29. Very subtle bug in object-name printing (it had a peculiar and very rare
    side-effect which I think only turned up when using odd combinations of
    debugging commands, and took me ages to find!) fixed.
30. The not very sad demise of another piece of Inform antiquity: the
    use of the "special" token in the library grammar.  The only substantial
    use left was in the grammar for looking up or consulting things, like
    books (an old Curses mainstay).  Now it's tricky to parse lines like

      look up figure 18 in the engineering textbook

    because almost anything could appear in the first clause, and even its
    format depends on what the second clause is.  So the new arrangement
    is: if an object wants to be "consultable", it should have a before rule
    for the "Consult" action.  The Consult action will happen when the
    player types, for instance,

      look up <any words here> in <the object>
      read about <any words here> in <the object>
      consult <the object> about <any words here>

    and the object has to parse the <any words here> part itself.
    (Note that "second" doesn't hold any value in a Consult action; internally,
    the <any words here> part is treated as an adjective by the parser.)
    To help the object to do this, variables are set up:

      consult_from       -        number of the first word in the <any...>
      consult_words      -        number of words in the <any...>
                                  (which must be at least 1)

    It can then use NextWord(), TryNumber(word-number) and the like
    to decide on the topic.  If you really need more elaborate topic-parsing
    then grammar replacement is probably a better bet.
31. The verbs "read" and "examine" are now separated - this has been a
    popular request for about a year now!  They still both ordinarily
    generate the Examine action, but it is now possible to add or replace
    grammar for "read" without doing so for "examine" at the same time.
    Consequently one may now easily create a separate Read action, if
    required.  E.g.:

      Attribute legible;

      Object textbook "textbook"
        with name "engineering" "textbook" "text" "book",
             description "What beautiful covers and spine!",
             before
             [; Consult, Read:
                   "The pages are full of nasty equations which \
                    make no sense to you.";
             ],
        has  legible;
      [ ReadSub; <<Examine noun>>; ];
      Extend "read" first
                * legible                        -> Read;

    Note that "read" is automatically translated to "examine" for anything
    which doesn't have "legible", or indeed does but doesn't provide any
    "before" rule for Read.
32. Many actions (all those which do something substantial and then print a
    message saying they've done it), viz.:

      Take, Drop, Insert, PutOn, Remove, Enter, Exit, Go, Unlock, Lock,
      SwitchOn, SwitchOff, Open, Close, Wear, Disrobe, Eat

    now consult a variable called "keep_silent".  If this is 1, they say
    nothing in the event of _success_ (if they fail, as they may do in many
    different convoluted ways, they still complain out loud).
    It is essential to reset this variable to 0 after use.
    This feature makes implicit actions much easier to "properly" implement,
    i.e. to implement without bypassing any lurking game rules.
33. (As indeed here.)  The library used to be a bit casual about putting
    items away automatically into the SACK_OBJECT (if there was one defined),
    but now it applies the full normal rules by causing an Insert action.
    Thus, the sack needs to be open, any odd behaviour coded up for the
    sack will now work, the sack's capacity cannot be exceeded and so on.
34. The Enter and Exit actions sometimes missed possible location "after"
    rules; they've now been tidied up.
35. Silly bug in scoring "scored" objects (picked up by take all) fixed.
36. "your" is now understood in some contexts by the parser: so that

      george, give me your ukelele

    works (if someone called George is holding a ukelele).
37. In 5/6 and before, if you put a green box inside a red bag, and then
    tried to put the red bag into the green box, they would collapse in on
    themselves into a black hole and vanish from the game.  (An amusing
    thing to do is then to use the "tree" debugging command on the green
    box.)  The library now insists on the Axiom of Foundation (i.e., won't
    let you put something indirectly inside or on top of itself).

Changes in Release 5/7 (941220)
===============================

38. The "the box of tarot cards is empty already." sentence now capitalises
    the "The".
39. Bug in the parser fixed.  Occasionally grammar like

      ... * scope=MicroScope "at" noun  -> ...

    would mistakenly apply the MicroScope scope rules to the second, plain
    noun token.  This no longer happens.
40. Minor darkness bug (to do with getting out of enterable objects when in
    a dark place) fixed.
41. Single rather than double new-line now printed when light returns to the
    game (after all, some people have small displays).
42. If a "supporter" (say, a mantelpiece) holds up only items which have
    "scenery" or "concealed", the library used to say "On the mantelpiece."
    and stop: now it omits such a line entirely.
43. The treatment of "concealed" possessions of containers is slightly
    tidied up (though using such is not recommended except in scenery, as
    it's likely to need some effort to make inventories do the right thing).
44. (Cf. (4) above.)  At Gareth Rees' proposal, WriteListFrom now has a
    policy on what to do if both CONCEAL_BIT and WORKFLAG_BIT are set,
    causing a clash.  In this instance, the "workflag" rule applies at the
    top level, but not below, and the "conceal" rule applies below but not
    at the top level.
45. A soupcon of new grammar: "climb over" (just does the Climb action);
    "thump" and "punch" now equate to "attack"; "present" and "display" to
    "show"; one can now "stand on" something.
46. It's Christmas, and a new fake action is born.  This one is called
    "ThrownAt" and is analogous to "Receive" for containers: i.e., it runs
    before rules for the object which something is being thrown at.  E.g.,

        before
        [;  ThrownAt: if (noun==dart)
                      {   move dart to self; "Triple 20!"; }
                      move noun to location;
                      CDefArt(noun); " bounces incongrously off the board.";
        ],

    Note: "after" rules don't apply, as the default behaviour of ThrowAt
    is to do nothing but rebuke the player.

Change in Release 5/7 (941230)
==============================

47. Last and most embarrassing bug fix of 1994: removing a spurious tracing
    message, "Else clause", left in by accident from earlier debugging.

Changes in Release 5/7 (950109)
===============================

48. Minor enhancement to the "tree" debug verb; new "gonear" debug verb,
    such that "gonear frog", say, takes you to the room the frog is in.
49. The library often needs to print a property value if it's a string, or
    run it if a routine.  There's now a routine to do this:

        PrintOrRun(object, property, flag);

    If the (optional) flag is given and non-zero, a new-line is printed
    after a string (but only if it was a string).
    The library now makes extensive use of this, tidying up the code
    somewhat, but the reason for the change was that it was previously
    doing signed comparisons to work out where addresses lie in memory,
    which begins to fail when the total game size exceeds about 180K.
    Two new useful primitives are:

        UnsignedCompare(x,y)  returns   1  if x>y
                                        0  if x=y
                                       -1  if x<y

    and

        ZRegion(addr)         returns   1  if addr is a valid object number
                                        2  if addr is a routine address
                                        3  if addr is a string address
                                        0  otherwise.
50. The "NewRoom" entry point was previously not always being called when
    a new room was entered, as the manual claimed; now it is.
51. The "purloin" debugging verb now clears "concealed" from anything it
    magically takes - this prevents nuisance in later use.
52. The "article" property can now hold a routine to print one, in line
    with standard library practise.  One might imagine "a mouse" changing
    dynamically to "some mice", perhaps.
53. Inelegant messages like "(which is closed) (which is empty)" tidied
    up into "(which is closed and empty)".
54. New debugging verbs are provided to take advantage of the Z-machine's
    own game-testing features.  These may not fully work under ITF, but
    do work under Zip.  (For either Standard or Advanced games.)

    "recording" (or "recording on") saves all the commands typed in a
       session to a file,
    "recording off" stops this,
    "replay" plays back the script (i.e. reads commands from the file);

    in order to make the Z-machine predictable (that is, deterministic)
    one would like to make the random number generator do exactly the
    same thing each time, and this is achieved by typing

    "random", which internally does @random -100.  It should be noted that
    this in particular depends very much on how good your interpreter
    (and its port) is: on my machine, this doesn't appear to do anything,
    for instance.

Changes in Release 5/8 (950118)
===============================

55. Trying to ask somebody else to repeat something by, e.g.,

        major, resign     rather than     major, resign
        major, again                      again

    would sometimes (horrifyingly) hang the Z-machine - now it produces a
    polite reply.  Apologies for having missed this case.
56. And another crude parser bug.  "get all except" hasn't always been
    working recently: now it works again.
57. A popular request (well, three people asked, anyway) is for a way of
    changing some of the parser's assumptions about what to do with vague
    requests by the player.  The notorious one is: should "take all"
    attempt to take objects marked as "scenery", and thus reveal their
    existence as game objects?  (Infocom games did, and Inform usually
    does.)
    The new entry point

        ChooseObjects(object, code)

    is provided for this.  It is called in two circumstances.  If code is
    0 or 1, that means the parser is contemplating including this item in
    an "all", and the code is 0 if the parser intends not to, 1 if it
    intends to do so.  Returning 1 forces it to be included, returning 2
    forces it to be excluded and returning 0 (the default, i.e. rfalse)
    makes the parser do what it had previously decided anyway.

    The other time is when code is 2.  This means that the parser is having
    to sort through a list of items, trying to decide which is intended.
    Return a number from 0 to 9 (0 is the default, i.e. rfalse again) to
    give the item a score for how appropriate is.
    For instance:

        [ ChooseObjects obj code;
          if (code<2) { if (obj has scenery) return 2; rfalse; }
          if (action_to_be==##Eat && obj has edible) return 3;
          if (obj hasnt scenery) return 2;
          return 1;
        ];

    (The parser's internal variable "action_to_be" is always set to the
    action that will be generated if the current line of grammar is
    successfully matched.)
    Scenery is penalised twice in this example - it never appears in any
    multiple lists, and non-scenery is always preferred over scenery when
    sorting out an ambiguous input.  Unless, that is, the object is edible,
    and the player is trying to Eat something.  ("eat black" will now choose
    a Black Forest Gateau rather than a black rod with a star on the end).
58. Another popular request (popular with everyone except me, as it was
    horrid to implement) was for a mechanism for changing the Library's
    habitual messages - many people become very irritated when their own
    games say "Violence isn't the answer, you know" for the dozenth time.
    Of course this was always possible by massive means (replacing huge
    numbers of routines, for instance), but now it's much easier.

    This feature is provided in an unusual way.  You may optionally
    provide a special object called LibraryMessages (but if you do so,
    you must define it in between the inclusion of "Parser" and the
    inclusion of "Verblib").  Here is an example, changing two of the
    library's standard messages:

        Object LibraryMessages "lm"
          with before
               [;  Jump: "You jump and float uselessly for a while in \
                          the zero gravity here on Space Station Alpha.";
                   SwitchOn:
                       if (lm_n==3)
                       {  print "You power up "; DefArt(lm_o); "."; }
               ];

    The object never appears in the game, of course, and exists solely
    to have a "before" routine.  As usual, returning false (0) causes the
    library to carry on as it normally would, while returning true (1)
    indicates that you've printed the message and it doesn't need to.

    The Jump action only ever prints one message, but more elaborate
    actions such as SwitchOn have several (the extreme case is Take, with
    13).  lm_n holds the message number, which counts upwards from 1
    essentially in order of use in VerbLib.  It would be too inefficient
    to define 250 constants to give these cute names, and instead the
    programmer is referred to the last few pages of the source code of
    VerbLib.  The stock of messages has changed very little in the last
    six months and, while it may occasionally be added to, there shouldn't
    be any need to renumber the present ones.  An amusing way to observe
    LM in action is to add

        Object LibraryMessages "lm"
          with before
               [;  print "[", sw__var, ",", lm_n, "] ";
               ];

    to your game (arcane note: sw__var, the "switch variable", always
    holds the action number used by Inform in working out which paragraph
    of code to run in a before/after/life routine).  Another amusing
    effect is to simply write "rtrue" for the before routine, which
    results in an alarmingly silent game - blindfold Adventure, perhaps.

    Note that LM can be used as a sneaky way to add extra rules onto the
    back of actions, and to make messages more sensistive to game context.

    One could even use LM to translate absolutely everything the Library
    says into Middle English during a medieval section of a game.  This is
    left as an exercise to the reader.

    This new feature imposes a slight speed overhead, which should hardly
    be noticed (text printing being something which isn't repeated hundreds
    of times per second) and a slight code size overhead, which might:
    about 2K.  I regret this but consider the gain to outweigh the loss.
59. "him"/"her" now never become the player when the player self-refers.
    Of course people never refer to themselves in the third person...
60. There was a slight bug in the method of Asking people about things, and
    anyway the existing documentation is a bit unclear (read: slightly
    wrong).  The way to code for this is:

        Ask: if (second=='bug') "Graham says, ~It's mended now.~";

    though you can also look at special_word directly.  What you can't do
    is look at noun and expect to find the word there: noun is of course
    set to Graham.
61. "graham, tell me about bug" is now equivalent to "ask graham about bug".
    Likewise, one can Tell people about things (this is a new action).
62. One now can't Enter or Exit a closed container.  (Enterable objects
    which aren't containers or doors don't need to be open, though.)
63. The Curses-style "objects" and "places" verbs have been added.  These
    are normally present in the library but can be made not to appear by
    defining the constant NO_PLACES before the inclusion of VerbLib.
    (A neat trick, if an object or place is going to be misleadingly named
    in such a list (e.g. if it represents 40 different nearly-identical
    rooms) is to give an object a different short_name when the action is
    ##Places or ##Objects than the rest of the time.)

Changes in Release 5/8 (950201)
===============================

64. "You aren't in anything at the moment" bug (if you don't know what this
    means, you haven't seen it) fixed.
65. In 5/8, after a ChangePlayer the former player's object was not properly
    short-named in some cases: now it's usually called "your former self".
66. Actions causing death or victory could sometimes make LibraryMessages
    replacement go wrong: this is fixed.
67. MAX_TIMERS bound checking corrected (at long last).
68. "places" no longer says "You have visited" twice, and "objects" now says
    "None." if you've never held any objects in the game.
69. The prompt "^>" is now printed via the library messages system, with the
    (fake) action Prompt.  Thus, you might use:

        Object LibraryMessages "lm"
          with before
               [;  Prompt: print "^What now? "; rtrue;
               ];

    to change the prompt.  Likewise you can adapt it to events, or get rid
    of the "skipped line on screen each turn" convention.
    This prompt is only used in ordinary game play, and not at such keyboard
    inputs as yes/no questions or the RESTART/RESTORE/QUIT game over choice.
70. Subtle change in transparency rules.  If you ChangePlayer to some
    creature, then any animate objects which are (directly or indirectly)
    holding the creature at the time are made "transparent".  This prevents
    you from finding yourself in darkness for a reason which is now
    obselete.
----------------------------------------------------------------------------
