adv3.h | documentation |
#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
Generated on 5/16/2013 from TADS version 3.1.3