adv3.h
#charset "us-ascii"
/*
* Copyright (c) 2000, 2006 Michael J. Roberts. All Rights Reserved.
*
* TADS 3 Library - main header
*
* This file provides definitions of macros, properties, and other
* identifiers used throughout the library and in game source.
*
* Each source code file in the library and in a game should generally
* #include this header near the top of the source file.
*/
#ifndef ADV3_H
#define ADV3_H
/* ------------------------------------------------------------------------ */
/*
* Include the system headers that we depend upon. We include these here
* so that each game source file will pick up the same set of system
* headers in the same order, which is important for intrinsic function
* set definitions.
*/
#include <tads.h>
#include <tok.h>
#include <t3.h>
#include <vector.h>
#include <strbuf.h>
#include <file.h>
#include <dict.h>
/* ------------------------------------------------------------------------ */
/*
* Establish the default dictionary for the game's player command parser
* vocabulary.
*/
dictionary cmdDict;
/* ------------------------------------------------------------------------ */
/*
* canInherit - determine if there's anything to inherit from the current
* method. Returns true if there's a method to inherit, nil if
* 'inherited' in the current context would not invoke any code.
*/
#define canInherit() \
propInherited(targetprop, targetobj, definingobj, PropDefAny)
/* ------------------------------------------------------------------------ */
/*
* Generic part of speech for "miscellaneous word." We use this to
* classify words in unstructured phrases; it can apply to any token.
* Note that dictionary entries are never made with this word type, so
* it's not specific to any language; this is merely for flagging words in
* unstructured phrases in grammar matches.
*/
dictionary property miscWord;
/*
* Generic part of speech for SpecialTopic words. We enter special topic
* keywords into the parser dictionary so that they're not flagged as
* unknown words if they're used out of context.
*/
dictionary property specialTopicWord;
/* ------------------------------------------------------------------------ */
/*
* If we're compiling for debugging, automatically include the parser
* debug code, which allows certain information on the parsing process
* (such as grammar match trees) to be displayed each time a command is
* typed.
*
* Note that you can turn on parser debugging independently of full
* compiler debug information simply by explicitly defining PARSER_DEBUG
* (with the t3make -D option, for example).
*/
#ifdef __DEBUG
#define PARSER_DEBUG
#endif
/*
* Define some convenience macros for parser debug operations. When
* PARSER_DEBUG isn't defined, these macros expand out to nothing.
*/
#ifdef PARSER_DEBUG
#define dbgShowGrammarList(lst) showGrammarList(lst)
#define dbgShowGrammarWithCaption(headline, match) \
showGrammarWithCaption(headline, match)
#else /* PARSER_DEBUG */
#define dbgShowGrammarList(lst)
#define dbgShowGrammarWithCaption(headline, match)
#endif /* PARSER_DEBUG */
/* ------------------------------------------------------------------------ */
/*
* Parser global variables giving information on the command currently
* being performed. These are valid through doAction processing. These
* should never be changed except by the parser.
*/
/* the actor performing the current command */
#define gActor (libGlobal.curActor)
/*
* For convenience, define some macros that return the current direct and
* indirect objects from the current action. The library only uses direct
* and indirect objects, so games that define additional command objects
* will have to add their own similar macros for those.
*/
#define gDobj (gAction.getDobj())
#define gIobj (gAction.getIobj())
/*
* Get the current ResolvedTopic, and the literal text of the topic phrase
* as the user typed it (but converted to lower case). These are
* applicable when the current action has a topic phrase.
*/
#define gTopic (gAction.getTopic())
#define gTopicText (gTopic.getTopicText.toLower())
/* get the current literal phrase text, when the command has one */
#define gLiteral (gAction.getLiteral())
/*
* The tentative pre-resolution lists for the direct and indirect objects.
* When we're resolving an object of a multi-object command, these
* pre-resolution lists are available for the later-resolved objects.
*
* Note that these values are list of ResolveInfo objects. The obj_
* property of a list entry gives the entry's game-world object.
*
* These lists do not provide the final resolution lists for the objects;
* rather, they provide a tentative set of possibilities based on the
* information that's available without knowing the results of resolving
* the earlier-resolved objects yet.
*
* These are not meaningful when resolving single-object actions.
*/
#define gTentativeDobj (gAction.getTentativeDobj())
#define gTentativeIobj (gAction.getTentativeIobj())
/*
* the actor who *issued* the current command (this is usually the player
* character, because most commands are initiated by the player on the
* command line, but it is also possible for one actor to send a command
* to another programmatically)
*/
#define gIssuingActor (libGlobal.curIssuingActor)
/* the Action object of the command being executed */
#define gAction (libGlobal.curAction)
/*
* Determine if the current global action is the specified action. Only
* the action prefix is needed - so use "Take" rather than "TakeAction"
* here.
*
* This tests to see if the current global action is an instance of the
* given action class - we test that it's an instance rather than the
* action class itself because the parser creates an instance of the
* action when it matches the action's syntax.
*/
#define gActionIs(action) \
(gAction != nil && gAction.actionOfKind(action##Action))
/* is the current global action ANY of the specified actions? */
#define gActionIn(action...) \
(gAction != nil \
&& (action#foreach/gAction.actionOfKind(action##Action)/||/))
/* the verification results object - this is valid during verification */
#define gVerifyResults (libGlobal.curVerifyResults)
/* the command transcript object - this is valid during command execution */
#define gTranscript (mainOutputStream.curTranscript)
/*
* Some message processors add their own special parameters to messages,
* because they want to use expansion parameters (in the "{the dobj/him}"
* format) outside of the set of objects directly involved in the command.
*
* The Action method setMessageParam() lets you define such a parameter,
* but for convenience, we define this macro for setting one or more
* parameters whose names exactly match their local variable names. In
* other words, if you call this macro like this:
*
* gMessageParams(obj, cont)
*
* then you'll get one parameter with the text name 'obj' whose expansion
* will be the value of the local variable obj, and another with text name
* 'cont' whose expansion is the value of the local variable cont.
*/
#define gMessageParams(var...) \
(gAction.setMessageParams(var#foreach/#@var, var/,/))
/*
* Synthesize a global message parameter name for the given object and
* return the synthesized name. This is useful in cases where there might
* be repeated instances of global message parameters in the same action,
* so it's not safe to use a fixed name string for the object. We'll
* create a unique global message parameter name, associate the object with
* the name, and return the name string.
*/
#define gSynthMessageParam(var) (gAction.synthMessageParam(var))
/* ------------------------------------------------------------------------ */
/*
* Miscellaneous macros
*/
/* get the current player character Actor object */
#define gPlayerChar (libGlobal.playerChar)
/*
* the exit lister object - if the exits module isn't included in the
* game, this will be nil
*/
#define gExitLister (libGlobal.exitListerObj)
/*
* the hint manager object - if the hints module isn't included in the
* game, this will be nil
*/
#define gHintManager (libGlobal.hintManagerObj)
/* ------------------------------------------------------------------------ */
/*
* The current library messages object. This is the source object for
* messages that don't logically relate to the actor carrying out the
* comamand. It's mostly used for meta-command replies, and for text
* fragments that are used to construct descriptions.
*
* This message object isn't generally used for parser messages or action
* replies - most of those come from the objects given by the current
* actor's getParserMessageObj() or getActionMessageObj(), respectively.
*
* By default, this is set to libMessages. The library never changes this
* itself, but a game can change this if it wants to switch to a new set of
* messages during a game. (If you don't need to change messages during a
* game, but simply want to customize some of the default messages, you
* don't need to set this variable - you can simply use 'modify
* libMessages' instead. This variable is designed for cases where you
* want to *dynamically* change the standard messages during the game.)
*/
#define gLibMessages (libGlobal.libMessageObj)
/* ------------------------------------------------------------------------ */
/*
* readMainCommandTokens() phase identifiers. We define a separate code
* for each kind of call to readMainCommandTokens() so that we can do any
* special token processing that depends on the type of command we're
* reading.
*
* The library doesn't use the phase information itself for anything.
* These phase codes are purely for the author's use in writing
* pre-parsing functions and for differentiating prompts for the different
* types of input, as needed.
*
* Games that read additional response types of their own are free to add
* their own enums to identify the additional phases. Since the library
* doesn't need the phase information for anything internally, it won't
* confuse the library at all to add new game-specific phase codes.
*/
/* reading a normal command line */
enum rmcCommand;
/* reading an unknown word response, to check for an "oops" command */
enum rmcOops;
/* reading a response to a prompt for a missing object phrase */
enum rmcAskObject;
/* reading a response to a prompt for a missing literal phrase */
enum rmcAskLiteral;
/* reading a response to an interactive disambiguation prompt */
enum rmcDisambig;
/* ------------------------------------------------------------------------ */
/*
* Property set definitions
*/
/* in debug mode, flag objFor definitions for non-existent actions */
#ifdef __DEBUG
# define objForCheck(which, action) \
sentinel##which##action = __objref(action##Action, warn)
#else
# define objForCheck(which, action)
#endif
#define objFor(which, action) \
objForCheck(which, action) \
propertyset '*' ## #@which ## #@action
#define dobjFor(action) objFor(Dobj, action)
#define iobjFor(action) objFor(Iobj, action)
/*
* Treat an object definition as equivalent to another object definition.
* These can be used immediately after a dobjFor() or iobjFor() to treat
* the first action as though it were the second. So, if the player types
* "search box", and we want to treat the direct object the same as for
* "look in box", we could make this definition for the box:
*
* dobjFor(Search) asDobjFor(LookIn)
*
* Note that no semicolon is needed after this definition, and that this
* definition is completely in lieu of a regular property set for the
* object action.
*
* In general, a mapping should NOT change the role of an object:
* dobjFor(X) should not usually be mapped using asIobjFor(Y), and
* iobjFor(X) shouldn't be mapped using asDobjFor(Y). The problem with
* changing the role is that the handler routines often assume that the
* object is actually in the role for which the handler was written; a
* verify handler might refer to '{dobj}' in generating a message, for
* example, so reversing the roles would give the wrong object in the role.
*
* Role reversals should always be avoided, but can be used if necessary
* under conditions where all of the code involved in the TARGET of the
* mapping can be carefully controlled to ensure that it doesn't make
* assumptions about object roles, but only references 'self'. Reversing
* roles in a mapping should never be attempted in general-purpose library
* code, because code based on the library could override the target of the
* role-reversing mapping, and the override could fail to observe the
* restrictions on object role references.
*
* Note that role reversals can almost always be handled with other
* mechanisms that handle reversals cleanly. Always consider remapTo()
* first when confronted with a situation that seems to call for a
* role-reversing asObjFor() mapping, as remapTo() specifically allows for
* object role changes.
*/
#define asObjFor(obj, Action) \
{ \
preCond { return preCond##obj##Action; } \
verify() { verify##obj##Action; } \
remap() { return remap##obj##Action; } \
check() { check##obj##Action; } \
action() { action##obj##Action; } \
}
#define asDobjFor(action) asObjFor(Dobj, action)
#define asIobjFor(action) asObjFor(Iobj, action)
/*
* Define mappings of everything except the action. This can be used in
* cases where we want to pick up the verification, preconditions, and
* check routines from another handler, but not the action. This is often
* useful for two-object verbs where the action processing is entirely
* provided by one or the other object, so applying it to both would be
* redundant.
*/
#define asObjWithoutActionFor(obj, Action) \
{ \
preCond { return preCond##obj##Action; } \
verify() { verify##obj##Action; } \
remap() { return remap##obj##Action(); } \
check() { check##obj##Action; } \
action() { } \
}
#define asDobjWithoutActionFor(action) asObjWithoutActionFor(Dobj, action)
#define asIobjWithoutActionFor(action) asObjWithoutActionFor(Iobj, action)
/*
* "Remap" an action. This effectively rewrites the action in the given
* form. Each of the object slots can be filled either with a specific
* object, or with a noun phrase role name (DirectObject, IndirectObject);
* in the latter case, the object or objects from the named noun phrase
* role in the *current* action (i.e., before the rewrite) will be used.
*
* If the new action has two or more objects (for example, if it's a
* TIAction), then EXACTLY ONE of the slots must be filled with a specific
* object, and all of the other slots must be filled with role names. The
* specific object is the one that corresponds to the original object
* that's doing the remapping in the first place - this can simply be
* 'self' if the new action will operate on the same object, or it can be
* a different object. The important thing is that the 'verify' method
* for the defining object will be forwarded to the corresponding 'verify'
* method on the corresponding object for the new action.
*
* This macro must be used as the ENTIRE definition block for a dobjFor()
* or iobjFor(). For example, to remap a "put in" command directed to a
* desk so that the command is instead applied to a drawer in the desk, we
* could define the following on the desk object:
*
* iobjFor(PutIn) remapTo(PutIn, DirectObject, deskDrawer)
*/
#define remapTo(action, objs...) { remap = [action##Action, ##objs] }
/*
* Conditionally remap an action. If 'cond' (a conditional expression)
* evaluated to true, we'll remap the action as directed; otherwise, we'll
* inherit the default handling
*/
#define maybeRemapTo(cond, action, objs...) \
{ remap = ((cond) ? [action##Action, ##objs] : inherited()) }
/*
* For two-object push-travel actions, such as "push sled into cave",
* define a special mapping for both the direct and indirect objects:
*
* - Map the direct object (the object being pushed) to a simple
* PushTravel action. So, for "push sled into cave," map the direct
* object handling to PushTravel for the sled. This makes the handling of
* the command equivalent to "push sled north" and the like.
*
* - Map the indirect object (the travel connector) to use the PushTravel
* action's verify remapper. This is handled specially by the PushTravel
* action object to handle the verification as though it were verifying
* the corresponding ordinary (non-push) travel action on the indirect
* object. Beyond verification, we do nothing, since the direct object of
* a pushable object will handle the whole action using a nested travel
* action.
*
* This effectively decomposes the two-object action into two coupled
* single-object actions: a regular PushTravel action on the object being
* pushed, and a regular whatever-kind-of-travel on the connector being
* traversed. This handling has the appeal that it means that we don't
* need a separate PUSH version of every kind of allowed travel on a
* connector, and we don't need a special handler version for each kind of
* travel on a pushable object; instead, we just use the basic PushTravel
* and kind-of-travel handlers to form the combined form. Note that this
* still allows separate treatment of the combined form wherever desired,
* just by overriding these default handlers for the two-object action.
*/
#define mapPushTravelHandlers(pushAction, travelAction) \
dobjFor(pushAction) asDobjFor(PushTravel) \
mapPushTravelIobj(pushAction, travelAction)
#define mapPushTravelIobj(pushAction, travelAction) \
iobjFor(pushAction) \
{ \
verify() \
{ gAction.verifyPushTravelIobj(self, travelAction##Action); } \
}
/* ------------------------------------------------------------------------ */
/*
* For an Actor, delegate an action handler to the ActorState object for
* processing. You can use this any time you want to write the handlers
* for a particular action in the ActorState rather than in the Actor
* itself. This would be desirable if the actor's response for a
* particular action varies considerably according to the actor's state.
* For example, if you want an actor's response to being attacked to be
* handled in the actor's current ActorState object, you could put this
* code in the Actor object:
*
* dobjFor(AttackWith) actorStateDobjFor(AttackWith)
*
* Once you've done this, you'd just write a normal dobjFor(AttackWith)
* handler in each of the ActorState objects associated with the actor.
*/
#define actorStateObjFor(obj, Action) \
{ \
preCond { return curState.preCond##obj##Action; } \
verify() { curState.verify##obj##Action; } \
remap() { return curState.remap##obj##Action; } \
check() { curState.check##obj##Action; } \
action() { curState.action##obj##Action; } \
}
#define actorStateDobjFor(action) actorStateObjFor(Dobj, action)
#define actorStateIobjFor(action) actorStateObjFor(Iobj, action)
/* ------------------------------------------------------------------------ */
/*
* Object role identifiers. These are used to identify the role of a noun
* phrase in a command.
*
* The library provides base classes for actions of zero, one, and two noun
* phrases in their grammars: "look", "take book", "put book on shelf". We
* thus define role identifiers for direct and indirect objects. Note that
* even though we stop there, this doesn't preclude games or library
* extensions from adding actions that take more than two noun phrases
* ("put coin in slot with tongs"); any such extensions must simply define
* their own additional role identifiers for the third or fourth (etc) noun
* phrase.
*/
enum ActorObject, DirectObject, IndirectObject;
/*
* A special role for the "other" object of a two-object command. This
* can be used in certain contexts (such as remapTo) where a particular
* object role is implied by the context, and where the action involved
* has exactly two objects; OtherObject in such contexts means
* DirectObject when the implied role is IndirectObject, and vice versa.
*/
enum OtherObject;
/* ------------------------------------------------------------------------ */
/*
* Pronoun types. These are used to identify pronoun antecedents when
* resolving noun phrases involving pronouns.
*
* We define a basic set of pronouns here that are common to most
* languages. Language-specific modules are free to add their own pronoun
* types as needed.
*
* Our basic set is:
*
* 'it' - the neuter singular
*. 'him' - the masculine singular
*. 'her' - the feminine singular
*. 'them' - the ungendered plural
*. 'you' - second person singular
*. 'me' - first person singular
*
* Note that the first-person and second-person pronouns are assigned
* meanings that can vary by context. When a command is issued by the
* player character to the player character (i.e., the command comes from
* the player and no target actor is specified), these refer to the player
* character when the PC is in the appropriate referral person - if the
* game calls the PC "you", then the player calls the PC "me", and vice
* versa. When a command is targeted to or issued by an actor other than
* the PC, then "you" refers to the command's target and "me" refers to
* the command's issuer.
*/
enum PronounIt, PronounThem, PronounHim, PronounHer, PronounYou, PronounMe;
/* ------------------------------------------------------------------------ */
/*
* set the location property
*/
+ property location;
/* ------------------------------------------------------------------------ */
/*
* Alternative exit definition. This can be used to define a secondary
* direction that links to the same destination, via the same connector, as
* another direction. It's frequently desirable to link multiple
* directions to the same exit; for example, a door leading north might
* also lead out, or a stairway to the north could lead up as well.
*
* Use this as follows in a room's property list:
*
*. out asExit(north)
*
* (Note that there's no '=' sign.)
*
* It's not necessary to use this macro to declare an alternative exit,
* since the alternatives can all point directly to the same connector as
* the original. The only thing this macro does is to make the alternative
* exit unlisted - it won't be shown in the list of exits in the status
* line, and it won't be shown in "you can't go that way" messages.
*
* Note that there's one common case where you should be careful with
* asExit(): if you have a room that has an exit in some compass direction,
* you might be tempted to make OUT the primary "direction" for the exit,
* and treat the equivalent compass as a synonym, with a line such as
* "south asExit(out)". You should avoid doing this - do it the other way
* instead, with the compass direction as the primary direction and OUT as
* the synonym: "out asExit(south)". The reason this is important is that
* if there's a nested room inside the location (such as a chair), OUT
* while in the nested room will mean to get out of the nested room. If
* you make the compass direction primary and make OUT the synonym, the
* compass direction will be listed as an available exit both in the
* location and in any nested rooms within it.
*/
#define asExit(dir) = static ((dir).createUnlistedProxy())
/* ------------------------------------------------------------------------ */
/*
* "Person" indices. We define these as numbers rather than enums so that
* we can easily use these as list indices.
*/
#define FirstPerson 1
#define SecondPerson 2
#define ThirdPerson 3
/* ------------------------------------------------------------------------ */
/*
* Transparency levels
*/
/* the sense is passed without loss of detail */
enum transparent;
/* the sense is passed, but with a loss of detail associated with distance */
enum distant;
/*
* The sense is passed, but with attenuation of energy level. No other
* obscuration of detail occurs; this is something like tinted glass that
* doesn't distort the transmitted sense but reduces the amount of energy.
*/
enum attenuated;
/*
* The sense is passed, but with a loss of detail due to an obscuring
* layer of material. The energy level is also attenuated. This is
* something like dirty or wavy glass that distorts an image transmitted
* through it but doesn't completely block out light.
*/
enum obscured;
/* the sense is not passed at all */
enum opaque;
/* ------------------------------------------------------------------------ */
/*
* Size classes. An object is large, medium, or small with respect to
* each sense; the size is used to determine how well the object can be
* sensed at a distance or when obscured.
*
* What "size" means depends on the sense. For sight, the size
* indicates the visual size of the object. For hearing, the size
* indicates the loudness of the object.
*/
/*
* Large - the object is large enough that its details can be sensed
* from a distance or through an obscuring medium.
*/
enum large;
/*
* Medium - the object can be sensed at a distance or when obscured, but
* not in any detail. Most objects fall into this category. Note that
* things that are parts of large objects should normally be medium.
*/
enum medium;
/*
* Small - the object cannot be sensed at a distance at all. This is
* appropriate for detailed parts of medium-class objects.
*/
enum small;
/* ------------------------------------------------------------------------ */
/*
* Path traversal operations.
*/
/* traverse from the starting point of the path */
enum PathFrom;
/* traverse into the contents */
enum PathIn;
/* traverse out to the container */
enum PathOut;
/* traverse from an object to a peer at the same containment level */
enum PathPeer;
/*
* traverse through an object with no common container on either side of
* the traversal - this is used when we are traversing an object, such as a
* SenseConnector, that connects unrelated locations
*/
enum PathThrough;
/* traverse to the ending point of the path */
enum PathTo;
/* ------------------------------------------------------------------------ */
/*
* Listing Options
*/
/*
* use "tall" notation, which lists objects in a single column, one item
* per line (the default is "wide" notation, which creates a sentence
* with the object listing)
*/
#define ListTall 0x0001
/*
* Recursively list the contents of each item we list.
*
* For a 'tall' list, this indicates that we'll show the listed contents
* of each item that we list, and the listed contents of those items, and
* so on, indenting each level to indicate the containment relationship.
*
* For a 'wide' list, this indicates that we'll show the listed contents
* of each item in-line in the listing, as a parenthetic note.
*
* For both types of listings, when this flag is set and the indent level
* is zero (indicating a top-level listing), after the main list, we'll
* show a separate list for the contents of each item in our list that
* isn't itself listable but has listed contents, or has contents with
* listed contents, and so on to any level. For example, if we're showing
* a room description, and the room contains a desk that isn't listed
* because it's a fixed part of the room, we'll show a separate list of
* the desk's listed contents.
*/
#define ListRecurse 0x0002
/*
* use "long list" notation - separates items that contain sublists with
* special punctuation, to set off the individual items in the longer
* listing from the items in the sublists (for example, separates items
* with semicolons rather than commas)
*/
#define ListLong 0x0004
/*
* This is a recursive listing of the contents of an item. This is set by
* showList() in calls it makes to recursive listing levels.
*/
#define ListContents 0x0008
/*
* Custom option bits. Flag bits with this value and higher are reserved
* for use by individual lister subclasses.
*
* To ensure compatibility with any future changes that involve adding
* more base lister flags, subclasses are encouraged to use the following
* mechanism. DO NOT use #define to define your own custom subclass
* flags. Instead, define a property of your lister subclass for each
* flag you need as follows:
*
* myCustomFlag1 = ListerCustomFlag(1) // use 1 for the first flag
*. myCustomFlag2 = ListerCustomFlag(2) // etc
*. nextCustomFlag = ListerCustomFlag(3)
*
* You DO NOT have to use the name 'myCustomFlag1' - use whatever name you
* like that describes the nature of the flag. However, the last item
* MUST be called 'nextCustomFlag' - this ensures that any subclasses of
* your class will allocate their own flags with new values that don't
* conflict with any of yours.
*
* Then, when a client of your Lister subclass needs to pass one of your
* flag to the Lister, it should simply evaluate your 'myCustomFlagN'
* property of your lister. If you'd like, you can even #define a ListXxx
* macro that retrieves the value, for the convenience of your callers:
*
* #define ListMyclassMyCustomFlag1 (Myclass.myCustomFlag1)
*/
#define ListCustomFlag 0x0100
#define ListerCustomFlag(n) static ((inherited.nextCustomFlag) << ((n) - 1))
/* ------------------------------------------------------------------------ */
/*
* Spelled-out number options, for spellInt() and related functions.
*
* Note that the interfaces to the number-spelling functions can vary by
* language, and that variation can include these flags. Some language
* modules might ignore some of these generic flags or define additional
* language-specific flags.
*/
/*
* Use tens of hundreds rather than thousands if possible - 1950 is
* 'nineteen hundred fifty' rather than 'one thousand nine hundred
* fifty'. This only works if the number (not including the millions
* and billions) is in the range 1,100 to 9,999, because we don't want
* to say something like 'one hundred twenty hundred' for 12,000.
*/
#define SpellIntTeenHundreds 0x0001
/*
* use 'and' before the tens - 125 is 'one hundred and twenty-five'
* rather than 'one hundred twenty-five'
*/
#define SpellIntAndTens 0x0002
/*
* put a comma after each power group - 123456 is 'one hundred
* twenty-three thousand, four hundred fifty-six'
*/
#define SpellIntCommas 0x0004
/* ------------------------------------------------------------------------ */
/*
* Decimal number format options. These are used with the number
* formatting functions to control the formatting of numbers displayed in
* decimal digit format.
*/
/*
* Use a group separator character between digit groups, using the
* default setting in languageGlobals.
*/
#define DigitFormatGroupSep 0x0001
/*
* Explicitly use a comma/period to separate digit groups, overriding
* the current languageGlobals setting.
*/
#define DigitFormatGroupComma 0x0002
#define DigitFormatGroupPeriod 0x0004
/* ------------------------------------------------------------------------ */
/*
* aHref() flags
*/
#define AHREF_Plain 0x0001 /* plain text hyperlink (no underline/color) */
/* ------------------------------------------------------------------------ */
/*
* ResolveInfo flags
*/
/* the noun phrase ends with an adjective */
#define EndsWithAdj 0x0001
/*
* one of the words in the noun phrase was truncated from its full
* dictionary spelling
*/
#define VocabTruncated 0x0002
/*
* One or more plurals was truncated from its full dictionary spelling.
* (We specially distinguish plurals that are truncated, because in
* English a plural is usually formed by adding "s" or "es" to the end of
* the singular form of a noun, meaning that a given singular form is
* usually a leading substring of its plural. When a singular noun is
* longer than the truncation limit, which is conventionally six
* characters, the singular will always match as a truncated version of
* the plural, so every time someone types in a singular it'll be treated
* as ambiguous between the singular and plural form. So, in the English
* parser, we have a preference to ignore a truncated plural any time the
* word could also be interpreted as an untruncated singular, hence we
* note when we have a truncated plural.)
*/
#define PluralTruncated 0x0004
/*
* The object came from an 'all' phrase. Normally, the only time this
* makes any difference is when deciding whether or not to mention which
* object we're acting upon; an 'all' object should normally be mentioned
* explicitly, as though the command had involved multiple objects,
* because otherwise it might not be clear to the user what object had
* actually matched 'all'.
*/
#define MatchedAll 0x0008
/*
* Always announce the object before executing the command on it. This
* flag can be set for objects that match phrases whose meaning isn't
* necessarily known to the player, such as "all" (which selects objects
* based on the simulation state, which might not exactly match what the
* player had in mind) or "any book" (which might select arbitrarily from
* several possibilities, so the player can't know which we'll choose).
*/
#define AlwaysAnnounce 0x0010
/*
* The noun phrase describing this object was ambiguous, and the object
* was selected by automatic disambiguation in a context where it was
* clear which object was indicated. This is used in cases where the
* objects not selected were all illogical for the action context.
*/
#define ClearDisambig 0x0020
/*
* The noun phase describing this object was ambiguous, and the object was
* selected by automatic disambiguation in a context where it was not
* perfectly clear which object was indicated. This is used for cases
* where the objects selected were more logical than the objects not
* selected, but some of the unselected objects were still logical.
*
* This flag doesn't mean that we chose arbitrarily, but rather that we
* chose the best object or objects from a field that included additional
* objects that, though not quite as good, were still valid. We flag this
* case because the user *could* have meant to use one of the other valid
* objects, even though we consider it most likely that the user meant to
* use the one(s) we selected; so, we want to flag this so we can call the
* user's attention to our choice, to make it more likely that the user
* will immediately notice if we made the wrong choice.
*
* Note that we can't have both ClearDisambig and UnclearDisambig at the
* same time, but we *can* have neither of these. If neither flag is set
* for an object, it simply means that the object wasn't ambiguous to
* start with. When the user explicitly picks an object interactively,
* the selected object is effectively unambiguous, so it won't have either
* flag set; even though it started off ambiguous, the user did all of the
* work of selecting the appropriate object, leaving things unambiguous in
* the end.
*/
#define UnclearDisambig 0x0040
/*
* The noun phrase was missing from the command and this object was
* supplied as an implicit default.
*/
#define DefaultObject 0x0080
/*
* We've announced this as a defaulted object. We use this to ensure that
* we only make this type of announcement once, even if the opportunity to
* make the announcement comes up more than once; this can happen when
* we're asking for missing objects interactively in a multi-object
* command, since we might want to announce a default before prompting as
* well as before execution.
*/
#define AnnouncedDefaultObject 0x0100
/* ------------------------------------------------------------------------ */
/*
* Announcement styles for disambiguated objects. These are used in the
* gameMain object (see GameMainDef) to select which type of announcement
* is used when the parser disambiguates a noun phrase using the
* logicalness rules.
*/
/*
* Announce unclear disambiguation results only. When this setting is
* selected, the parser makes a parenthetical announcement (e.g., "(the red
* door)") when it selects an object based on likelihood rankings from
* among more than one logical match. The parser makes no announcement
* when exactly one logical object is in scope, even if other objects match
* the noun phrase by name.
*/
enum AnnounceUnclear;
/*
* Announce clear and unclear disambiguation results, both using
* parenthetical announcement ("(the red door)"). When this setting is
* selected, the parser makes these announcements every time it applies the
* logicalness rules or likelihood rankings to disambiguate a noun phrase.
* There's no announcement when no disambiguation is needed (because the
* noun phrase matches only one in-scope object).
*/
enum AnnounceClear;
/*
* Describe clear disambiguation results, rather than announcing them. The
* parser makes the parenthetical announcement, as usual, for unclear
* disambiguation picks, but not for clear picks (a clear pick is one where
* there's only one logical object, even though the noun phrase matches
* more than one object). For clear picks, however, the parser uses a
* verbose version of the action reply in lieu of one of the terse default
* messages. For example, rather than saying just "Taken", the parser
* would reply "You take the red book." The longer messages mention the
* object by name, to make it clear exactly which one was chosen.
*/
enum DescribeClear;
/* ------------------------------------------------------------------------ */
/*
* Inventory modes. "Wide" mode displays the inventory in paragraph form;
* "tall" mode displays as a list, with one item per line, indenting items
* to reflect containment.
*/
enum InventoryWide, InventoryTall;
/* ------------------------------------------------------------------------ */
/*
* Define an action with the given base class. This adds the *Action
* suffix to the given root name, and defines a class with the given base
* class. We also define the baseActionClass property to refer to myself;
* this is the canonical class representing the action for all subclasses.
* This information is useful because a language module might define
* several grammar rule subclasses for the given class; this lets us
* relate any instances of those various subclasses back to this same
* canonical class for the action if necessary.
*/
#define DefineAction(name, baseClass...) \
class name##Action: ##baseClass \
baseActionClass = name##Action
/*
* Define a "system" action. System actions are meta-game commands, such
* as SAVE and QUIT, that generally operate the user interface and are not
* part of the game world.
*/
#define DefineSystemAction(name) \
DefineAction(name, SystemAction)
/*
* Define a concrete IAction, given the root name for the action. We'll
* automatically generate a class with name XxxAction.
*/
#define DefineIAction(name) \
DefineAction(name, IAction)
/* define a conversational IAction, such as Hello, Goodbye, Yes, No */
#define DefineConvIAction(name) \
DefineAction(name, ConvIAction)
/*
* Define a concrete TAction, given the root name for the action. We'll
* automatically generate a class with name XxxAction, a verProp with name
* verXxx, a checkProp with name checkXxx, and an actionProp with name
* actionDobjXxx.
*/
#define DefineTAction(name) \
DefineTActionSub(name, TAction)
/*
* Define a concrete TAction with a specific base class.
*/
#define DefineTActionSub(name, cls) \
DefineAction(name, cls) \
verDobjProp = &verifyDobj##name \
remapDobjProp = &remapDobj##name \
preCondDobjProp = &preCondDobj##name \
checkDobjProp = &checkDobj##name \
actionDobjProp = &actionDobj##name \
/*
* Define a concrete TIAction, given the root name for the action. We'll
* automatically generate a class with name XxxAction, a verDobjProp with
* name verDobjXxx, a verIobjProp with name verIobjxxx, a checkDobjProp
* with name checkDobjXxx, a checkIobjProp with name checkIobjXxx, an
* actionDobjProp with name actionDobjXxx, and an actionIobjProp with name
* actionIobjXxx.
*/
#define DefineTIAction(name) \
DefineTIActionSub(name, TIAction)
/*
* Define a concrete TIAction with a specific base class.
*/
#define DefineTIActionSub(name, cls) \
DefineAction(name, cls) \
verDobjProp = &verifyDobj##name \
verIobjProp = &verifyIobj##name \
remapDobjProp = &remapDobj##name \
remapIobjProp = &remapIobj##name \
preCondDobjProp = &preCondDobj##name \
preCondIobjProp = &preCondIobj##name \
checkDobjProp = &checkDobj##name \
checkIobjProp = &checkIobj##name \
actionDobjProp = &actionDobj##name \
actionIobjProp = &actionIobj##name
/*
* Define a concrete TopicAction, given the root name for the action.
*/
#define DefineTopicAction(name) \
DefineAction(name, TopicAction)
/*
* Define a concrete TopicTAction, given the root name for the action.
* 'which' gives the role the topic serves, for message generation purposes
* - this should be one of the object role enums (DirectObject,
* IndirectObject, etc) indicating which role the topic plays in the
* action's grammar.
*/
#define BaseDefineTopicTAction(name, which, cls) \
DefineAction(name, cls) \
verDobjProp = &verifyDobj##name \
remapDobjProp = &remapDobj##name \
preCondDobjProp = &preCondDobj##name \
checkDobjProp = &checkDobj##name \
actionDobjProp = &actionDobj##name \
whichMessageTopic = which
#define DefineTopicTAction(name, which) \
BaseDefineTopicTAction(name, which, TopicTAction)
/*
* Define a concrete ConvTopicTAction. This is just like defining a
* TopicTAction, but defines the action using the ConvTopicTAction
* subclass.
*/
#define DefineConvTopicTAction(name, which) \
BaseDefineTopicTAction(name, which, ConvTopicTAction)
/*
* Define a concrete LiteralAction, given the root name for the action.
*/
#define DefineLiteralAction(name) \
DefineAction(name, LiteralAction)
/*
* Define a concrete LiteralTAction, given the root name for the action.
* 'which' gives the role the literal phrase serves, for message generation
* purposes - this should be one of the object role enums (DirectObject,
* IndirectObject, etc) indicating which role the topic plays in the
* action's grammar.
*/
#define DefineLiteralTAction(name, which) \
DefineAction(name, LiteralTAction) \
verDobjProp = &verifyDobj##name \
remapDobjProp = &remapDobj##name \
preCondDobjProp = &preCondDobj##name \
checkDobjProp = &checkDobj##name \
actionDobjProp = &actionDobj##name \
whichMessageLiteral = which
/* ------------------------------------------------------------------------ */
/*
* Convenience macros for setting verify results.
*
* A verify routine can use these macros to set any number of verify
* results. The VerifyResultList will keep only the result that gives the
* strongest disapproval of the action, since the verification process is
* by its nature only interested in the most negative result.
*
* These macros take advantage of the fact that we have a global
* VerifyResultList object, which gathers the results of the verification,
* so they can be used only in verify routines. The global verification
* results object is valid during each verification invocation.
*/
/*
* Command is logical. There's generally no need to add a logical result
* explicitly, since a command is logical unless disapproved, but we
* include this for completeness.
*
* We use 100 as the default likelihood, to leave plenty of room for
* specific likelihood rankings both above and below the default level.
*/
#define logical \
(gVerifyResults.addResult(new LogicalVerifyResult(100, '', 100)))
/*
* Command is logical, and is ranked as indicated among logical results.
* The 'rank' value is the likelihood rank; the higher the rank, the more
* logical the command is. The rank is only used to establish an ordering
* of the logical results; if a command also has illogical results, all of
* the illogical results rank as less logical than the logical result with
* the lowest likelihood.
*
* The 'key' value is an arbitrary string value associated with the
* ranking. When two result lists both have a logical result object, and
* both logical result objects have the same likelihood level, we'll check
* the keys; if the keys match, we'll treat the two results as equivalent
* and thus not distinguishing for disambiguation. This is useful because
* it creates a crude multivariate space for ranking items for
* disambiguation.
*
* For example, suppose we have a "put in" command, and we have two
* possibilities for the target container. Neither is being held by the
* actor, so they both have a result with a logical rank of 70 with a key
* value of 'not held'. In addition, both are openable, and one is open
* and the other is closed; the closed one has an additional result with a
* logical rank of 80 and a key of 'not open'. Which do we choose? If we
* looked only at the logical rankings, both would be equivalent, since
* both have 70's as their most disapproving results. However, we see
* that the two 70's were applied for the same reason - because they share
* a common key - so we know this information isn't helpful for
* disambiguation and can be ignored. So, we find that the closed one has
* an 80, and the other has no other results (hence is by default logical
* with rank 100), thus we take the '80' as the better one.
*
* Throughout the library, we use the following conventions:
*
* 150 = especially good fit: a good candidate for the action that is
* especially likely to be used with the command. For example, a book is
* especially suitable for a "read" command.
*
* 140 = similar to 150, but slightly less ideal a fit. We use this for
* objects that are excellent fits, but for which we know certain other
* objects might be better fits.
*
* 100 = default: a perfectly good candidate for the action, with nothing
* that would make it illogical, but nothing that makes it especially
* likely, either
*
* 80 = slightly less than perfect: a good candidate, but with some
* temporary and correctable attribute that may make it less likely than
* others. This is used for attributes that can be corrected: a container
* needs to be opened for the action to succeed, but isn't currently open,
* or an article of clothing cannot be worn for the action to proceeds,
* but is currently being worn.
*
* 60/70 = slightly less than perfect, but with some attributes that can't
* be readily corrected and which make the candidate potentially less
* likely. These are used to make guesses about which might object might
* be intended when several are logical but some might be more readily
* used than others; for example, if putting an object into a container, a
* container being held might rank higher than one not being held, so the
* one not being held might be ranked a "70" likelihood.
*
* 50 = logical but not especially likely: an acceptable candidate for the
* action, but probably not the best choice for the action. This is used
* when an object can be used for the action, but would not be expected to
* do anything special with the action.
*/
#define logicalRank(rank, key) \
(gVerifyResults.addResult(new LogicalVerifyResult(rank, key, 100)))
/*
* Logical ranking with specific list ordering. This is the same as a
* regular logicalRank, but uses the given list ordering rather than the
* default list ordering (100).
*/
#define logicalRankOrd(rank, key, ord) \
(gVerifyResults.addResult(new LogicalVerifyResult(rank, key, ord)))
/* command is logical but dangerous */
#define dangerous \
(gVerifyResults.addResult(new DangerousVerifyResult('')))
/*
* command is logical but non-obvious: the object should never be taken as
* a default
*/
#define nonObvious \
(gVerifyResults.addResult(new NonObviousVerifyResult('')))
/* command is currently (but not always) illogical, for the given reason */
#define illogicalNow(msg, params...) \
(gVerifyResults.addResult(new IllogicalNowVerifyResult(msg, ##params)))
/* illogical because things are already as the command would make them */
#define illogicalAlready(msg, params...) \
(gVerifyResults.addResult( \
new IllogicalAlreadyVerifyResult(msg, ##params)))
/* command is always illogical */
#define illogical(msg, params...) \
(gVerifyResults.addResult(new IllogicalVerifyResult(msg, ##params)))
/* illogical since we're trying to use something on itself (eg, PUT X IN X) */
#define illogicalSelf(msg, params...) \
(gVerifyResults.addResult(new IllogicalSelfVerifyResult(msg, ##params)))
/* command is being performed on an inaccessible object */
#define inaccessible(msg, params...) \
(gVerifyResults.addResult(new InaccessibleVerifyResult(msg, ##params)))
/* ------------------------------------------------------------------------ */
/*
* Convenience macros for setting command results.
*/
/*
* Set a default report for the current command. This report will be
* shown unless a non-default report is issued, or if the default report
* is to be suppressed (for example, because the command is being
* performed implicitly as part of another command).
*
* Default reports should be used only for simple acknowledgments of the
* command's successful completion - things like "Taken" or "Dropped" or
* "Done."
*
* Default responses are suppressed for implicit commands because they are
* redundant. When a command is performed implicitly, it is conventional
* to mention the command being performed with a parenthetical: "(First
* taking the book)". In such cases, a simple acknowledgment that the
* command was successfully performed would add nothing of use but would
* merely make the output more verbose, so we omit it.
*/
#define defaultReport(msg, params...) \
(gTranscript.addReport(new DefaultCommandReport(msg, ##params)))
/*
* Set a default descriptive report for the current command. This report
* will be shown unless any other report is shown for the same command.
* This differs from defaultReport in that we don't suppress a default
* description for an implied command: we only suppress a default
* description when there are other reports for the same command.
*
* The purpose of the default descriptive report is to generate reports
* that say things along the lines that there's nothing special to
* describe. For example:
*
* >x desk
*. You see nothing special about it.
*
* >look in alcove
*. There's nothing in the alcove.
*
* When there's nothing else to report, these default descriptions are
* suitable as the full response to the command. However, they become
* undesirable when we have other "status" information or related special
* descriptions to display; consider:
*
* >x desk
*. You see nothing special about it.
*. Someone has jabbed a dagger into the top of the desk.
*
* >look in alcove
*. There's nothing in the alcove.
*. A vase is displayed in the alcove.
*
* >x bag
*. You see nothing special about it. It's open, and it contains
*. a red book, an iron key, and a brass key.
*
* In the first two examples above, we have special descriptions for
* objects contained in the objects being described. The special
* descriptions essentially contradict the default descriptions' claims
* that there's nothing special to mention, and also render the default
* descriptions unnecessary, in that it would be enough to show just the
* special descriptions. The third example above is similar, but the
* extra information is status information for the object being described
* rather than a special description of a contained item; as with the
* other examples, the generic default description is both contradictory
* and unnecessary.
*
* Default description reports should ONLY be used for messages that have
* the character of the examples above: generic descriptions that indicate
* explicitly that there's nothing special to report. Messages that offer
* any sort of descriptive detail should NOT be generated as default
* description reports, because it is suitable and desirable to retain an
* actual descriptive message even when other status information or
* related special descriptions are also shown.
*/
#define defaultDescReport(msg, params...) \
(gTranscript.addReport(new DefaultDescCommandReport(msg, ##params)))
/*
* Add an cosmetic internal spacing report. This type of report is used
* to show spacing (usually a paragraph break) within command output.
*
* The important thing about this report is that it doesn't trigger
* suppression of any default reports. This is useful when internal
* separation is added on speculation that there might be some reports to
* separate, but without certainty that there will actually be any reports
* shown; for example, when preparing to show a list of special
* descriptions, we might add some spacing just in case some special
* descriptions will be shown, saving the trouble of checking to see if
* anything actually needs to be shown.
*/
#define cosmeticSpacingReport(msg, params...) \
(gTranscript.addReport(new CosmeticSpacingCommandReport(msg, ##params)))
/*
* Add an "extra" report. This is an incidental message that doesn't
* affect the display of a default report.
*/
#define extraReport(msg, params...) \
(gTranscript.addReport(new ExtraCommandReport(msg, ##params)))
/*
* Set a main report for the current command. This report will be shown
* as the main report from the command, overriding any default report for
* the command.
*/
#define mainReport(msg, params...) \
(gTranscript.addReport(new MainCommandReport(msg, ##params)))
/*
* Set a "before" report for the current command. This report will be
* shown before any main report, but will override any default report for
* the command.
*/
#define reportBefore(msg, params...) \
(gTranscript.addReport(new BeforeCommandReport(msg, ##params)))
/*
* Set an "after" report for the current command. This report will be
* shown after any main report, but will override any default report for
* the command.
*/
#define reportAfter(msg, params...) \
(gTranscript.addReport(new AfterCommandReport(msg, ##params)))
/*
* Report failure. This overrides any default report, and marks the
* command as having failed.
*
* A failure report should NOT indicate any state change - this is
* important because failure reports are suppressed under some conditions
* (for example, when an NPC is performing an implied command, and the
* implied command fails, we don't show the failure report). If a failure
* is accompanied by a state change, then a mainReport() should be made in
* addition to the failure report - the main report should indicate the
* state change.
*/
#define reportFailure(msg, params...) \
(gTranscript.addReport(new FailCommandReport(msg, ##params)))
/*
* Report a question. This shows a report that's really an interactive
* prompt for more information, such as a prompt for a missing object.
*/
#define reportQuestion(msg, params...) \
(gTranscript.addReport(new QuestionCommandReport(msg, ##params)))
/* ------------------------------------------------------------------------ */
/*
* Thing message property overrides sometimes need to be selective about
* the role of the object. These macros let you specify that a Thing
* message override is only in effect when the Thing is the direct or
* indirect object. When the object isn't in the specified role, the
* message override will be ignored.
*
* For example, suppose you want to override an object's response to PUT
* IN, but *only* when it's the indirect object of PUT IN - *not* when the
* object is itself being put somewhere. To do this, you could give the
* object a property like this:
*
*. notAContainerMsg = iobjMsg('The vase\'s opening is too small. ')
*
* This specifies that when the object is involved in a PUT IN command that
* fails with the 'notAContainerMsg' message, the given message should be
* used - but *only* when the object is the indirect object.
*/
#define dobjMsg(msg) (gDobj == self ? msg : nil)
#define iobjMsg(msg) (gIobj == self ? msg : nil)
/* ------------------------------------------------------------------------ */
/*
* Try performing a command implicitly. The action is the root name of
* the action, without the 'Action' suffix - we'll automatically add the
* suffix. 'objs' is a varying-length list of the resolved objects in the
* new action - the direct object, indirect object, and any others needed
* for the action.
*/
#define tryImplicitAction(action, objs...) \
_tryImplicitAction(gIssuingActor, gActor, &announceImplicitAction, \
action##Action, ##objs)
/*
* Try performing a command implicitly, with a special descriptive
* message. 'msgProp' gives the libMessages method to invoke the announce
* the action, if the action is performed. If 'msgProp' is nil, no
* message is displayed at all.
*
* 'action' is the root name of the action, without the 'Action' suffix
* (we'll automatically add the suffix). 'objs' is a varying-length list
* of the resolved objects - direct object, indirect object, and any
* others needed.
*/
#define tryImplicitActionMsg(msgProp, action, objs...) \
_tryImplicitAction(gIssuingActor, gActor, msgProp, \
action##Action, ##objs)
/*
* Replace the current action with a new action. The new action will be
* performed, and the original action will be terminated with 'exit'.
*
* 'action' is the root name of the action, without the 'Action' suffix
* (we'll add the suffix automatically). 'objs' is a varying-length list
* of the resolved objects - direct object, indirect object, etc.
*/
#define replaceAction(action, objs...) \
_replaceAction(gActor, action##Action, ##objs)
/*
* Replace the current action with a new action directed to a different
* actor (but from the same issuing actor).
*/
#define replaceActorAction(actor, action, objs...) \
_replaceAction(actor, action##Action, ##objs)
/*
* Run a nested action.
*/
#define nestedAction(action, objs...) \
_nestedAction(nil, gActor, action##Action, ##objs)
/*
* Run a nested action targeted to a given actor.
*/
#define nestedActorAction(actor, action, objs...) \
_nestedAction(nil, actor, action##Action, ##objs)
/*
* Run a new action. This is a brand new action run as a separate turn,
* not as a nested action. This doesn't replace any current action, but is
* simply a separate action.
*
* This is normally used only for internal actions that are run between
* other actions. This should not normally be used while another action is
* being processed - use nestedAction for that instead. This should also
* not normally be used to replace the current action with another - use
* replaceAction for that.
*
* Returns a CommandTranscript object, which provides information on the
* results of the action.
*/
#define newAction(action, objs...) \
_newAction(CommandTranscript, nil, gActor, action##Action, ##objs)
/* run a new action with a specific actor */
#define newActorAction(actor, action, objs...) \
_newAction(CommandTranscript, nil, actor, action##Action, ##objs)
/*
* Ask for a direct object and retry the command using the single-object
* phrasing. This can be used in the action() routine for a no-object
* command to ask for the missing direct object.
*
* In many cases, there is simply no grammar rule for a zero-object form
* of a verb; in such cases, this macro is not needed, since the missing
* object is handled via the grammar. However, for some actions, it is
* desirable to allow the zero-object phrasing some of the time, but
* require the direct-object phrasing other times. This macro exists for
* these cases, because it allows the intransitive version of the action
* to decide, on a case-by-case basis, whether to process the no-object
* form of the command or to prompt for a direct object.
*
* newAction is the root name (without the Action suffix) of the
* transitive action to execute. For example, if we're processing a plain
* "in" command, we could use askForDobj(Enter) to ask for a direct object
* for the transitive "enter" phrasing.
*/
#define askForDobj(newAction) \
(newAction##Action.retryWithMissingDobj(gAction, ResolveAsker))
/*
* Ask for an indirect object and retry the command using the two-object
* phrasing. This can be used in the action() routine of a single-object
* command to ask for the missing indirect object.
*
* In many cases, there is simply no grammar rule for a single-object form
* of a verb; in such cases, this macro is not needed, since the missing
* object is handled via the grammar. However, for some actions, it is
* desirable to allow the single-object phrasing some of the time, but
* require the two-object phrasing other times. This macro exists for
* these cases, because it allows the action() routine to decide, on a
* case-by-case basis, whether to process the single-object form of the
* command or to prompt for an indirect object.
*
* newAction is the root name (without the Action suffix) of the
* two-object form of the action. For example, if we're processing a
* single-object "unlock" command, we would use askForIobj(UnlockWith) to
* ask for an indirect object for the "unlock with" two-object phrasing.
*/
#define askForIobj(newAction) \
(newAction##Action.retryWithMissingIobj(gAction, ResolveAsker))
/*
* Ask for a literal phrase and retry the command using the two-object
* phrasing. This is analogous to askForDobj() and askForIobj(), but for
* literal phrases; we effectively convert a TAction into a
* LiteralTAction.
*/
#define askForLiteral(newAction) \
(newAction##Action.retryWithMissingLiteral(gAction))
/*
* Ask for a topic phrase and retry the command using the two-object
* phrasing.
*/
#define askForTopic(newAction) \
(newAction##Action.retryWithMissingTopic(gAction))
/* ------------------------------------------------------------------------ */
/*
* Command interruption signal macros.
*/
/* a concise macro to throw an ExitSignal */
#define exit throw new ExitSignal()
/* a concise macro to throw an ExitActionSignal */
#define exitAction throw new ExitActionSignal()
/* a concise macro to throw an AbortImplicitSignal */
#define abortImplicit throw new AbortImplicitSignal()
/* ------------------------------------------------------------------------ */
/*
* Flags for LOOK AROUND styles
*/
/* show the room name as part of the description */
#define LookRoomName 0x0001
/* show the room's long desription (the roomDesc) */
#define LookRoomDesc 0x0002
/* show the non-portable items (the specialDesc's) */
#define LookListSpecials 0x0004
/* show the portable items */
#define LookListPortables 0x0008
/* ------------------------------------------------------------------------ */
/*
* Template for multi-location objects. To put a MultiLoc object in
* several initial locations, simply use a template giving the list of
* locations.
*/
MultiLoc template [locationList];
/* ------------------------------------------------------------------------ */
/*
* Templates for style tags
*/
StyleTag template 'tagName' 'openText'? 'closeText'?;
/* ------------------------------------------------------------------------ */
/*
* A template for footnotes - all we usually need to define in a footnote
* is its descriptive text, so this makes it easy to define one.
*/
Footnote template "desc";
/* footnote status levels */
enum FootnotesOff, FootnotesMedium, FootnotesFull;
/* ------------------------------------------------------------------------ */
/*
* An achievement defines its descriptive text. It can also optionally
* define the number of points it awards.
*/
Achievement template +points? "desc";
/* ------------------------------------------------------------------------ */
/*
* An event list takes a list of strings, objects, and/or functions.
*/
EventList template [eventList];
/*
* A shuffled event list with two lists - the first list is the sequential
* initial list, fired in the exact order specified; and the second is the
* random list, with the events that occur in shuffled order after we
* exhaust the initial list.
*/
ShuffledEventList template [firstEvents] [eventList];
/* a synchronized event list takes its state from another list */
SyncEventList template ->masterObject inherited;
/* low-level shuffled list */
ShuffledList template [valueList];
/* ------------------------------------------------------------------------ */
/*
* Define a template for the Tip class.
*/
Tip template "desc";
/* ------------------------------------------------------------------------ */
/*
* Definitions for the menu system
*/
/*
* The indices for the key values used to navigate menus, which are held
* in the keyList array of MenuItems.
*/
#define M_QUIT 1
#define M_PREV 2
#define M_UP 3
#define M_DOWN 4
#define M_SEL 5
/* some templates for defining menu items */
MenuItem template 'title' 'heading'?;
MenuTopicItem template 'title' 'heading'? [menuContents];
MenuLongTopicItem template 'title' 'heading'? 'menuContents';
/* templates for hint system objects */
Goal template ->closeWhenAchieved? 'title' 'heading'? [menuContents];
Hint template 'hintText' [referencedGoals]?;
/* ------------------------------------------------------------------------ */
/*
* Templates for topic database entries.
*/
/*
* A TopicEntry can be defined with an optional score, followed by the
* match criteria (which can be either a single matching object, a list of
* matching objects, or a regular expression pattern string), followed by
* the optional response text (which can be given either as a double-quoted
* string or as a list of single-quoted strings to use as an EventList).
*/
TopicEntry template
+matchScore?
@matchObj | [matchObj] | 'matchPattern'
"topicResponse" | [eventList] ?;
/* a ShuffledEventList version of the above */
TopicEntry template
+matchScore?
@matchObj | [matchObj] | 'matchPattern'
[firstEvents] [eventList];
/* we can also include *both* the match object/list *and* pattern */
TopicEntry template
+matchScore?
@matchObj | [matchObj]
'matchPattern'
"topicResponse" | [eventList] ?;
/* a ShuffledEventList version of the above */
TopicEntry template
+matchScore?
@matchObj | [matchObj]
'matchPattern'
[firstEvents] [eventList];
/* miscellanous topics just specify the response text or list */
MiscTopic template "topicResponse" | [eventList];
MiscTopic template [firstEvents] [eventList];
/*
* A SpecialTopic takes a keyword list or a regular expression instead of
* the regular match criteria. It also takes a suggestion name string and
* the normal response text. There's no need for a score in a special
* topic, since these are unique.
*/
SpecialTopic template
'name'
[keywordList] | 'matchPat'
"topicResponse" | [eventList] ?;
/* a ShuffledEventList version of the above */
SpecialTopic template
'name'
[keywordList] | 'matchPat'
[firstEvents] [eventList];
/* default topics just specify the response text */
DefaultTopic template "topicResponse" | [eventList];
DefaultTopic template [firstEvents] [eventList];
/* alternative topics just specify the response string or strings */
AltTopic template "topicResponse" | [eventList];
AltTopic template [firstEvents] [eventList];
/* a TopicGroup can specify its score adjustment */
TopicGroup template +matchScoreAdjustment;
/* a conversation node need a name */
ConvNode template 'name';
/*
* End-of-conversation reason codes
*/
enum endConvBye; /* player typed GOODBYE */
enum endConvTravel; /* the other character is trying to travel away */
enum endConvBoredom; /* our attentionSpan has been exhausted */
enum endConvActor; /* the NPC itself (not the player) is saying GOODBYE */
/*
* Special result code for Actor.canEndConversation() - this indicates that
* the other actor said something to force the conversation to keep going.
*/
enum blockEndConv;
/* ------------------------------------------------------------------------ */
/*
* Conversation manager macros
*/
/* has a topic key been revealed through <.reveal>? */
#define gRevealed(key) (conversationManager.revealedNameTab[key] != nil)
/* reveal a topic key, as though through <.reveal> */
#define gReveal(key) (conversationManager.setRevealed(key))
/* mark a Topic/Thing as known/seen by the player character */
#define gSetKnown(obj) (gPlayerChar.setKnowsAbout(obj))
#define gSetSeen(obj) (gPlayerChar.setHasSeen(obj))
/* ------------------------------------------------------------------------ */
/*
* For compatibility with versions before 3.1.1, define
* openableContentsLister as a synonym for openableDescContentsLister. The
* former was renamed to the latter in 3.1.1 because the original name was
* inconsistent with the corresponding listers for other classes. In
* principle, openableContentsLister is meant to be the 'contentsLister'
* (for displaying the openable's contents in room descriptions, etc) for
* an Openable, while openableDescContentsLister is its
* 'descContentsLister' (for displaying the openable's contents in its own
* EXAMINE description). Fortunately we don't have a need for a special
* contentsLister for Openable, so we can avoid breaking existing code by
* mapping the old name to the new name.
*/
#define openableContentsLister openableDescContentsLister
#endif /* ADV3_H */
TADS 3 Library Manual
Generated on 5/16/2013 from TADS version 3.1.3