tips.t
#charset "us-ascii"
/*
* TADS 3 Tips, by Krister Fundin (fundin@yahoo.com). Provides a uniform
* way of providing one-time only tips to the player (and especially to
* inexperienced players) when certain things happen in the game.
*/
#include <adv3.h>
/* ---------------------------------------------------------------------- */
/*
* The tip manager keeps track of which tips we have shown. Since we don't
* want to unnecessarily show any tips more than once, we store this
* information both transiently (in the tipManager) and persistently (in
* the tip objects themselves). This should make sure that we at least
* cover these two types of cases:
*
* - The player sees a tip, then restarts, undos or restores to an earlier
* position.
* - The player sees a tip, saves, then resumes play at some later time.
*/
transient tipManager: InitObject, PostRestoreObject, PostUndoObject
/*
* Show pending tips. This is called by a PromptDaemon before each new
* round of input.
*/
showTips()
{
/*
* Go through our vector of pending tips. Use a 'for' loop instead
* a 'foreach' loop, in case showing one tip triggers another one.
*/
for (local i = 1 ; i <= pendingTips.length ; i++)
{
/* show the description of the current tip */
pendingTips[i].showTipDesc();
}
/* clear the vector of pending tips */
pendingTips.setLength(0);
}
/* update tip information after a restore, restart or undo */
execute()
{
/* go through all tips */
forEachInstance(Tip, function(tip)
{
/*
* see if this one has been shown, according to its own
* persistent memory
*/
if (tip.shown)
{
/*
* It says that it has been shown. If it's not in our list
* of shown tips, then add it.
*/
if (shownTips.indexOf(tip) == nil)
shownTips += tip;
}
else
{
/*
* It says that it hasn't been shown. If it's in our list
* of shown tips, then it must have been shown after all.
*/
if (shownTips.indexOf(tip) != nil)
tip.shown = true;
}
});
}
/* a vector of tips to be displayed before the next prompt */
pendingTips = static new Vector(2)
/*
* A transient list of shown tips. Note that this must be a list and
* not a vector. When updating a list, we actually replace it with a
* new list, since lists are immutable. This is a transient change -
* it affects only the value of the shownTips property. Updating a
* vector, however, modifies the vector itself and leaves the property
* with the same reference. A vector itself is always persistent, so
* this change would be lost after E.G. a restore.
*/
shownTips = []
;
/*
* The Tip class. Each actual tip should be represented by an instance of
* this class. To show the tip, just call tipName.showTip(). If the tip
* has already been shown, or if the tips have been turned off completely,
* then nothing will be displayed.
*/
class Tip: object
/*
* The actual text to display when this tip is shown. We'll wrap it in
* <.tip> tags automatically, and also add a paragraph break before
* it.
*/
desc = ""
/* show this tip */
showTip()
{
/* see if we should be shown */
if (!shouldShowTip)
return;
/*
* defer the actual displaying of the tip until just before the
* next command prompt
*/
tipManager.pendingTips.append(self);
/* note that we have been shown */
makeShown();
}
/* display our tip description, I.E. the actual tip */
showTipDesc()
{
/* display a pargraph break and an opening <.tip> style tag */
"<.p><.tip>";
/* show our description */
desc();
/* close the <.tip> tag */
"<./tip>";
}
/* should we show this tip when asked to? */
shouldShowTip()
{
/*
* We'll show it as long as it hasn't been shown before and we
* haven't turned the tips off completely. Certain tips might want
* to be displayed even when all tips are turned off, if they
* contain information specific to a certain story or an extension
* that it uses. If so, then this method could be overridden.
*/
return (!shown && tipMode.isOn);
}
/*
* Mark this tip as shown. This method can be called by outside code
* before the tip has been triggered. If the tip informs the player of
* a certain command, for instance, then it would become redundant if
* the player has already used that command.
*/
makeShown()
{
/* set our shown flag */
shown = true;
/* also add us to the transient list of shown tips */
tipManager.shownTips += self;
}
/* flag: has this tip been shown before? */
shown = nil
;
/*
* A style tag that we enclose tips with. By default, we just use plain
* parentheses, just like for notifications and parser messages, but this
* could be overridden if we wanted to display something fancier.
*/
tipStyleTag: StyleTag 'tip'
openText = '('
closeText = ')'
;
/*
* During pre-init, create a PromptDaemon for displaying tips. We don't
* want to display them directly when the showTip() method is called, to
* allow tips to be triggered from pretty much anywhere without having to
* worry about them showing up in the middle of some text.
*/
PreinitObject
execute()
{
/*
* Give this daemon a higher-than-average eventOrder, in case
* another PromptDaemon wants to display a tip. The standard tip
* about turning of score notification is triggered this way.
*/
new PromptDaemon(tipManager, &showTips).eventOrder = 200;
}
;
/* ---------------------------------------------------------------------- */
/*
* Next, we want to allow turning all tips on and off during the game. It
* should also be possible to turn the tips off for ALL games that use
* them, and thus we define a SettingsItem for this purpose. This means
* that the player can turn the tips off and then save this setting as the
* default.
*/
tipMode: BinarySettingsItem
/* we show tips by default */
isOn = true
/* the ID string to use in the configuration file */
settingID = 'tips.showtips'
/* show our description */
settingDesc = (libMessages.tipStatusShort(isOn))
;
/*
* Define a system action for turning tip mode on/off.
*/
DefineSystemAction(TipMode)
execSystemAction()
{
/* set the new tip mode */
tipMode.isOn = stat_;
/* acknowledge the change */
libMessages.acknowledgeTipStatus(stat_);
}
;
TADS 3 Library Manual
Generated on 5/16/2013 from TADS version 3.1.3