/* footnote.t -- simple footnote allocation library
  written by david etherton ([email protected])
  do whatever you want to with this.
  requires TADS 2.1 or later because of the use of the 'modify' feature.

  footnotes are really easy to overuse, so be careful out there!

  common sense says that anything in a footnote should be able
  to be safely ignored by the player.
*/

/*
       example usage:

       desk: fixeditem, surface
               noun = 'desk'
               adjective = 'fine' 'oak'
               location = startroom
               sdesc = "fine oak desk"
               ldesc = { "The desk is stained a deep brown color, and has
                       that wonderful rustic appeal of a Norman Rockwell
                       painting. ";
                       makeNote('In fact, this entire room looks like an
                               explosion at a Normal Rockwell factory.');
                       }
       ;

       >examine the desk
       The desk is stained a deep brown color, and has that wonderful
       rustic appeal of a Norman Rockwell painting.  [3]
       >footnote 3
       [3]. In fact, this entire room looks like an explosion at a
       Norman Rockwell factory.
*/

/* local static state for footnote library. */
fnState: object
       highest = 0             /* highest footnote allocated so far */
       badTries = 0            /* number of times bad footnote number tried */
       text = []               /* accumulated footnote text */
;


/* makeNote is a function which accepts footnote text and produces, as
  a side effect, the resulting footnote reference number in brackets.
  Its main purpose is to associate a block of text with a dynamically
  assigned footnote number which can be retrieved later with the
  'footnote' verb defined below.  Passing the same block of text
  always produces the same footnote number as output. */
makeNote: function (noteText)
{
       local foundNum;

       /* see if the footnote has already been allocated. */
       for (foundNum:=1; foundNum<=fnState.highest; foundNum++)
               if (noteText = fnState.text[foundNum])  /* already seen? */
                       break;                          /* yes, leave loop */

       /* allocate a new footnote if this is the first time it's been seen */
       if (foundNum >= fnState.highest) {
               ++ fnState.highest;             /* get next note number */
               fnState.text += [noteText];     /* save text in a list */
       }

       /* display the reference number in brackets. */
       "["; say(foundNum); "]";
}


/* footnote is a new verb we're declaring.  The verb and sdesc fields are
  pretty standard; the former supplies the actual words the players can
  type to get this verb, and the latter is used by the parser itself
  occasionally.  action(actor) defines what happens when the verb is
  supplied with no direct or indirect objects; in this case, we want
  to inform the player of the proper usage.  Finally, doAction defines
  what method in the direct object (in this case, the generic number
  object) gets called to handle this verb; in this case, 'doFootnote'
  will be the method which is called. */
footnote: deepverb
       verb = 'footnote' 'note'
       sdesc = "footnote"
       action(actor) = "You need to include a footnote number."
       doAction = 'Footnote'
;


/* basicNumObj is an object supplied by TADS in adv.t which we are
  modifying to include support for new footnotes.  The
  verDoFootnote method indicates that this object knows how to
  handle the footnote verb; therefore, 'footnote lamp' would
  produce a parser error since a lamp would probably not inherit
  from basicNumObj and as such would not define a verDoFootnote
  method.  On the other hand, 'footnote 4' would cause
  basicNumObj (actually, numObj, which directly inherits from it)
  to receive a verDoFootnote message--which it knows how to handle!
  Since verDoFootnote produces no output, the parser will automatically
  call the doFootnote method to complete processing.  The doFootnote
  method checks to see if the footnote is in range; if it is not
  in range, it prints an error message.  If the user has obviously
  been trying a lot of bad footnote numbers, it also offers a
  suggestion to cease and desist.  On the other hand, if the
  reference is valid, we display the footnote number along with
  its associated text.  In either case, we do nothing special
  besides return to the parser, so the footnote is counted as
  a normal turn.  If you don't want footnotes to count as a turn,
  make 'footnote' about inherity from sysverb instead of deepverb. */
modify basicNumObj
       verDoFootnote(actor) = { }      /* always allowed */
       doFootnote(actor) =
               {
                       /* footnote out of range? */
                       if (self.value < 1 or self.value > fnState.highest) {
                               if (++fnState.badTries = 5)
                                       "Footnotes aren't assigned until
                                       they are encountered in the game.
                                       Repeatedly guessing footnotes will
                                       accomplish nothing.";
                               else
                                       "No such footnote.";
                       }
                       else {  /* display the footnote reference & text */
                               "["; say(self.value); "].\ ";
                               say(fnState.text[self.value]);
                       }
               }
;