footnote.t
#charset "us-ascii"
/*
* Copyright (c) 2000, 2006 Michael J. Roberts. All Rights Reserved.
*
* TADS 3 Library - footnotes
*
* This module defines objects related to footnotes.
*/
/* include the library header */
#include "adv3.h"
/* ------------------------------------------------------------------------ */
/*
* Footnote - this allows footnote references to be generated in
* displayed text, and the user to retrieve the contents of the footnote
* on demand.
*
* Create an instance of Footnote for each footnote. For each footnote
* object, define the "desc" property as a double-quoted string (or
* method) displaying the footnote's contents.
*
* To display a footnote reference in a passage of text, call
* <<x.noteRef>>, where x is the footnote object in question. That's all
* you have to do - we'll automatically assign the footnote a sequential
* number (so that footnote references are always seen by the player in
* ascending order, regardless of the order in which the player
* encounters the sources of the footnotes), and the NOTE command will
* automatically figure out which footnote object is involved for a given
* footnote number.
*
* This class also serves as a daemon notification object to receive
* per-command daemon calls. The first time we show a footnote
* reference, we'll show an explanation of how footnotes work.
*/
class Footnote: object
/*
* Display the contents of the footnote - this will be called when
* the user asks to show the footnote with the "NOTE n" command.
* Each instance must provide suitable text here.
*/
desc = ""
/*
* Get a reference to the footnote for use in a passage of text.
* This returns a single-quoted string to display as a reference to
* the footnote.
*/
noteRef
{
/*
* If the sensory context is blocking output, do not consider
* this a reference to the footnote at all, since the player
* won't see it.
*/
if (senseContext.isBlocking)
return '';
/*
* if we haven't already assigned a number to this footnote,
* assign one now
*/
if (footnoteNum == nil)
{
/*
* Allocate a new footnote number and remember it as our
* own. Note that we want the last footnote number for all
* footnotes, so use the Footnote class property
* lastFootnote.
*/
footnoteNum = ++(Footnote.lastFootnote);
/*
* add myself to the class's list of numbered notes, so we
* can find this footnote easily again given its number
*/
Footnote.numberedFootnotes.append(self);
/* note that we've generated a footnote reference */
Footnote.everShownFootnote = true;
}
/*
* If we're allowed to show footnotes, return the library
* message text to display given the note number. If all
* footnotes are being hidden, or if we're only showing new
* footnotes and we've already read this one, return an empty
* string.
*/
switch(footnoteSettings.showFootnotes)
{
case FootnotesFull:
/* we're showing all footnotes unconditionally */
return gLibMessages.footnoteRef(footnoteNum);
case FootnotesMedium:
/* we're only showing unread footnotes */
return footnoteRead ? '' : gLibMessages.footnoteRef(footnoteNum);
case FootnotesOff:
/* we're hiding all footnotes unconditionally */
return '';
}
/*
* in case the status is invalid and we fall through, return an
* empty string as a last resort
*/
return '';
}
/*
* Display a footnote given its number. If there is no such
* footnote, we'll display an error message saying so. (This is a
* class method, so it should be called directly on Footnote, not on
* instances of Footnote.)
*/
showFootnote(num)
{
/*
* if there's a footnote for this number, display it; otherwise,
* display an error explaining that the footnote number is
* invalid
*/
if (num >= 1 && num <= lastFootnote)
{
local fn;
/*
* it's a valid footnote number - get the footnote object
* from our vector of footnotes, simply using the footnote
* number as an index into the vector
*/
fn = numberedFootnotes[num];
/* show its description by calling 'desc' method */
fn.desc;
/* note that this footnote text has been read */
fn.footnoteRead = true;
}
else
{
/* there is no such footnote */
gLibMessages.noSuchFootnote(num);
}
}
/* SettingsItem tracking our current status */
footnoteSettings = footnoteSettingsItem
/*
* my footnote number - this is assigned the first time I'm
* referenced; initially we have no number, since we don't want to
* assign a number until the note is first referenced
*/
footnoteNum = nil
/*
* Flag: this footnote's full text has been displayed. This refers
* to the text of the footnote itself, not the reference, so this is
* only set when the "FOOTNOTE n" command is used to read this
* footnote.
*/
footnoteRead = nil
/*
* Static property: the highest footnote number currently in use.
* We start this at zero, because zero is never a valid footnote
* number.
*/
lastFootnote = 0
/*
* Static property: a vector of all footnotes which have had numbers
* assigned. We use this to find a footnote object given its note
* number.
*/
numberedFootnotes = static new Vector(20)
/* static property: we've never shown a footnote reference before */
everShownFootnote = nil
/* static property: per-command-prompt daemon entrypoint */
checkNotification()
{
/*
* If we've ever shown a footnote, show the footnote
* notification now. Note that we know we've never shown a
* notification before simply because we're still running - we
* remove this daemon as soon as it shows its notification.
*/
if (everShownFootnote)
{
/* show the first footnote notification */
gLibMessages.firstFootnote();
/*
* We only want to show this notification once in the whole
* game, so we can cancel this daemon now. Since we're the
* event that's running, we can just tell the event manager
* to remove the current event from receiving further
* notifications.
*/
eventManager.removeCurrentEvent();
}
}
;
/* our FOOTNOTES settings item */
footnoteSettingsItem: SettingsItem
/* our current status - the factory default is "medium" */
showFootnotes = FootnotesMedium
/* our config file variable ID */
settingID = 'adv3.footnotes'
/* show our short description */
settingDesc = (gLibMessages.shortFootnoteStatus(showFootnotes))
/* get the setting's external file string representation */
settingToText()
{
switch(showFootnotes)
{
case FootnotesMedium:
return 'medium';
case FootnotesFull:
return 'full';
default:
return 'off';
}
}
settingFromText(str)
{
/* convert to lower-case and strip off spaces */
if (rexMatch('<space>*(<alpha>+)', str.toLower()) != nil)
str = rexGroup(1) [3];
/* check the keyword */
switch (str)
{
case 'off':
showFootnotes = FootnotesOff;
break;
case 'medium':
showFootnotes = FootnotesMedium;
break;
case 'full':
showFootnotes = FootnotesFull;
break;
}
}
;
/* pre-initialization - set up the footnote explanation daemon */
PreinitObject
execute()
{
/* since we're available, register as the global footnote handler */
libGlobal.footnoteClass = Footnote;
/* initialize the footnote notification daemon */
new PromptDaemon(Footnote, &checkNotification);
}
;
TADS 3 Library Manual
Generated on 5/16/2013 from TADS version 3.1.3