Change Log
- Version 2.1
- Version 2.0
- Version 1.6.2
- Version 1.6.1
- Version 1.6
- Version 1.5
- Version 1.4
- Version 1.3
- Version 1.2
- Version 1.1
- Version 1.0
- Version 0.92
- Version 0.91
- Version 0.9
- Version 0.8
- Version 0.7
- Version 0.6
- Version 0.5
- Version 0.4
- Version 0.3
- Version 0.2
Version 2.1 (03-July-2024)
The behaviour of the MoveTo action has be modified (with a small RISK OF AFFECTING EXISTING CODE). The previous behaviour could often prove counter-intuitive or confusing. The main purpose of the MOVE TO command was and is to allow notional relocation of objects to a particular vicinity within a room, e.g. so that the player might need to use the command MOVE CHAIR TO BOOKCASE before standing on the chair to reach the top shelf of the bookcase, in which case the chair's movedTo property becomes set to the bookcase (for game code to check). But this probably doesn't feel like the expected behaviour when the indirect object of a MOVE TO command is a container or surface. e.g. MOVE PEN TO BOX or MOVE BOOK TO SHELF, so now when the indirect object of a MOVE TO command is a container, the command will be converted to PUT IN and when it's a surface the command will be converted to PUT ON.
There were in any case a number of issues with the original use of MOVE TO. For one thing, if the direct object of a MOVE TO command was on, in, under or behind something it remained on, in, under or behind that thing even after it had been moved, which seems illogical, so MOVE TO now performs an implicit TAKE under such circumstances and then deposits the direct object in the location of the indirect object (e.g. MOVE BOOK TO DOOR when the book is on a shelf would result in the book being taken for the shelf and left in the outermost room, notionallly next to the door). Conversely, as things stood, the book's movedTo property would remain unchanged thereafter even if the book was picked up and carried around, which was clearly a bug; so now calling the moveInto() method on any object resets its movedTo property to nil.
Finally, although the MOVE TO action reports (and reported) that A had been moved to B, there was no indication of that in subsequent room listings, so now the the listing of a miscellaneous object will be followed by ' (by the whatever)' when the object's movedTo property is whatever. To suppress this behaviour you can set the showMoveToInfo property on the appropriate lister (e.g. lookLister) to nil.
There is now a new MoveAwayFrom action (e.g. MOVE CHAIR AWAY FROM BOOKCASE) that undoes the effect of a MoveTo action by resetting the movedTo property of the direct object to nil. In the event that the direct object has not been moved to the indirect object but is in, on, under, or behind the indirect object the MOVE FROM action is converted to a TAKE FROM action.
There have also been some minor modifications to the Immovable class. Although this class is strictly defined as referring to objects that cannot be taken, it may seem counterintuitive that they previously could be moved (e.g. MOVE HEAVY TABLE TO DOOR). On the other hand, there some objects, such as heavy trolleys, that clearly can be pushed from place to place although they can't be picked up and carried around. The isMoveable property of the Immovable class has therefore been redefined to be true if and only if the Immovable object can PushTravel (or PullTravel). Also, the cannotMoveMsg (on Thing, and hence on Immovable than inherits from Thing) has been changed to 'The whatever won't budge' instead of simply taking its value from cannotTakeMsg.
The Scene class now has turnsActive property (to indicate how many turns an active Scene has been happening).
The Thing class now has altVocab and useAltVocabWhen properties that can be used to change the Thing's vocab (and hence also its name) at run-time according to a user-defined condition (when what you want to do can't be handled by a State object, which is otherwise still the preferred method).
Facilities for hyperlinking and enumerating lists of suggested conversational topics have now been expanded. It was possible to hyperlink lists of suggested conversational topics in previous versions of adv3Lite, but no commands were available to allow players to access this option. A new HYPERLINK TOPIC SUGGESTIONS command, which can be abbreviated to HYPER SUGGS, has now been added. There is also now an option to enumerate lists of topic suggestions, allowing the player to select one simply by entering the corresponding number at the command prompt. This can be toggled on and off using the new ENUMERATE TOPIC SUGGESTIONS command, which can be abbreviated to ENUM SUGGS. By default both commands are explained to players the first time a list of topic suggestions is displayed.
The way the game chooses which SpecialVerb to use (in the event that there's more than one that matches the verb phrase entered by the player) has been enhanced to take into account how well the noun phrase entered by the player matches appropriate objects in scope. In addition, SpecialVerb now defines tentativeDobj and tentativeDobjList properties which can be tested in its when condition.
The SpecialVerb class now has a new exclusions property that extends the range of non-standard verbs a SpecialVerb can safely match to those that partially match verbs defined in the library (or elsewhere in game code). For example if you had previously tried to define a SpecialVerb to match PICK X when X is a flower, this would have blocked the standard PICK UP X command (meaning TAKE X). Now you can, for example, define exclusions = ['pick up'] on such a SpecialVerb to stop it matching any command beginning with PICK UP, thereby allowing the normal meaning of PICK UP to continue to be recognised correctly.
The Actor/AgendaManager methods setStat(val), addToAgenda(val) and addToPendingAgenda(val) now test that val is a valid parameter (i.e. that it refers to an ActorState or AgendaItem belonging to the Actor) and will issue a warning rather than going ahead to change ActorState or add an AgendaItem if val is not a valid value.
There is now a new Redirector method askMissingLiteral(action, role), which is therefore available on Things, Doers, Actions and ActorTopicEntries but is most likely to be useful in the action section of a dobjFor(Whatever) block on a Thing or in the execAction() method of an IAction, where it can be used to ask for the missing literal argument to a vaguely phrased command like TURN DIAL or WRITE. The various LiteralActions and LiteralTActions defined in the library have been adapted to make use of this where appropriate, so that players will be prompted to supply the missing literal, thereby allowing the fully-specified action to go ahead.
There is now a new reportPostImplicit() macro for use in the action section of xObjFor() blocks, to allow one or more custom reports to be immediately appended to the implicit action reports. This is intended for situations where game authors wish to display a customized report for an action which might be performed implicitly, but where displaying the report directly via a double-quoted string (e.g. "You pick the delicate vase up very carefully") clashes with the implicit action reports. In this situation you could instead use the following coding pattern:
dobjFor(Take) { action() { local msg = 'You pick the delicate vase up very carefully. '; if(gAction.isImplicit) reportPostImplicit(msg); else say(msg); inherited(); } }
The new actionReport() function further allows you to abbreviate this to the following coding pattern:
dobjFor(Take) { action() { actionReport('You pick the delicate vase up very carefully. '); inherited(); } }
The exitLister option now has a new pair of flag properties, showDQSExits and showSQSExits which control whether or not exits which are defined respectively as double-quoted strings or single-quoted strings on the direction property of a room are listed by the exit lister. Hitherto they have not been, but now the default value for showDQSExits is true, which is a potential SLIGHT INCOMPATIBILITY with previous versions of the library. The reason for making this change is that attempting to move in a direction defined by a double-quoted string triggers beforeTravel notifications, so it is logical to suppose that we are modelling travel that has been attempted and then aborted (like an adv3 FakeConnector), so that there would be an apparent exit in that direction. This also more clearly distinguishes the function of defining a single-quoted string on an a direction property (to state why direction that way is either impossible or not worth attempting) from that of defining a double-quoted string there (to suggest that travel is attempted but then abandoned). The previous behaviour can be restored by overriding exitList.showDQSExits to nil.
Some additional flexibility has been added to the way TopicEntries work with Facts. An optional msg parameter has been added to various TopicEntry and ActorTopicEntry methods to make it easier to customize how a Fact is articulated in the course of a conversational exchange, and a constructor has been defined on the Fact class to facilitate the addition of a couple of TopicEntry methods that allow new Facts to be created on the fly in the definition of a TopicEntry's topicResponse, rather than having to define the Fact separately.
There have been some minor enhancements to the Fact debugging commands. The LIST FACTS command now hyperlinks the names of Facts so that clinking on the name of a listed fact executes the FACT INFO command for that Fact, while the FACT INFO command now shows a bit more information about a Fact in a slightly clearer format.
There have been some minor tweaks to the way Facts are listed by the FactHelper class, particularly in relation to FactThought. The introductory message "You recall" has been replaced by the more neutral "It comes to mind", and where a Fact is not regarded by the player character as true, a parenthetic notice to that effect is appended to the description of the Fact.
There are now a couple of ways to adjust the display of Facts to changes in the circumstances of your game. The new relevant property (on the Fact class), which is true by default, can be set to nil on a Fact that's been rendered irrelevant by developments in a game (e.g. because it refers to a wish that's now been fulfilled); setting it to nil means that it will no longer be listed by the FactHelper class. The new redescFact(tag, newdesc) function allows you to change the desc of the Fact with name tag tag to newdesc, which again may be useful if a change in circumstances changes the way the Fact might be viewed.
The Fact Relations extensions no longer attempts to assign a belief value to incoming information based on its contradicting what the receiving actor already knows or believes, since this can produce unsatisfactory results (there's more than one way to resolve a contradiction and it's probably best left to game code to deal with this if it needs to).
Calling actorSay(msg) on an AgendaItem now calls actorSay(msg) on its associated Actor. This should make it a little more straightforward to use actorSay() in the invokeItem() method of an AgendaItem.
There is now a new str() function that does exactly the same as the intrinsic toString() function except that it also works for enums. This was introduced to allow the library to build a message string involving belief enums (rather than directly outputting an enum through say()) but might well have other uses in game code.
There is now a new pcListedInLook property on the Thing class, which controls whether or not the player character is listed as being in/on the Thing in a room description, e.g., "You are on the old chair. " By default this takes its value from contentsListedInLook. Previously there was no obvious way of suppressing messages of this sort.
The various messages for seeing nothing of interest in/under/behind/through something have been made more consistent with one another.
Fixed bug that prevented an actor from being kissed (and displayed a buggy message in the course of so doing).
Fixed bug in the Fact Relations extension that could cause a nil-object reference run-time error in the nextStep() method of an ActorTopicEntry.
Fixed bug where the parser might look for the owner of a Topic in response to a conversational command and then complain if it didn't find one, so that, for example, ASK BOB ABOUT HIS COUSIN might be met with "Bob doesn't appear to have any cousin" even though there was a 'his cousin' Topic for the parser to match.
Fixed bug that could cause runtime error in Fact.getTargets() if it was called before any targets had been recorded on a Fact.
Fixed bug that partly allowed the player character to talk to actors in another location within a SenseRegion when this was not intended. The fix involves the implementation and use of a new canTalkToObj PreCondition.
Fixed bugs in VerbRule(Query) which could lead to runtime errors.
Fixed bug (or maybe overzealous 'feature') that could sometimes prevent an abbreviated Query or Say command matching what the player most probebly meant when, in another context, their input might have matched a topic with a briefer name; e.g. if the player entered ASK WHEN WEDDING as an abbreviated form of ASK WHEN THE WEDDING WILL BE, this previously might not have been correctly understood if there was a separate 'wedding' topic that matched ASK ABOUT WEDDING.
Fixed bug whereby calling libGlobal.setRevealed(tag, nil) (often implicitly when the second parameter was omitted) reversed the value of gRevealed(tag) instead of leaving it unchanged when it was previously non-nil.
Fixed bug (albeit one that may rarely if ever have manifested itself in practice) whereby the replaceVocab() method failed to reset to their defaults the various properties (such as isHim, proper and plural) that are set by initVocab(). This would only have manifested as an issue in relatively rare cases such as where changing the vocab of an object changed its gender or number or from a proper-named object to a common-named one.
Fixed bug in SpecialVerb whereby SpecialVerbs may not have matched commands entered in upper case.
Fixed a couple of bugs to do with the matching of regular expressions in TopicEntry and SpecialTopic (with thanks to Jim Nelson for catching the errors and suggesting the fixes).
Version 2.0 (03-May-2024)
POSSIBLE COMPATIBILITY ISSUES: Version 2.0 of adv3Lite should be fully backwards compatible with games written in previous versions APART FROM possible name clashes caused by the introduction of new features involving new identifiers in adv3Lite version 2. Should such clashes occur, you will need to change the clashing identifier names in your game.
Identifier names that are affected include Fact, FactConsultTopic, FactHelper, FactThought,Mood, Stance and SpecialVerb (now class names in the library) together with some property/names that include words like 'fact', 'mood' and 'stance'. In addition likely, dubious, unlikely and untrue are now enums defined in the library. The various uses of these new identifiers are explained below.
Some internal changes have been made to the Actor and Player classes that should not affect existing code. The core module thing.t now defines a very basic class that is replaced by the one in actor.t. This allows the Player class to descend from Actor. It also removes the potential difficulty of some code in core modules wanting to refer to an Actor class. It is recommended that the Player class always be used to define the player character from now on (especially in new games).
Library preinitialization now sets the globalParamName of every Actor for which is is not already defined. The globalParamName is set to the name of the Actor object, for example the globalParamName of bob is set to 'bob'. This makes it a little easier for game authors to use a recognizable globalParamName in message parameter substitutions (and for library code to assume this will be available). Existing code should not be affected, since any existing globalParamNames will not be changed.
There has been a change to the way the library sets the identity of the initial player character on libGlobal (or rather, the addition of a failsafe way of doing this). libGlobal.playerChar() is now defined as a method which establishes the identity of the initial player character (or creates one if none can be found) and then sets itself to the player character object it finds. This means it is safe to use gPlayerChar even in situations, such as preinit, where it may not have been set yet, since in that case the first call to gPlayerChar (i.e. libGlobal.playerChar() will cause its value to be found and set.
The number of numbered items that can appear in an enumerated disambiguation list has been increased to twenty. This is also the effective cap, since the parser isn't designed to handle a larger number correctly (if the player enters a number higher than 20, the game may respond as if it worked, but the wrong item will be selected).
The Actor method arouse(key, stat) now has a second optional parameter stat, which defaults to true for compatibilty with existing code. If stat it nil, the effect of arouse() is reversed, setting the curiosityAroused property of all ActorTopicEntries matching key to nil. A new conversation tag <.abate key> (or if you prefer <.unarouse key>) can be used to call arouse(key, nil) to reset curiosityAroused to nil on the relevant ActorTopicEntries in the same way. This is for use in situations where the player character's attention has changed to a different topic or set of topic but the PC's curiosity has not been satisfied (because the player might want to return to further topics sharing the same key).
A number of enhancements have been made to the triggering of subtopics from a master topic. The new ActorTopicEntry property autoSuppress now controls the listing of suggested topics when a master TopicEntry triggers a list of subtopics through its keyTopics property; for example where an AskTopic that responds to ASK FRED ABOUT ISLAND has keyTopics of 'island' that in turn causes the game to suggest a number of subtopics (e.g. "What is this island called?", "Where is this island?", "How many people live here?") that the player can then choose between. Setting autoSuppress to true (the default) on the master topic (e.g., AskTopic @tIsland) will suppress the suggestion of the master topic while any of its subtopics (e.g. "Where is this island?") is in the current list of suggestions.
The ActorTopicEntry class also has a new autoSuppressSubTopics property, which is the complement of the autoSuppress property. If autoSuppressSubTopics is true (the default) then if a player changes the subject from one master topic to another (e.g. from ASK ABOUT ISLAND to ASK ABOUT WEATHER) then the subtopics suggested by the first master topic (e.g., "Where is this island?") will have their curiosityAroused property reset to nil, so that they will no longer appear in response to a TOPICS command (unless and until the player types ASK ABOUT ISLAND) again. This is intended to model the player/player character's shift of attention and to declutter the list of suggested topics.
The ActorTopicEntry class also has a new arouseKeyTopics property. If this is true (the default) there is no need to include <.arouse key> before 'key' in the keyTopics property of an ActorTopicEntry that's designed to suggest a list of subtopics (although doing so will still also work). This means that instead of writing keyTopics = [<.arouse key>, 'key'] you can just write keyTopics = ['key'] (if you want all the topics keyed by key to have curiosityAroused set to true). The new activateKeyTopics (by default nil) works similarly to activate the same subtopics.
The ActorTopicEntry class also has a new lastConvResponse property. This is mainly intended for ActorTopicEntries that are mixed in with StopEventList, and where the final response in the list is not something said by the actor but the narrator's summary of what the actor said previously. Setting lastConvResponse to -1 will abbreviate a useful coding pattern that was previously needed to treat the final response as a non-conversational one that did not need to be suggested.
The TopicGroup class now has a contents property and a curiosityAroused property. The contents property contain a list of all the topic entries located in this TopicGroup. If the curiosityAroused property is not set to -1 (the default) it will be copied to the curiosityAroused property of all the contained topic entries at game startup/preinit. This can be useful in setting up groups of subtopics to be suggested by a master topic.
A new Scenery class has been added to facilitate the creation of multiple Decorations. Instead of having to create a number of Decoration objects individually, the Scenery class allows you to define a related set of decorations on a single object with rather less typing; for instance the following would be equivalent to five different Decoration objects placed in the forest location:
Scenery @forest [ ['trees; oak ash beach pine;;them' 'A mix of trees, oak, ask, beech and pine, surround you on every side. '], ['branches;;;them', 'All around you the branches are laden with twigs and leaves. '], ['leaves';green;; them', The leaves are all varies shades of green. '], ['twigs;;;them', nullObj] ['sunlight; dappled', 'Dappled sunlight filters through the leaves and branches overhead. '] ]
The nullObj in the 'twigs' line causes any attempt to refer to the twigs to be responded to with "That's not something you need to refer to. "
The Consultable class now has a topicEntryList property which can be used to automate the creation of simple ConsultTopics in a manner analogous to the creation of Decoration objects by the new Scenery class.
There is now a SpecialVerb class that can facilitate handling commands that apply to only a handful of objects in a game. For example, if a game has a doorbell that can be rung by being pushed, instead of having to define a new Ring Action and VerbRule(Ring)) and dobjFor(Ring) blocks on both Thing and the doorbell object just to handle this one case, you can simply define:
SpecialVerb 'ring' 'push' @doorbell;
The say() function has been tweaked so that it can now display the names of enums; for example say(small) now outputs 'small'. Internally the enum names are stored in the LookupTable enumTabObj.enumTab in english.t. Some of the string name equivalents of enums are predefined in this table; any that are not at added at preinit. This is to allow translators to provide own-language equivalents of enum names, so that, for example, say(small) could be made to output 'petit' in a French game.
There has been some reworking of the knowledge framework, principally to facilitate distingushing player knowledge from player character knowledge where these might diverge (especially when the player character can change in the course of play). As before, anything that have been revealed (typically through gReveal(tag) or <.reveal tag>) is stored in the table of revealed tags on libGlobal, but is now also stored in the informedAboutTab on the current player character. If the player character changes, therefore, the new player character will no longer inherit the old player character's knowledge (as stored in its informedAboutTab) but may start out with a different set of knowledge of its own (encapsulated in its own informedAboutTab).
Additionally, the Thing methods setKnowsAbout(obj) and knowsAbout(obj) can now take a inform/reveal string tag as its argument as well an an object. so that setKnowsAbout(tag) has the same effect as setInformed(tag) and knowsAbout(tag) the same effect as informedAbout(tag) when tag is a single-quoted string. The new macro gKnown(tag), which expands to (gPlayerChar.knowsAbout(obj)) can thus be used to test for the player character's knowledge both of objects and of facts encapsulated in string tags (which could conceivably differ from what has been revealed.
The new Thing property initiallyKnowsAbout can used to store a list of objects and tags the Thing in question (usually but not necessarily an actor) starts the game already knowing about.
The methods and properties relating to the informed mechanism have been moved from Actor to Thing. This is in part to ensure that they work on the player character object if it has been defined as a Thing, but also to allow it to be used with inanimate objects (such as Consultables) which may also 'know' (be informed about) certain facts, things and topics.
Thing now has a new forget(tag) method that causes the Thing (usually an Actor or Consultable) forget all about having been informed about tag.
The behaviour of the CONSULT ABOUT and THINK ABOUT actions have been tweaked to avoid a problem that could arise if they used the <.reveal> tag (or used the reveal mechanism some other way): previously the library called the setInformed method of any actor within hearing distance whenever something was revealed on the basis that they'd overhear the conversational exchange in which it was revealed, but, of course, NPCs shouldn't overhear the player thinking or looking things up. This would only be a problem if the player character thought about or looked things up in the course of a conversation, but since these things could happen these actions now suspend the converational context (by setting the current interlocutor to nil) while the THINK ABOUT and CONSULT ABOUT actions are handled, and then restore the current interluctor (if there was one). This should ensure that bystanders no longer overhear thoughts or whatever the player character looks up in the course of a conversation.
The <.known val> tag can now be used with fact tag names as well as object names provided that val is not a valid object name if it's intended to be a fact tag name. To force a fact tag name that would otherwise be a valid object name to be invalid, you can preface it with a special character (by default, '$') which will then be stripped from the start of val before it's used.
These changes should all be backward compatible with existing game code apart from marginal differences in what gRevealed() and <.reveal> do. The differences may be more apparent on games in which the player character changes in the course of play and which already test for the new player character's knowledge via its informedAboutTab, but the practical impact on most games is likely to be minimal.
As a further refinement to the knowledge model, the Thing function setInformed(tag, arg?) and the libGlobal function setRevealed(tag, arg?) now have an optional second parameter arg. If this is supplied it will stored as the value of the tag key in the associated LookupTable. Both functions can also be used to change the value of an existing entry.
The library also now defines a set of enums, likely, dubious, unliklely, and untrue, to provide possible values of this seoond parameter, allowing games to track the level of credence an actor gives a piece of information (with the default value true retained for items accepted as true). As yet the library does nothing with these values (apart from one case in the new Fact Relations extension), so it will be up to game authors to use — or not use — them as they see fit.
These enums can be used in <.reveal> and <.inform> tags by placing an = sign directlty between the tag name and the enum (or other value), e.g. <.reveal troubles=dubious>. For further information, see the new section on Knowledge, Truth and Belief.
The new (and currenlty experimental) Belief Calculations extension implements various calculations involving the belief enums likely, dubious, unlikely and untrue (together with true) when combined using various operators for AND, OR and NOT (or COMPLEMENT). It does not require the new Facts module, but neither does it provide a particularly realistic simulation of how most people reckon these things. For further details, see the comments in beliefcals.t
There is also a new Facts module that extends the adv3Lite knowledge system by allowing game authors to define Fact objects that encapsulate (and help to track and use) the information associated with <.reveal> and <.inform> tags, so for example there can be Fact object called 'rain-tomorrow' that encapsulates what information has been revealed by a <.reveal rain-tomorrow> tag and who knows about it and what game objects or topics it concerns. In this context a Fact is something that has been asserted to be true by some person or object (e.g. book) in the game; not something that is necessarily true.
The functionality of the optional Facts module can be further extended by the new Fact Relations extension. This extends the functionality of the Facts module by defining a number of relations involving Facts and using them to enhance the conversational abilities of NPC, for example by enabling NPCs to steer conversations towards desired goals through a chain of related topics.
The handling of Thoughts has been tweaked to allow for games in which there are multiple player characters who should each have their own set of Thoughts.
Room and Region now have a new isFamiliar(prop) method that farms out the question of familiarity to the prop property of the Room or Region in question. If the optional prop parameter is not supplied, it defaults to &familiar. The setPlayer() function now loops through all the Regions in the game to set their rooms to the appropriate familiar property for the new player char (if this is different from the old one). This all allows games to track the familiarity of Rooms and Regions to different actors when their knownProp properties differ.
In additional to all these enhancements to the cognitive abilities of NPCs, there are some initial steps to modelling their affective states. Each Actor now has a mood property and a stance property (meaning stance towards the player character, although ambitious game authors can also set and test actor stances towards other actors provided the full adv3Lite library is present). The different possible moods and stances are defined in objects of the Mood and Stance classes. The library definea a number of these but it is very straightforward for game code to define more if desired.
The functionality of the DSDoor class has been slightly enhanced (to bring it closer to that of SymDoor) and the standard library now also has DSPassage, DSPathPassage, DSStairway and DSTravelConnector classes to allow passages and stairways to be defined as single objects instead of pairs of objects. In addition to bringing the convenience of these classes to the standard library, this more clearly separates the provision of double-sided (aka two-way) travel connector objects from the original function of the SymConn extenstion, which is to automate the setting up of reciprocal map connections.
In turn the SymConn extension has been radically refactored to leverage the new DSCon classes in the main library. It should still, however, work in exactly the same way as before from the perspective of game authors, except that as the underlying class inheritance hierarchy has changed, modifying classes higher up in that hierarchy may conceivably have different effects from before (e.g., SymDoor now inherits from Door, via DSDoor, so a modification to Door would now affect SymDoor, which it would not have done previously).
There is now a maxItemsCarried capacity that defines the maximum number of items an actor can carry regardless of their bulk (or weight). This is checked in addition to the bulk the actor is carrying. This allows game authors to limit the number of items an actor (especially the player character) can carry in addition to the maximum bulk they can carry. The default value of maxItemsCarried is very large (100,000) so this unlikely to be a limit ever reached unless the game author overrides it to a lower value. If the player character is holding an appropriate BagOfHolding, the game will attempt to move carried items to it if either the bulkCapacity or the maxItemsCarried is exceeded.
The library now defines a new sLoc(where) macro that can be used to abbreviate defining the subLocation of items initially located in an object's remapXX SubComponents. This means that instead of having to type subLocation = &remapIn one can just write sLoc(In) (and similarly for On, Under and Behind).
The Thing class now defines a new preAction(lst) method, which is called on the actor (usually the player character) just before the relevant Doer is invoked. By default it doesn't do anything, but game code can use it to intervene in an action before it gets going. This is provided principally to cater for the situation in which the player character is incapacitated, through being tied up or paralysed, for example, and the game author wants to rule out all but a handful of actions before any standard verify messages are displayed. This could be done with Doers, but would require the definition of three (or possibly four) Doers to catch every type of action, whereas preAction(lst) allows you to catch them all in one place, allowing a small number (such as SystemActions, Look and Think) to proceed, while stopping all the rest with exit or abort. The lst parameter contains details of the action that's about to be attempted: lst[1] is the action itself, while the other elements are the direct, indirect and auxiliary objects (if any) of the proposed action.
The two new libGlobal properties lastTopicMentioned and lastFactMentioned attempt to keep track of the most recent topic and fact mentioned in the current conversation (which will be nil if no conversation is currently in progress). These properties can be also be referenced by the macros gLastTopic and gLastFact. For this purpose, a 'fact' is represented by the string tag last output by a <.reveal tag> or <.inform tag>.
There is a third new libGlobal property, agendaItem, intended for internal use by the library only. It is set by the AgendaItem class and its subclasses just before calling invokeItem() and reset to nil just after, and so can be referenced by any objects (particularly InitiateTopics) that might be invoked from the AgendaItem's invokeItem() method so they can access the AgendaItem that invoked them. This in turn has enabled three new properties on the InitiateTopic class, namely agendaItem (the AgendaItem that triggered the InitiateTopic), reasonInvoked (the reason the AgendaItem was invoked, relevant only if is a ConvAgendaItem, as is likely to be the case if it's invoked an InitiateTopic) and defaultInvocation which is true only if the ConvAgendaItem that invoked this InitiateTopic was in turn triggered by a DefaultAgendaTopic.
The AgendaItem class now has new endCondition and executeOnce properties that can (opitionally) be used to control when its isDone property becomes true. If executeOnce is true, then isDone will be set to true after the first invocation of invokeItem(), while endCondition can be defined as a method or expression that is checked both immediately before and immediately after invokeItem() is called and sets isDone to true if endCondition evaluates to true.
There is now a new gActorRoom macro that expands to (gActor.getOutermostRoom).
The library now defines a pair of new templates for the CommandTopic class to facilitate defining their matchDobj and matchIobj properties.
Some work has been done on documentation. This manual now has a new Task Topical Guide to make it easier to find the information you're looking for. The Adv3Lite Tutorial has been updated to showcase the DSDoor class (as well as the Door class). There has been a similar light revision of Learning TADS 3 with AdvLite.
The library's typographicalOutputFilter inserts an n-space between the closing punctuation of one sentence and the start of the next. The new property typographicalOutputFilter property sentenceSpacer allows this to be changed to something else, such as a single normal space.
The valToSym(val) function defined in debug.t (and hence only available when a game is compiled for debugging) has been tweaked to work a little better when val is an anonymous object. Intead of returning (the somewhat unhelpful) '???' as it did before, it now returns val.name, provided val provides a name property. This in turn enables more helpful output from some debugging commands.
There have been some tweaks to the DerivedRelation class in the Relations extension designed to make it easier to use and debug.
Some of the longer methods on TravelAction have been broken down into smaller ones to make it easier for user code to customize the handling of travel (I recall seeing this being requested a while back on intfiction.org). This should not result in any changes to the way the library handles travel.
There has been a minor reorganization of library variants. What used to be called adv3Liter is now called adv3Litest, while the name adv3Liter is now applied to a library variant included all the core modules plus many (but not all) of the optional ones, to give a usable, but truly 'liter' version of the library comparable in power to Inform 6 or TADS 2 with a few extra features. For a fuller explanation see the new section on Options and Alternative Libraries — Lite, Liter and Litest.
Fixed bug in ResolvedTopic.getBestMatch (gTopicMatch) that could make it prefer a dummy Topic created by the parser to a Topic object defined by the game author, leading to topics mysteriously failing to be matched as expected.
Fixed bug which could cause an ActorTopicEntry to be counted as not having been conversational after its topic response had been displayed (which could cause errors in the library's internal bookkeeping). The handling of ActorTopicEntries now tracks a new wasConversational property.This mostly affected TopicEntries mixed in with an EventList class where advancing the curScriptState could affect whether or not the TopicEntry was to be regarded as conversational, e.g. because the final entry in a StopEventList might be treated as a summary of what was said in previous entries rather than a conversational response.
Fixed some bugs in the Relations extension in the handling of inverse relations.
Fixed bug with the QueryVague action that caused a run-time error if the player enterered an 'incomplete' query command like ASK WHY or ASK WHO. If there is an available QueryTopic with the right qType, the command will now match it, otherwise it will be treated as not matching anything other than the appropriate kind of DefaultTopic.
Version 1.6.2 (01-Mar-2024)
The behaviour of the DROP action has been changed to allow objects to be dropped directly from a BagOfHolding (or other containers, if game authors so wish). The new Thing property canDropContents controls whether or not a DROP command will attempt an implicit TAKE FROM on an object an actor wishes to drop, when the object is in a container (on which canDropContents is defined) held by the actor. By default, canDropContents is true on the BagOfHolding class and nil on everything else (the logic of this being that players might reasonably expect a BagOfHolding to act as a direct extension to their inventory without requiring any further inventory management busy work). Game code can, of course, define canDropContents as true on other container objects if it is desired to extend this behaviour to them as well.
To facilitate this new behaviour, the handling of the DROP action now employs a new objCarried PreCondition.
The definition of gVerifyIobj has been changed so that it evaluates to a new dummy failVerifyObj if gTentativeIobj[] is an empty list, thereby preventing potential runtime errors if an attempt is made to evaluate gTentativeIobj in this situation. A similar change has been made to gVerifyDobj. The new failVerifyObj is defined to fail all actions at the verify stage as being inaccessible, so should never be used as a valid object choice for any command.
The Thing class now defines allowImplicitSay = nil in order to avoid warnings that might otherwise arise when compiling without the file actor.t present (which might occur, for example, when using adv3Liter).
The Room class now defined smellSize = large and soundSize = large, which gives better results if the player enters a command to smell or listen to the current location (e.g. SMELL DINING ROOM).
The order of events in Actor.travelVia() has been tweaked so the departure message is displayed just before the travel takes place instead of just after. This ensures that the direction-specifc departure message is shown instead of the generic one, as previously.
There is now a new DSDoor (double-sided door) class which allows a straightforward door to be implemented as a single object instead of having to define each side of the door as a separate Door object. While this to some extent duplicates the function of the the SymDoor class defined in the symconn extension, the DSDoor class allows simpler doors to be implemented without needing to include the symconn extension, the full functionality of which game authors may not always want.
A runtime error could occur if a command such as PUT PEN was issued near the start of the game, before any previous commands had selected an indirect object. The change to the definition of gVerifyIobj is one of a series of tweaks designed to fix this bug, the other main one being a small tweak to Parser.selectObjs() to prevent it trying to disambiguate unnecessarily.
Several problems with Attachables (and related classes) have been sorted out, and the Attachable family of classes streamlined. The code for attaching and detaching is now defined on SimpleAttachable in such a way that it can be inherited by the other Attachable classes. The attachedTo property should now be regarded as read-only. With one exceeption, there should be no change to the way these classes behave, except that they should now behave more reliably.
POSSIBLE RISK OF INCOMPATIBILITY. The one exception is that if a SimpleAttachable starts out attached to another object, then the object to which it starts out attached should be defined on its initiallyAttachedTo property instead of the attachedTo property as previously. (This is to facilitate greater consistency in the implementation elsewhere).
The disambiguation prompt now enumerates the options the player can choose from, e.g. "Which coin do you mean? (1) The gold coin on the table, , (2) The gold coin on the floor, or (3) The silver coin?", to allow players to select one of the options by simply typing the appropriate number. Currently, this works with a list of up to 12 options, on the assumption that a player should never normally be presented with a disambiguation list even that long.
If this new behaviour is not desired it can be disabled by setting libGlobal.enumerateDisambigOptions to nil. It can also be toggled on and off under player control using the command TOGGLE DISAMBIGUATION ENUMERATION which can be abbreviated to TOGGLE DISAMBIG ENUM or just DISAMBIG ENUM.
Added a chapter on Library Macros to this manual.
The spelling oÆ’ the Thing property canGoThroughMe has been corrected (from the previously mis-spelled canGoThrougMe).
The spelling oÆ’ defaultSayResponse has been corrected in dobjFor(SayTo) in actor.t.
The spelling of appliesto on ownerDistinguisher has been corrected to appliesTo.
Corrected typo in the postures.t extension that prevented it from compiling.
Corrected multiple mispellings of "explicit" as "explict", most notably in the response to a TERSE command (but elsewhere only in comments in the code).
Corrected cannotThrowToMsg to refer to the iobj (the object thrown to) rather than the dobj (the object being thrown).
Bug fixed that caused a run-time error when issuing commands to NPCs.
Bugs fixed that could cause a run-time error with a TAKE FROM command. Other aspects of verification on the dobj of a TAKE FROM command have also been tweaked to take into account situations where there may be more than one plausible indirect objects.
Fixed a several other meessages for TIActions that could cause run-time errors if they referenced the iobj before it had been fully resolved.
Version 1.6.1 (15-Mar-2023)
The default value of ParseErrorQuestion.priority has been changed to true. This means that player input in response to a parser query will be understood as a response to that query before being interpreted as a new command (if the latter is possible). So, for example, if the parser responds to X WALL, which 'Which do you mean, the east wall or the west wall?', the response EAST will be taken as meaning the player meant to refer to the east wall rather than being interpreted as a GO EAST command (as it previously would have been).
The okaySetMsg property has been moved from the Settable class to the Thing class, and is now used On Thing in place of the DMsg() previously used to report the effect of setting something to somethinq. This ensures that overriding okaySetMsg should consistently behave as expected.
All the occurrences of gDobj and gIobj within verify routines have been replaced with gVerifyDobj and gVerifyIobj (respectively). This should help guard against any further run-time error bugs of the kind noted below in relation to locks and keys (that is, run-time errors resulting from attempts by verify routines to reference gDobj or gIobj before the parser has determined what their values are).
The new Action property failedActionCountsAsTurn allows game code to optionally make actions that fail at the verify stage not count as a turn (so that no further turn processing takes place).
There is now a new EventListItem extension, which allows the definition of items in EventLists that can be used conditionally, a little like AgendaItems.
The library module extras.t now defines a MinorItem class (based on work by Joey Cramsey) which can be used to define unobtrusive items that should only be mentioned in response to LOOK or WHATEVER ALL under certain circumstances (such as being directly in the outermost room, the actor's location, or the player character's inventory).
The SensoryEmanation class has been changed so that SensoryEmanations are by default hidden from actions applied to ALL that are not relevant to the kind of SensoryEmanation involved (in other words, a SensoryEmanation will not respond to FOO ALL unless FOO is either EXAMINE or whichever is appropriate of SMELL or LISTEN TO). Hopefully, this is a minor improvement (avoiding unnecessary clutter in respose to FOO ALL commands) that will not cause any problematic issues with backward compatibility, but any games that wish to reinstate the old behaviour can do so by overriding the hideFromAll(action) method on the SensoryEmanation class.
The header file advlite.h now defines the constant ADV3LITE_H (previously it instead defined ADV3_H).In theory this could allow game code to detect whether the game is written using adv3Lite or adv3 (which defines the constant ADV3_H in its header file(. This may, however, be of limited use since the constant is only defined for source files which in any case include the appropriate header file.
The Room class now defines a new noScriptAfterListen property which, if true (the default) prevents the room's roomDaemon() method calling the room's doScript() method on the same turn as an intransitive LISTEN command. The purpose of this is to prevent the clash that might otherwise occur between the output of a LISTEN command and an atmospheric message describing a sound, thereby avoiding output like:
>LISTEN You hear nothing out of the ordinary. You hear the hoot of a distant owl.
The Action class now has an isConversational property that can be used to test whether an action is conversational. This is defined as true on all the conversational actions such as TalkTo, AskAbout, TellAbout and so on.
The statuslineExitLister.showListEmpty() method now uses BMsg(status line noexits, '<i>None</i>' instead of just '<i>None</i>' to display an empty list of exits in the status line. This makes it easier to customize what's shown by using a CustomMessages object, which may, for example, be useful in situations where there is a way of moving from the current location but not by using the usual direction commands. Note that the other types of exit lister already use BMsg or DMsg for this purpose.
According to the manual, the actor's current room should be included in the list of objects whose smellDesc or listenDesc is displayed in response to an intransitive SMELL or LISTEN command, but this wasn't happening. This has now been fixed so that the room is included in the list of objects, making it easier to associate an atmospheric smell or noise with a location.
Fixed bugs that could caused run-time errors when trying to unlock a door while holding the wrong key.
Fixed bug that could cause a run-time error or inappropriate messge with tryng to unlock a door without the right key (by changing cannotUnlockWithMsg from incorrectly referencing the direct object to correctly referencing the indirect object of the command).
Fixed bug that could upset subject-verb agreement in a string of verbs following the use of the {s/?ed} parameter substitution. Also added a new {aac} parameter substition (devised by Joey "Jess" Cramsey) as a workaround for any similar problems that might occur.
Fixed bug that prevented the names of responding objects to be listed in respond to a LISTEN TO command applied to multiple objects.
Fixed bug in askMissingObject() that could cause run-time errors by resetting objects to nil at the wrong point. This might manifest, for example, when issuing a LOCK command without specifying a key.
Version 1.6 (12-Dec-2022)
The Thing class now defines a new checkRemove(obj) which can be used to allow the Thing in question to object to the removal of obj. This is intended to be called at the check stage of action handling, so that checkRemove(obj) can prevent the removal of obj simply by displaying a message. Currently, the library only calls checkRemove(obj) from the check stage of the TAKE action (which covers most cases where an object is likely to be removed from a container, including commands that would result in an implicit TAKE). Game code may, however, wish to call checkRemove() from the check stage of other actions, depending on how they are implemented, if they could result in the removal of an object from its container without the actor taking the object. In some cases it may be easier to use the checkReach(actor) method to do this, especially where what is being modelled is the inaccessibility of the object to the player character's touch.
This method was originally removed to correct a problem that had arisen with using exit or abort at the action stage of command handling, since at one point this was suppressing the output of any text from the action stage (resulting in silent failure of the command). This in turn made it appear unsafe to use notifyRemove() to prevent an object being removed from its container, since this would be called at the action stage (via actionMoveInto()). With luck, this should no longer be a problem, so it should be safe to use notifyRemove() and prevent the removal with exit. Using checkRemove() provides an alternative if its needed, or where it seems more logical to halt the action at the check stage before it gets going at the action stage.
The library now defines a noHalt() function which can be used in check methods to allow an action to proceed even if the check method needs to display some text.
The Special class now invalidates the cached list of active Specials (Special.allActive_) each time its first() method is called. This ensures that the list of active Specials is recalculated every time the Q object is queried, which is useful if Specials become active or inactive during the course of the game. If this behaviour is not wanted, it can be switched off by setting Q.dynamicSpecials to nil.
The library now defines four new macros: gVerifyDobj, gVerifyIobj, gTentativeDobjIn(lst) and gTentativeIobjIn(lst). These are principally for use in verify routines of TIActions which want to depend on the identity of the other object (for example, of the direct object when the action handling is being written on the indirect object) before the other object has been resolved (so that, gDobj, for example, may still be nil,leading to possible run-time errors). gVerifyDobj, gVerifyIobj evaluate to gDobj and gIobj respectively if gDobj/gIobj is not nil, and to the first object in the list of tentative direct/indirect objects (gTentativeDobj[1]/gTentativeIobj[1)) otherwise. gTentativeDobjIn(lst) and gTentativeIobjIn(lst) return true if lst contains any items in common with gTentativeDobj or gTentativeIobj respectively.
The library now defines INVENTORY TALL and INVENTORY WIDE commands to switch between inventory listing formats (along with a lister to show the inventory in the tall, columnar format as an alternative to the existing wide, sentence-style one).
The VerbRule for the ClimbUpWhat action has been changed to match only CLIMB UP in order to avoid clashing with commands like GO UP or WALK UP that should triggle a Travel Action instead. The VerbRules for both ClimbUpWhat and ClimbDownWhat have had the [badness] tag removed so that the commands CLIMB UP and CLIMB DOWN will either choose an appropriate direct object or ask for one. This is princiapply to prevent the parser understanding UP or DOWN as the names of the object the player wants to climb.
The handling of PushTravel has been substantially overhauled to make it more robust, fix some bugs, and handle the possible barriers to PushTravel in a more logical order. This should not necessitate any changes to game code, but should enable game code to behave more in the way game authors are likely to expect. A main feature of this overhaul is that any PushTravelDir commands are now converted into the appropriate action (ClimbUp, ClimbDown, or GoThrough) the appropriate TravelConnector object.
The library now defines a new travelPermitted PreCondition. This calls the beforeTravel notifications on every object in scope so that they can rule out Travel or PushTravel at the PreCondition stage before it is attempted (for example, before travel is even attempted through a closed door). It was primarily introduced as part of the overhaul of PushTravel handling but has also been added to the preconditions of travel via physical connectors such as doors, passages and stairways, and indeed on dobjFor(TravelVia) on the abstract TravelConnector class.
As part of the same overhaul, some substantial changes have been made to the inner workings of the UnlistedProxyConnector class. Some of these have a future overhaul of further travel handling in mind (along the same lines as for PushTravel), should this prove necessary or desirable (although I've delayed doing this completely for now on the "if it ain't broke, don't fix it" principle). But it should now be possible (though probably not necessary) to make an UnlistedProxyConnector the direct object of a GoThrough action and have it work as expected.
There is now a new nonTravel(loc, direction) function which contains the common handling of attempts to travel from loc in a direction that does not lead to at TravelConnector (e.g. where a direction property points to a string or method). This is used in the library as part of the new implementation of both PushTravel and Travel, and probably isn't directly useful for game code. There is also a new objOfKind(obj, cls) function which returns true if obj is indeed an object and that object is ofKind(cls) and nil otherwise. It was introduced to help with testing whether a direction property points to a TravelConnector when it might not even point to an object, but may have other uses in game code when the data type of a given value at run-time is uncertain.
The Actor class now has a physicalTopicObjs property containing a list of topic entry topic objects (by default [hitTopicObj, kissTopicObj, touchTopicObj]) for which an actor's noResponse message should not be invoked. This is to prevent actions like KISS MARY or HIT FRED being treated as conversational when a noResponse property is defined and to allow user code to extend the range of such non-conversational topic types, for example if game code wants to define a HugTopic to respond to a HUG command.
The English-specific LMentionable properties possAdj and possNoun (which determine the possessive forms of object names used by library messages) have been tweaked to provide better defaults for plural nouns. The previous handling simply added apostrophe-S to the theName property of the object in question, which could result in output like, "You now have the clerks's attention." The new behaviour now adds apostrophe-S to singular nouns or plurals that's don't end in S (such as men and women) but only an apostrophe to plurals that do end in S. This is defined in the new LMentionable property possEnding which can be overriden by game code to deal with exceptions (you could, for example, define possEnding on an npc called Moses to be just an apostrophe).
There has been a substantial overhaul of how implicit SAY commands are handled. The previous behaviour was that the parser would interpret any command not otherwise understood as something the player wants to say to the NPC the player character is currently in conversation with (assuming a conversation is currently in progress). This might well be the appropriate behaviour in a game that makes substantial use of SayTopics, but might be quite inappropriate (and potentially confusing to players) in a game that makes little or no use of SayTopics. The default behaviour is now that the parser will only understand otherwise unparseable input as an implicit SAY command if the current interlocutor (the NPC the player character is currently in conversation with) has SayTopics defined on the corresponding Actor object or its current ActorState. Moreover, several methods and properties are now available on the Actor class to tweak this behaviour as game authors wish. For full details see the relevant section of this manual on when implicit say happens.
The way the library handles (implicit or explicit) SAY commands when there is no matching SayTopic (or DefaultSayTopic) has also been tweaked to make it clearer to the player how their command has been understood (which is particularly important when SAY is implicit, that is, when the player's input has been interpreted as something the player character shoud say to the current interlocutor even when SAY is not explicitly included in the command. The default behaviour is now to echo the player's input back as something the player char has said, followed by the Actor's noResponse message, for example '"I like carrots," you say. / The pink rabbit does not respond.' While this may not look very elegant, it at least makes it clear to the player how the parser has interpreted their input, which could otherwise be a bit mysterious in the case of an implicit SAY. Game code can modify this behaviour either by overriding the defaultSayResponse property on the Actor class or object (to customize the entire message) or the pcDefaultSayQuip property (which defines the first part of this response reporting what the player character supposedly just said).
Note, however, that this behaviour (defined on the Actor) may be defeated by the presence a DefaultAnyTopic or DefaultConversationTopic, both of which may be triggered by a SAY command. This problem can be circumvented either by using a DefaultAnyNonSayTopic or DefaultNonSayTopic instead, or by including a DefaultSayTopic (which, if its topicResponse is not overriden, will now display its actor's defaultSayResponse, thus producing the same effect.
The default value of Parser.autoSpell has been changed from true to (gPlayerChar.currentInterlocutor == nil). This is because the spelling corrector can often appear inappropriately intrusive in conversational contexts, so not attempting spelling corrections during an ongoing conversation seems to give better results. Game code can easily override the value of Parser.autoSpell to true or nil or some other expression if that better suits game author preference.
If calling the moveInto() method on a Thing results in its changing location, its wornBy property is automatically set to nil (since it is then no longer being worn by its previous container)
The Quit action now uses the yesOrNo() method to ask players to confirm that they wish to quit, rather than looking for a response beginning with 'y', which is applicable only in English.
The new ProxyActor class can be used to continue the definition of a complex actor over more than one source file. Minor changes have also been made to the ActorState and AgendaItem classes to work with ProxyActor. Set the location property of a ProxyActor to the Actor object it is standing in for, and you can then locate everything in the ProxyActor just as you would in the original Actor.
The DefaultAgendaTopic class has been slightly tweaked so that a DefaultAgendaTopic is only active when there are any AgendaItems ready to execute. Previously it would be active if there were any AgendaItems in the DefaultAgendaTopic's agendaList at all, regardless of whether they might be executed.
The outermostVisibleParent() and outermostParent properties of Room are now defined as self (rather than nil, as previously). This avoids run-time errors that could otherwise occur in attempting to construct a scope list for a Room.
It is now possible to define a list of exceptions that a DefaultTopic will not match (allowing fallthrough to handling these topics elsewhere).
The library now defines a Player class that can be used to define the player character (although the previous way of doing so still works perfectly well). This makes very little practical difference but is provided for game authors who feel that defining the player character as a Thing with various properties that also have to be defined looks needlessly complex.
Previously, an active FollowAgendaItem prevented the running of a script on the current ActorState, even when no following was taking place (so that the FollowAgendaItem appeared not to be doing anything). This potentially frustrated the triggering of an event list defined on the ActorState to make an actor seem more lively while travel was not taking place. This has now been changed so that if an ActorState defines an event list (and combines a Script class in its definition) that event list will now be triggered even if there is an active FollowAgendaItem, provided that no following or conversation is taking place on the turn in question. Game authors also have the option to define an event list on the FollowAgendaItem instead (by mixing it in with a Script class), in which case the FollowAgendaItem's event list will take precedence over any defines on the ActorState.
The Region class now defines a new regionDaemon() method that's called each turn on all the regions in which the player character is currently located.
Displaying the description of a Room now sets its examined property to true (as well as its visited property, as previously). This means that examined and visited nearly always mean the same thing, but there is one exception: when the player character enters a dark room for which recognizableInDark is true, it will considered as visited but not examined.
The Room class now defines a roomFirstDesc property, which, if used (i.e., not left as nil), will be used the first time a Room is described in place of its desc property, the desc property being used thereafter. If roomFirstDesc is not defined then the desc property will also be used the first time the room has been described.
The usePreParser in the English-language newbie.t file previously intercepted any command beginning USE with a message saying this was too vague and suggesting the player try something more specific, but this could get in the way of a USE command defined in game code that actually wants it. The usePreparser now checks whether the game defines an action called Use and only intervenes if there is no Use action defined in game code.
TAction now defines a reportFailureAfterSuccess property. If this is set to true, then on any command that acts on multiple direct objects, any messages that report failure at the check stage will be displayed after any messages that report successful attempts. This may give better results when, for example, a TAKE ALL command results in the player character trying to pick up more objects than the PC can carry. For now, the default value of reportFailureAfterSuccess is nil, both for backwards compatibility and because this feature is somewhat experimental; there may be situations in which it doesn't produce desirable results. Game code can, of course, override this property either on the TAction class or on individual Actions.
The SymConn extension has been significantly enhanced to make it easier to define connections that are two-way (using only single doors, passages and the like) but not necessarily strictly symmetrical. The extension also adds new SymStairway and SymPathPassage classes, as well as number of properties and methods to facilitate varying the description of SymConnectors from either side.
The library now provides a new Brightness extension which can be used to model different lighting levels. This is based on, but not identical to, the implementation of different levels of lighting in the adv3 library and is intended to supply what was previously the lack of any implementation of this feature in adv3Lite.
The library previously defined the objHeld precondition for iobjFor(LockWith) and iobjFor(UnlockWith) on Key but no preconditions for these actions on Thing. Thing now defines the touchObj precondition for the iobj of these two actions.
The library previously defined the objHeld precondition for the dobj on the various ThrowXXX actions and the GiveTo action. It now defines the objHeld precondition for these actions in addition.
The incorrect comma at the end of the "Shipboard directions have no meaning here" message in Doer has been replaced with a full stop.
Tweaked the order in which the verify routine for locking or unlocking an indirectLockable object rules out failed attempts to do so, so that it reports that the object is already locked when attempting to lock it or unlocked when attempting to unlock it rather than displaying the message saying that the object is locked/unlocked by some other means.
There is now a <.unreveal key> tag which reverses the effect of a <.reveal key> tag, along with a gUnrevealed(key) macro that undoes the effect of gRevealed(key). This is primarily intended for use outside conversational contexts where game authors want to use the revealed/unrevealed mechanism as a covenient way to set and unset flags.
It is now possible to control the order in which rooms in a SenseRegion have their contents listed/described in response to an intransitive LOOK, LISTEN or SMELL command by using either the room's listOrder property, or, for finer-grained control, its remoteRoomListOrder(pov) method (based on a suggestion posted on intfiction.org by Joey "Jess" Cramsey).
The TravelConnector class now maintains a list of actors, vehicles and push-travelers that have traversed the TravelConnector over the course of the game. This list is stored in the new traversedBy property, which can be queried by the new hasBeenTraversedBy(actor) method. The common case of testing whether the TravelConnector has been traversed by the player character can be carried out by simply querying the traversed property.
Fixed bug that caused spurious implicit action reports when trying to go through a locked door (with a GO THROUGH DOOR command).
Fixed bug that prevented proper execution of Daemons and added facility to allow a Daemon to be created with an interval of zero, which causes it to he executed on the same turn and then every turn thereafter.
Fixed bug that could make an actor get out of a vehicle before travelling to a new location (instead of travelling in/on the vehicle). Note, however, that this fix does not change what happens in response to commands like ENTER that might trigger travel but are not themselves travel commands; in such cses the actor will still leave the vehicle (since this is probably the most sensible default). If you want to change this behaviour for a particular vehicle (say a bike that can be ridden into a wood in response to ENTER WOOD) the simplest way to accomplish it is almost certainly via a Doer.
Fixed bug that could cause a crash if the TEST debugging command was used with a very long list of commands.
Fixed bug that could cause a run-time error when directing a command to an ambiguous actor (or object), such as "glove, hello" when there are two gloves in scope.
Fixed bug that could cause a run-time error when the parser tries to lock or unlock something with a key that doesn't fit (caused by the direct object not yet having been definitively identified when the verify routine was run on the indirect object).
Fixed bug that could cause nothing to be displayed when the parser should be asking for a missing (usually indirect) object.
Fixed bug in the VerbRule for the Cut action (from which the missingQ was missing).
Fixed bug that could cause a run-time error when attempting to attach one object to another (this could occur in the verify method on the iobj when the dobj had not yet been determined). At the same time replaced a couple of instances of += with appendUnique() for adding at item to a list of attached objects to ensure greater protection against unintentional duplication.
Fixed (hopefully!) an obscure bug that could result in a game not reporting anything when the player character opens an openable container from the inside.
Fixed bug that prevented the display of an implicit action report, such as "(first taking the doodah)", if the main action failed at the check stage.
Changed the English language grammar for the implicit TELL ABOUT command to avoid the parser misinterpreting commands of the form TELL HER ABOUT FOO (for which the parser was misinterpreting HER as a possessive and replying with contextually inappropriate statements such as "Martha doesn't appear to have any about foo.")
Version 1.5 (28-Mar-2016)
There is now a Weight extension that can be used to track object weights in much the same way as the standard library already tracks bulk.
There is now a SymConn (Symmetrical Connectors) extension. This does two things. First, if a direction property of a room points to another room, it automatically sets up the connection back in the reverse direction (so, for example, if you defined hall.east = study it would automatically set study.west = hall). Second, it defines SymConnector, SymPassage and SymDoor classes which can be used to set up symmetrical connections between rooms requiring one object instead of the normal two (so that, for example, a single SymDoor object can be used to represent both sides of a door, instead of needing two Door objects).
The Direction class now has an opposite property, which specifies the direction object corresponding to the opposite direction (e.g. eastDir.opposite would be westDir). It also has an oppositeProp(prop) method which returns the direction property corresponding to the opposite of prop (for example Direction.oppositeProp(&east) would return &west). Both these changes are principally to facilitate the implementation of the SymConn extension, but are also available for use by game code.
The TravelConnector class now has a getDestination(origin) method which returns the destination to which the connector leads for an actor starting from origin. For all TravelConnectors defined in the main library this simply returns direction, so existing user code should be unaffected by this change, although a number of library methods that used to use the value of the direction property now use the value returned by getDirection() instead. Again, this change is principally to facilitate implementation of the SymConn extension.
The Viewport class in the viewport extension now has a setRooms() method that can be called to change the rooms overlooked by the Viewport.
The new Thing property inDarkDesc can be used to give an alternative description for an object that is visibleInDark in an unlit room.
The Thing class now has a travelVia() method (which simply calls the travelVia method on the appropriate TravelConnector). This is mainly to provide minimal handling in case user code ends up trying to call this method on a Thing that isn't an Actor, although this should not normally occur.
The handling of PUT ALL prep XXX has been changed to make a more intelligent selection of the list of direct objects corresponding to ALL. The library first attempts to restrict the choice to all portable objects that are not already in/on/under/behind XXX and are not XXX themselves (a container can't be put in/on/under/behind itself); if it finds any it applies the command to those. If not it next takes ALL to apply to all the portable objects in scope. If there are none it takes ALL to apply to all objects in scope apart from the actor and the room. The idea is to make PUT ALL prep XXX do what the player most likely wants it to do, or else explain why none of the objects to which ALL might otherwise most plausibly apply can be placed in/on/under/behind XXX.
At the same time the message explaining that something can't be put in/on/under/behind itself has been changed from "You can't put anything in/on/under/behind itself" to "You can't put {the dobj} in/on/under/behind itself." This is to make it clearer which object the parser is complaining about if it issues several messages about objects that can't be put somewhere on the same turn; e.g. PUT ALL IN BOX when there's no portable objects in scope not already in the box so the parser has to explain why each of the other available objects can't be put in the box ("The table is too heavy, the door is fixed in place, you can't put the box in itself").
The definition of gActionListObj has been changed so that it correctly picks up the gender of the first object in the list, if that's the only object in the list (so that an appropriate pronoun can be used to reflect it). This is particularly helpful for languages where gendered nouns are more common than in English.
The message that generates the report "You seen nothing special about the whatever" has been changed to reference the self object rather than its theName property to ease translation into languages where the case of a noun may be signficant.
Three message ID names have been changed: already plugged in vagaue is now already plugged in vague (thereby correcting the obvious typo), and cannot smell used as the ID name of an error message in the objSmellable Precondition is now cannot smell through to avoid collision with the cannot smell message ID used elsewhere; finally one instance of game now brief (it was used twice) has been changed to (the more obviously correct) game now verbose.
There is now a new tryImplicitActorAction() function to allow an implicit action to be attempted by an actor other than that of the main action (typically an NPC performing an independent action).
Some tweaks have been made to VerbRules involving TURN to improve the response in certain cases (such as TURN ON with no object specified).
A few library messages have been tweaked to fix missing full stops and the like.
The order of events in the travelVia() method of the actor class has been tweaked to improve the order in which messages are displayed.
Bug fixed whereby the setting of the various contentsListedInXXXX properties was ignored.
Bug fixed whereby a TopicEntry matching on a regular expression wouldn't be matched if the same topic vocab would also match an object in the game.
Bug fixed whereby the writeToStream(val) method of OutputStream didn't cater for the case where val was the Boolean value true. This could cause run-time errors with embedded expressions that called a function or method for its side-effects when that function returned true. OutputStream.writeToStream(val) now treats true the same way as nil; i.e. it outputs nothing in either case (which is intended to cater for the embedded expression situation).
Bug fixed whereby a plural pronoun was not recognized as referring to a plural interlocutor (e.g. in a command like ASK GUARDS ABOUT THEMSELVES), in situations where a single Actor object is used to represent multiple characters.
Bug(s) (hopefully) fixed whereby implicit action reports were not always shown when tryImplicitAction() was called in author code. Getting implicit action reports to appear in the right place is proving to be one of the trickiest areas of the library. This latest version employs a new ImplicitActionFilter to do the job; this is an OutputFilter that prepends any pending implicit action reports to whatever is output next (and so can be use to display a implicit action report just before any text output by the current main action).
Bug fixed whereby items contained in remapXXX items weren't being listed as part of the contents of the parent item.
Bug fixed whereby responding to a prompt for the topic of an incomplete conversational command (e.g. typing ASK BRIAN and then LIFE in response to "What do you want to ask him about?") resulted in a run-time error instead of processing the command.
Bug fixed whereby no travel notifications were displayed when an NPC carried out a travel action (e.g. in response to a player command), even though the NPC was visible to the player character.
Bug fixed whereby an NPC travelling according to some user-supplied script might be blocked by a door the NPC ought to be able to open.
Version 1.4 (12-Sept-2014)
Minor Risk of Incompatibility: The identifier stop is now defined as a macro (for use with the Rules extension), so any methods, properties, functions or other identifiers in game code called stop will need to be changed to something else. In particular this will effect the Airport sample game developed in the Tutorial. The same applies to nostop, rnull and nextrule, which have also been defined as macros, and to null, which is now an enum, though these are less likely to have been used as identifiers in user code.
The nameDistinguisher in parser.t has been altered so that it now considers two object names to be 'equal' not just if they are the same, but if one is wholly contained within the other. The effect of this is that when the parser wishes to disambiguate between two objects with names one of which is a subset of the other, it will now resort to using their disambigNames rather than displaying a message like "Which do you mean, the red ball or the ball?" when use of the disambigName might have avoided this. This may lead to a few 'false positives' (e.g. the name 'ant' is contained in 'pants', which would now trigger use of the disambigName of both objects were there a need to disambiguate between them), but since by default the disambigName is the same as the name, and the need to disambiguate between in cases of contained names like 'ant' and 'pants' will be fairly rare, such 'false positives' will seldom result in any noticeable difference.
The rules for scope and for matching objects in remote locations have been tightened up, especially in relation to SenseRegions which do not allow line of sight (i.e. for which canSeeAcross = nil). Objects the player character does not yet know about in remote locations are not added to scope, and objects in remote locations are excluded from plural matches if there are also matches in the player character's current location (which is more likely to be what the player intended to refer to). For details, see the section on Special Remote Scope Considerations in the SenseRegion chapter.
Several new extensions have been added. Relations and Rules both provide functionality similar to their Inform 7 equivalents. Sysrules (which needs the Rules extension to work) defines a number of rulebooks and rules which can be used to fine-tune certain aspects of the turn-cycle.
There is also a new Collective extension which can help manage the relations between a collective and its individual items, for example a bunch of grapes from which a number of individual grapes may be taken.
There is also a new SceneTopic extension, based on work by Donald Smith, that allows the use of ActorTopicEntries that are triggered by the beginning and ending of particular scenes: SceneEndTopic and SceneEndTopic.
The new Signals extension builds on the new Relations extensions to provide a framework for objects to send signals to other objects and handle them in user-defined ways.
The new Command Help extension provides an alternative response to an empty command. Instead of executing a LOOK command, the extension will offer the player a short menu of options asking what he or she wants to do. If the player responds by selecting one of the options the extension will display a list of suggested commands. On an HTML-capable interpreter these will be hyperlinked so that a command can be selected by clicking on it.
The Actor method handleTopic() can now take nil as its third parameter. This means that nothing will be displayed, and nil returned to the caller, if no matching topic is found (rather than the display of a default message). The new SceneTopic extension takes advantage of this, and the workings of InitTopic and some greeting topics have also been changed to take advantage of it. This is a change that mainly affects the internal workings of the library, but might be relevant to game code that wants to call this method directly.
Three new macros have been added to the library to assist with the interpretation of commands: gVerbWord, gVerbPhrase and gCommandToks. If the player entered the command PUT RED BALL ON TABLE then gVerbWord would be 'put' (i.e. the first word of the command), gVerbPhrase would be 'put (dobj) on (iobj)' (i.e. the command entered by the player with (dobj) and (iobj) replacing the words used to describe the direct and indirect objects) and gCommandToks would be ['put', 'red', 'ball', 'on', 'table'].
The various PushTravel actions (such as PUSH TROLLEY EAST, PUSH TROLLEY UP RAMP and PUSH TROLLEY THROUGH DOOR) are now able to distinguish between pushing and pulling if desired. Previously PUSH SOMETHING SOMEWHERE, PULL SOMETHING SOMEWHERE, DRAG SOMETHING SOMEWHERE and MOVE SOMETHING SOMEWHERE were all treated as synonymous. This is still the default behaviour, but there is now a canPullTravel property that can be set separately from canPushTravel. By default canPullTravel takes its value from canPushTravel, but if one is set to true and the other to nil it's possible to define an object that can be pulled from one place to another but not pushed, or pushed from one place another put not pulled. In addition, where appropriate the descriptions of PushTravel now reflect whether the object was pushed or pulled.
The Noise and Odor classes have been refactored, so that they are now defined as belonging to the SensoryEmanation class in the main library. This makes it possible to tidy up the way they are enhanced in the sensory.t extension without having to replace classes and duplicate existing definitions. No functionality should be affected.
The Sensory extension now defines SimpleNoise and SimpleOdor classes for sounds and smells associated with a location rather than with any particular object within that location. These may be particularly helpful for defining atmospheric sounds and smells. There is also a new SensoryEmanation template that can be used with these classes.
The Doer class now has a new handleAction property. This should be set to true if the Doer's execAction() method handles the complete action instead of either stopping it or replacing it with another one. The effect is to ensure that the proper beforeAction notifications are called.
The Wear action now calls makeWorn(gActor) rather than makeWorn(true), while makeWorn(stat) now just sets wornBy to stat. This ends up having the same effect as before; it just does it more directly.
The NumberPhrase class in parser.t has now been fully implemented. This has allowed two new action classes to be added: NumericAction and NumericTAction (see the manual section on Numeric Actions for details). The Footnote action (in the Footnote extension) has accordingly been redefined as a NumericAction.
The suggestedTopicLister now has a hyperlinkSuggestions property. If this is set to true then (provided the player is using an HTML-capable interpreter) the list of topic suggestions will be hyperlinked, allowing players to select a suggested topic just by clicking on the link. By default this property is nil unless the cmdhelp extension is present.
The Thing class now has a sayFindHidden() method to make it easier to customize the message displayed when items are discovered hidden in particular objects.
There is now an illogicalAlready() macro. This doesn't do anything different from IllogicalNow() in adv3Lite, but is supplied so that game authors familiar with adv3 can use it without getting a compilation error. It may also be slightly useful for documentary purposes to clarify why a verify routine in game code is ruling out an action.
Extensions are now included in the manual index and in the Library Reference Manual. It is made as clear as possible where material relates to an extension rather than the main library.
In the objtime extension, both GoTo.timeTaken and Continue.timeTaken are now defined to be TravelAction.timeTaken. This makes it possible to change the time taken for all travel-related actions in one place (and in particular, set to zero in one place if you want to use the TravelConnector traversalTime mechanism instead).
A few more message substitution parameters have been added to the message system to deal with contracted versions of the verb 'to have', e.g. {\'ve} and {haven\'t}.
Some changes have been made to the messages displayed when greetings (including TALK TO X) are used but no suitable HelloTopics or GoodbyeTopics are available to respond to them. Previously this would result in the display of the noResponseMsg if a conversation was being started or ended, or nothing at all if HELLO or TALK TO X was used in the middle of a conversation (see report of bug fix immediately below). In no case was this fully satisfactory. The library thus now defines three new message properties to cater for these situations. If HELLO or TALK TO is issued at the start of a conversation, then the noHelloResponseMsg will be used in default of any available HelpTopic. If HELLO or TALK TO is used while a conversation is already in progress, then the alreadyTalkingMsg will be used. Finally, if there's no ByeTopic to deal with a BYE command then the actor's noGoodbyeResponseMsg will be used.
The new Thing property autoUnlock (nil by default) can be used to make the actor attempt to unlock a locked item (door or container) before attempting to open it, provided unlocking is straightforwardly possible (in other words it adds the objUnlocked Precondition to the opening action).
The new Thing method abcName(action, role) can be used in those rare cases where you want to override the name the parser uses to describe an object when announcing its best choice of object. For example, if you have a bottle of wine from which you can fill a glass, you might prefer '(with wine from the bottle)' to '(with the bottle of wine)' following FILL GLASS.
The order of events in the Actor setState() method has been changed so that the curState property of the actor is set to the new state before the new state's activateState() method is called (instead of after, as previously). This removes a potential problem that might otherwise occur if an activateState() method wants to change the state of another actor, and the other actor needs to know what state the first actor is in.
The new Actor methods curNodeIdx(), curNodeKey() and curNodeObj() can be used to test whether the actor is currently at a Conversation Node, and, if so, what it is. If you simply want to test whether there is an active ConvNode, test whether curNodeIdx() returns a number (meaning there is one) or nil (meaning there isn't). The curNodeKey() method returns the convKeys value associated with the current ConvNode (if there is one) or nil otherwise, while the curNodeObj() method returns the current ConvNode object, if there is one.
The new TravelConnector property transmitsLight can be used to control whether or not a connector (typically a door) that leads to a lit room is visible from a dark room. This can be used, for example, to determine whether or not the player character can use a door from a dark room to a lit one.
The code for executing travel via TravelConnectors has been substantially refactored. Most of the actual work is now done by the execTravel() method of the room to which travel is taking place, although this delegates certain appropriate tasks to the connector via which travel is occurring (which may or may not be the same as the room being travelled to). User code should not be affected, though internally the implementation is now both simpler and more robust, not least in avoiding duplicate travel notifications. The particular bug that triggered this refactoring is listed below, but the entire TravelConnector mechanism should now be easier to maintain.
The new actor property pcArrivalTurn is used to note the turn on which the player character arrived in the location of the actor. This in turn is used by the new pcJustArrived property on both Actor and ActorState which can be used, for example, to vary the specialDesc of an Actor to reflect its reaction to the player character's arrival.
In the English language library the makeLit()method of Thing now checks whether the LitUnlit state needs to be added/subtracted from the list of states on the object concerned.
The working of the noResponse property of ActorState has been improved so that its presence no longer blocks ATTACK, KISS and FEEL actions.
There is now an ActorState template.
The way the Examine action works has been slightly changed internally to ensure that embedded strings in state descriptions are better handled.
Bug fixed whereby greeting an actor when a conversation with that actor was already in progress and there were no topics suggested resulted in no response at all. This relates to the immediately preceding change.
Bug fixed with the definition of VerbRule(QueryAbout) which could cause it inappropriately to interpret commands like A WHY AM I HERE as ASK A WHY I AM HERE when there's an object that matches A in its vocab (such as 'Door A').
Bug fixed whereby a takeObj precondition on an immovable indirect object wrongly reported that it was the direct object that couldn't be taken. To fix this the various cannotTakeMsg properties that referred to {the dobj} now refer to {the cobj} instead.
Bug fixed whereby the response ALL to a disambiguation prompt was not properly handled (it was effectively being ignored).
Bug fixed whereby issuing a movement command on the turn following a FollowAgendaItem being added to an actor's agenda might result in that actor being left behind instead of moving with the player character.
Bug fixed with FollowAgendaItem assuming that travel was always successful: a FollowAgendaItem causes an actor to lead the player character through a series of connectors, but previously it was not checking whether the travel actually succeeded, leading to odd results if progress was barred by a locked door or some other such obstacle. This is now fixed, and the new FollowAgendaItem method travelBlocked(conn) allows game code to respond to the blockage.
Bug fixed whereby after travel notifications were being sent even if no travel took place (e.g. in a failed attempt to go through a locked door).
Bug fixed whereby a space was lacking before 'then' in an implicit action report.
Bug fixed whereby a topic inventory listing that followed giving a command to an actor would say that that actor could say such and such, instead of saying that the player character could do so.
Bug fixed whereby 'were' had been omitted as a possible way of starting a command meant to trigger a query topic with qType = if or whether (e.g. WERE YOU THINKING OF COMING TO THE BALL).
Bug fixed in TopicGroup template (which wrongly referred to the boostScore property instead of the scoreBoost property).
Bug fixed with the way TopicGroups applied their score boosts to SlaveTopics. The score boost mechanism has been reworked to make use of a new scoreBooster() method on TopicEntry and TopicGroup; this is for internal use only and should not affect user code.
Bug fixed whereby the word 'the' was trimmed from the beginning of an object name created via the vocab property even when it was an appropriate part of the name (e.g. 'the king' or 'the Hague').
Bug fixed with setPlayer() that could cause messages using the parameter substitution {I} to conjugate the verb in the wrong person (e.g. 'you sees') just after setPlayer() has been called.
Bug fixed whereby ImplicitConversationActions were failing to set their curTopic property (so that gTopic would be left at nil)
Bug fixed with typo in goInstead macro.
Bug fixed whereby it was not possible to use the debugging command GONEAR with a decoration even when the game was compiled for debugging (due to a typo in a compiler directive).
Bug fixed whereby a failed attempt to travel through a locked door generated travel notifications as if the attempt had succeeded.
Version 1.3 (11-July-2014)
Minor Risk of Incompatibility: In the Thing methods listContents(lister) and listSubcontentsOf(contList, lister), the optional lister parameter is now a property pointer (to a property holding a Lister object) instead of a Lister object. This is to enable contents of contents to be listed using the appropriate Lister for their immediate container, rather than using the same Lister all the way down the containment chain. Most game code is likely to be unaffected, since it isn't usually necessary to call these methods directly, but if you do use either of the methods in your own game code you will need to make the appropriate change. The new Thing property roomSubContentsLister has been added to hold the lookContentsLister so that this can be passed via a property pointer (although this is mainly for the internal use of the library).
Minor Risk of Incompatibility: Previously DefaultAnyTopic worked a little inconsistently with regard to greetings, in that it would respond to HELLO if no HlelpTopic was defined but not to BYE. The DefaultAnyTopic class now has a matchGreetings property; if this is true, then it will match HELLO and BYE; if it is nil (the default), then it won't.
The SenseRegion class now has an autoGoTo property. If this is true, then an attempt to touch an object from a different room in the same SenseRegion will trigger an implicit GoTo action attempting to move the actor to the location of the object to be touched.
The fastGoTo property can now be set on an individual Region as well as globally on gameMain. Note that if gameMain.fastGoTo is true, the setting of fastGoTo on individual regions will have no effect, since fast GoTo (GoTo without stopping for CONTINUE commands) will then be in effect globally. If gameMain.fastGoTo is nil, however, setting it to true on an individual region will allow fast GoTo travel within that Region.
The SenseRegion class also has a new contSpace property. If this is true (it's nil by default) then moving from one room to another within the SenseRegion does not cause a LOOK AROUND to be performed (and hence a description of the new room to be displayed). This may be useful in situations where a SenseRegion is used to model a small continuous space such a room in a house divided into subsections which are modelled as the Rooms within the SenseRegion.
The Scene class now has the new methods beforeAction() and afterAction(), which work analogously to the similarly-named methods on Rooms, Regions and objects in scope. The beforeAction() and afterAction() method of every currently active Scene is called just before and after an action is about to take place or has taken place. The beforeAction() method can veto the proposed action with the exit macro.
The MultiLoc methods moveInto(loc), moveIntoAdd(loc) and moveOutOf(loc) now work if loc is a Region (as well as if it is a Thing or Room); previously loc had to be a Thing or Room. If loc is a Region then moveIntoAdd(loc) or moveInto(loc) adds the MultiLoc to every room in the Region while moveOutOf(loc) removes it from every room in the Region.
The Action class now has a preCond property to allow PreConditions to be specified for the action as a whole rather than for the action applied to particular objects. It is principally intended for IActions to allow PreConditions that apply to the actor, such as the new actorOutOfNested PreCondition, which tries to take the actor out of any nested room that it's in before carrying out the action. This is now applied to the Jump action, so that a JUMP command will try to take the actor out of any nested room (e.g. a bed or chair) that it's in before attempting to Jump. If this behaviour is not wanted (e.g. because while on a nested room such as a high ladder is the solution to a puzzle) the new getOutToJump property can be set to nil on the nested room object in question.
The ActorTopicEntry class now has a new listOrder property that gives some control over the order in which topic suggestions are listed within each group (e.g. an AskTopic with a listOrder of 110 will be listed after an AskTopic with a listOrder of 100). It is also now possible in principle to alter the order of the groups of topic suggestions (ask, tell, show etc.) by overriding the typeInfo property of suggestedTopicLister to list things in a different order.
There are now three additional extensions, two of which have been "borrowed" from their adv3 equivalents: footnotes, subtime (subjective time) and objtime (objective time).
The advLite.h header file now includes the date.h header, to facilitate using the Date intrinsic class in game code (and in two of the extensions just noted above).
The Command class now sets provisional values for gDobj and gIobj (if dobj and iobj are defined for the current Command) just before searching for matching Doers; this avoids problems that might otherwise occur if game authors reference gDobj and/or gIobj in conditions (such as when) applied to particular Doers.
The library now sets the value of the which parameter when calling the StringPreParser doParsing(str, which) method. If the game is requesting disambiguation, which is set to rmcDisambig; if the parser is asking for a missing noun, which is set to rmcAskObject; otherwise which is set to rmcCommand (rmcDisambing, rmcAskObject and rmcCommand are enums).
The previous change to the checkDisplay() method caused one problem while solving another; in particular the new version of checkDisplay() is no longer able to prevent a LISTEN or SMELL command sometimes giving an empty response when listenDesc or smellDesc don't actually display anything. To solve this problem without reintroducing the problem afflicted embedded expressions in listenDesc and smellDesc, a new Thing method displayAlt() has been added to the library and the handling of LISTEN and SMELL actions refactored to make use of it. This works by avoiding the need to predict whether listenDesc and smellDesc will produce any output and instead checking to see if they have. This is largely a purely internal change to the library that should not effect game code except by making listenDesc and smellDesc work more reliably.
Bug fixed that failed to reset the current actor to the player character early enough in the parsing routine after giving an order to an NPC on the previous turn, which could lead to trying to build the scope list for the wrong actor (possibly causing a run-time error if the NPC just commanded had meanwhile been moved into nil).
Bug fixed that gave an inappropriate response to trying to give an order to an Unthing. Attempting to give an order to an Unthing now causes its notHereMsg to be displayed, which is consistent with the way an Unthing responds to any other commands.
Bug fixed with the setKnown() method of Thing and Topic; previously, calling this method would cause a run-time error due to a typo in its definition.
Small bug fixed with the wrong kind of bracket terminating a message parameter in the 'no room' DMsg.
Bug fixed with setPlayer() function, which now sets gActor to the new player character to ensure that an action like looking around immediately after changing the player character now works as expected.
Bug fix whereby all the objects of a command were being resolved again when the parser asked the player to supply one missing object (for example, in a TIAction). In certain odd cases, such as when one object (the direct object, say) has already been established via a disambiguation prompt, this could cause the parser to re-resolved the previously resolved object (the direct object, say) to another, erroneous object when the player supplied another missing object (the indirect object) say. For example:
>UNLOCK DOOR Which door do you mean, the red door or the blue door? >BLUE What do you want to unlock it with? >KEY You unlock the red door with the key.
The code that asks the player to supply a missing object now prevents the parser from re-resolving existing objects so that this sort of thing should no longer occur.
A number of bugs fixed relating to the listing of suggested topics: Yes topics and No Topics are now separated correctly into different lists, and ShowTopics and CommandTopics should now be listed when they're meant to be suggested (they weren't before).
Version 1.2 (17-May-2014)
Risk of Incompatibility: The code for the inputManager object was largely copied from the adv3 library, but this included provisions for handling real-time processing, which adv3Lite doesn't have. This in turn resulted in several methods of inputManager taking a wholly redundant allowRealTime argument. This argument has now been removed from all the affected methods. Since the arguments to these methods were optional, some code may not be affected by the change, but any code that calls these methods with the arguments supplied will need to change them to match the new argument signature:
- getInputLine(allowRealTime?, promptFunc?) becomes getInputLine(promptFunc?).
- getEvent(allowRealTime?, promptFunc?) becomes getEvent(promptFunc?).
- getKey(allowRealTime?, promptFunc?) becomes getKey(promptFunc?).
- getEventOrKey(allowRealTime, promptFunc, keyOnly) becomes getEventOrKey(promptFunc, keyOnly).
The promptFunc parameter can now be supplied as a single-quoted string instead of a function pointer (previously it could only be a function pointer; now it can be either).
The inputManager method processRealTimeEvents() has been removed (it didn't do anything and wasn't used anyway).
The library now defines a number of macros that can be used as abbreviations for inputManager methods:
- #define more inputManager.pauseForMore()
- #define input(x) inputManager.getInputLine(x)
- #define waitKey(x) inputManager.getKey(x)
Risk of Incompatibility: the way the ATTACK and KISS commands are handled has been slightly altered, mainly to remove an inconsistency that had crept into the library. Previously ATTACK could be ruled on Thing by setting isAttackable to nil, but on Actor by setting allowAttack to nil; likewise KISS previously used isKissable and allowKiss. The properties allowAttack and allowKiss have now been abolished, so that Actor uses the same isAttackable and isKissable properties as Thing. Moreover, in the interests of consistency, the shouldNotAttackMsg property of Actor has been renamed attackResponseMsg.
At the same time two new properties have been introduced on Thing: checkAttackMsg and checkKissMsg. These provide an easy way to stop ATTACK or KISS at the check stage. By default they are both nil, but if they are defined (typically as a single-quoted string, though a double-quoted string or a method that displays some text should also work) then the message they define is displayed at the check stage, causing the action to halt there.
Thing also now defines a kissRank property. This is basically to allow the verify routine for KISS to give a higher logical rank to an Actor than to a Thing without having to override Thing's verify routine on Actor. It could also be used in game code if there are certain Actors the PC is more likely to want to kiss than others; these more kiss-desirable Actors could be given a higher kissRank, making the parser more likely to choose them in case of ambiguity.
The rationale for the slightly special treatment of ATTACK and KISS is that they are forms of interpersonal interaction that may require more nuanced treatment than most typical IF actions, even though they are not exactly conversational. The same would seem to apply to TOUCH, so this is now handled in an analogous fashion, and a new TouchTopic class has been added to allow the handling of TOUCH commands in a similar manner to HitTopic and KissTopic for ATTACK and KISS. There is likewise a corresponding new checkFeelMsg property on Thing (and hence on Actor) and a new touchResponseMsg property on Actor, both of which work in the same way as checkAttackMsg and attackResponseMsg.
To help cover possible confusion between HIT and ATTACK and between TOUCH and FEEL the library now defines seven macros which convert:
- checkTouchMsg into checkFeelMsg
- feelResponseMsg into touchResponseMsg
- isTouchable into isFeelable
- cannotTouchMsg into cannotFeelMsg
- touchDesc into feelDesc
- checkHitMsg into checkAttackMsg
- hitResponseMsg attackResponseMsg
For the full story see the section on Attacking, Touching and Kissing in the chapter on the Actor object.
The library now defines the macro gTurns, which expands to libGlobal.totalTurns, as a convenient abbreviation for getting at the current turn count.
Various changes have been made to improve the way the GO TO command works in some less common cases. A new ProxyDest class has been defined to prevent the parser perversely choosing an Enterable or Distant object as the target of a GO TO command when, for instance, the player is already at the destination specified, and the handling of the GoTo action on the Distant class has been altered so that an attempt to GO TO a Distant object can be interpreted as a request to go to the location specified in the Distant object's destination property.
The familiar property of SenseRegion has been changed so that it now becomes true once the player character has visited any room in the SenseRegion. This allows the player character to navigate to other objects in the SenseRegion using the GO TO command even without having previously visited their locations; this models the fact that the PC can presumably see how to get there since there's a line-of-sight connection between all the rooms in the SenseRegion.
The gameMain object has a new property fastGoTo; if this is true then the GO TO X command will carry on moving the player character either until s/he reaches the destination or until some obstacle prevents it. This allows players to go straight to the desired destination without needing to use the CONTINUE command (unless something blocks their journey). The default value of fastGoTo is nil, so that by default the behaviour of the GO TO command remains as before.
The TopicEntry class now as a topicMatched property which is set to the topic being tested for a match by the matchTopic() method. This is intended for use by the topicResponse() method which can then access the Topic that was actually matched.
A BMSg(), DMsg() or Msg() can now be defined with an anonymous function that returns a single-quoted string as its second parameter, as well as just with a single-quoted string. This is primarily to allow CustomMessages objects to define messages with variable text in embedded expressions.
The StairwayDown class now has its own cannotClimbMsg to give a more appropriate response to CLIMB STAIRS or CLIMB UP STAIRS when the stairs lead down.
The purloin action now works on an item even it if is hidden. To achieve this the Action class now has a new unhides property which, if true, allows the action to proceed even on an item for which isHidden is true. Additionally, the PURLOIN action sets isHidden to nil on anything it takes (otherwise the player character would still not be able to interact with it).
Some errors in the Quick Start Guide have been corrected and some brief guidance added to the adv3Lite Bookshelf page to help users find the best piece of documentation to start with.
Commands of the form TELL X TO Y, which are translated into X, Y (i.e. telling the NPC X to carry out the command Y) before being executed now use the name property of X rather than the theName property of X to form the translated command. This is both less accident-prone and less language-dependent. In particular it avoids the problem that could occur if X is an object that has been defined with a theName property that uses the indefinite article, since if TELL X TO Y is translated into A X, Y the parser will interpret the translated command as implicitly asking about X and Y, and then complain about an illegal use of multiple objects.
Previously the library was a bit over-zealous in suppressing the display of zero-length strings that might result from SMELL or LISTEN commands; the test applied to achieve this meant that embedded expressions (such as <<one of>>... constructions) in properties like smellDesc and listenDesc would not work as expected. The library now applies a less stringent test, which appears to have no adverse effects, and which allows embedded expressions to work with such properties as game authors would expect.
Bug fixed which could a run-time error when moving into a SenseRegion within or from a DynamicRegion.
Bug fixed which could cause inappropriate recursive listing (attempted listing of contents of contents) when using a user-defined openingContentsLister.
Bug fixed which would case an invalid command directed to the current interlocutor to be misinterpreted as two implicit SAY commands (e.g. BOB, FLY would be misinterpreted as SAY BOB followed by SAY FLY). Now no command containing a comma will be treated as potential implicit SAY command.
Bug fixed whereby ending a command with a comma (e.g. Z,Z,) would cause a spurious "You can't use multiple objects with that command" response. If the last token in a command string is a punctuation mark, it is now removed from the list of tokens before the command is processed.
Version 1.1 (04-Apr-2014)
Slight risk of Incompatibility: Previously, when the contents of a room were listed in response to a LOOK command (or when entering a new room), all its visible contents were listed as having been seen by the player character except for the contents of actors (which might be their body parts but would more usually be their inventory), on the basis that these contents were not explicitly listed. This could lead to counter-intuitive results, however, since in most cases the contents/inventory of actors (including the player character) would be in plain sight, and therefore game authors would probably expect them to have been seen by the player character. This new behaviour can however be changed by setting the new Thing property markInventoryAsSeen to nil (the default value is true).
Slight risk of Incompatibility: There has been a slight change to the timing of Scenes to make it easier to define a Scene that starts when the game starts. The scene manager now first executes just after the initial display of the starting location, rather than at the Init stage (before anything is displayed). This means that the whenStarting() method of a Scene whose startsWhen condition is simply true no longer needs to use a OneTimePromptDaemon to display text; it can simply display the text using a double-quoted string.
Examining an object now marks it as having been seen by the player character (provided the actor is the player character). In 99 cases out of a 100 this probably isn't necessary, but it may help to catch the odd case where an object is examined without having previously been marked as seen, since once the player character has examined an object, s/he has certainly seen it.
The canSee(a, b) methods of QDefaults and QSenseRegion now return nil if b.isHidden is true (reflecting the fact that if b is explicitly hidden, a shouldn't be able to see it).
The discover() method of Thing now marks the object as seen by the player character if the player character can see it when its discover() method is called.
The #charset us-ascii directive has been added to a number of source files from which it was previously missing. This corrects a problem some users may experience when compiling adv3Lite code with non-Western versions of Windows.
The Thing class now has new method reachBlockedMsg(target) that can be used to define the message that's displayed when the Thing in question (which would typically be a closed transparent container) is blocking reach (touch) access to target (typically an object that's inside a closed transparent container). Previously this message was defined on the ReachProblemBlocker class, which made it awkward to customize the message for particular blocking objects; the ReachProblemBlocker class now delegates the message to the object that's blocking access. For further explanations of this and the next two changes see the Querying the World Model section of this manual.
For similar reasons Thing now has a tooFarAwayMsg method that's called by a ReachProblemDistance object when the Thing in question is too far away (generally because it's in a remote Room). Like reachedBlockedMsg() this would normally be triggered (ultimately) from the touchObj PreCondition via the QDefaults object. Again the purpose is to make it easier to customize this message on a per object basis if desired. Alternatively you may prefer to customize this message on a per Room basis, in which case you can use the new Room method cannotReachTargetMsg(target) where target is the object the actor is trying to reach from the room the method is called on. (The default behaviour is to return the target's tooFarAwayMsg, so overriding cannotReachTargetMsg() will normally suppress the target's tooFarAwayMsg).
Completing this related trio of changes, Thing now also has a cannotReachOutMsg(target) method that returns a single quoted string explaining why the actor cannot reach target from within the Thing in question when reaching out is disallowed (for example when the player character is on a chair and the chair has defined both allowReachOut(obj) and autoGetOutToReach as nil).
The SEARCH command now works a little differently on the Surface class. It attempts to report both what is on the Surface and what is hidden in the Surface (i.e. in its hiddenIn list). If there is nothing listable either in or on the Surface it reports "You find nothing of interest on the X" rather than "You find nothing of interest in the X" as previously.
It probably doesn't make sense for a SEARCH command to look behind a RearContainer or under an Underside, since this is arguably doing too much for the player, but the grammar for LookBehind and LookUnder now accepts SEARCH BEHIND X and SEARCH UNDER X as equivalent to LOOK BEHIND X and LOOK UNDER X respectively, since these seem reasonable phrasings.
The library now defines two additional utility functions tryInt(val) and tryNum(val). The first of these tries to interpret val as an integer and returns an integer result if it can and nil otherwise; the second is similar but may return a BigNumber if val is a valid number but can't be fitted into the integer type. Both these functions will always return nil if val is neither a number nor a string that can be converted into a number (such as '2' or '3.4' or '-10'). The main difference between these functions and the intrinsic functions toInteger() and toNumber() is that toInteger() and toNumber() return 0 (instead of nil) from an unsuccessful conversion (and 1 for a val of true), making it unclear if the function was passed a valid numerical value of zero or some invalid input like 'foobar'.
The checkDirection() method of the Doer class now sets the current command's action.direction to the value of the current command's verbProd.dirMatch.dir in case game authors attempt to use the former instead of the latter to get at the direction entered in a player's command. Note, however, that this is not guaranteed to be totally failsafe; game authors are advised to use the current command's verbProd.dirMatch.dir property chain to get at the direction associated with a command, and to first ensure that verbProd.dirMatch is not nil to avoid a run-time error.
When a game has been compiled for debugging, it now attempts to check for obvious errors in vocab strings and issues warnings for any it finds at the start of the game.
It is now slightly easier to customise implicit action reports (using a CustomMessages object) or to suppress them altogether for all actions or specific actions.
A Doer with a command string of 'foo bar' will now match when the FOO action is applied to an object whose lexicalParent is bar (as well as bar itself). This makes it easier to get a Doer to match a command to a multiple-containment object where a command like OPEN WASHING MACHINE might be redirected to the remapIn SubComponent of the object specified (such as the washing machine). This is likely to be what game authors will expect to happen; as things stood before a Doer with a command string of 'open washingMachine' would not have matched the command OPEN WASHING MACHINE when the washing machine had a remapIn SubComponent, a failure that many game authors are likely to have found potentially puzzling (and one it would have been a little cumbersome to program around). The new behaviour should be both rather more intuitive and rather easier to work with.
The Region class has acquired two new methods: regionBeforeTravel(traveler, connector) and regionAfterTravel(travel, connector). The former of these is called when a traveler in the region is about to travel via connector; the latter when a traveler in the region has just traveled via connector. Note that these travel notifications are called after those on rooms and other objects in scope.
There is now a DynamicRegion extension that allows game code to define Regions that can expand or contract over the course of a game (ordinary Regions can't do this).
There is now more control over what listers are used to list the contents of objects in response to player commands. The new Thing property myOpeningContentsLister determines which lister is to be used to list the contents of a container when it is opened (the default value is openingContentsLister). The new Thing properties myLookInLister, myLookUnderLister and myLookBehindLister allow you to define which listers are to be used to list what is inside, under or behind an object in response to LOOK IN, LOOK UNDER and LOOK BEHIND commands; all three of these properties default to lookInLister. The new properties myInventoryLister and myWornLister can similarly be used to define which listers are used to list what an actor is carrying or wearing in response to an INVENTORY command.
The library now implements BRIEF and VERBOSE commands. The current setting is controlled by the new gameMain property verbose, which is true by default.
The English-specific file english.t now contains a new decimalPreParser that traps numbers entered with a decimal point (e.g. 2.4) in the player's input and wraps them in double-quotes to prevent the decimal point from being interpreted as a sentence-ending full stop (such that TURN DIAL TO 2.4 would previously have been parsed as the command TURN DIAL TO 2 followed by the meaningless command 4).
The NumberedDial class now has a new property allowDecimal. By default this is nil, but if it is true then the dial can be turned/set to numbers that include a decimal point. If it is nil only integer numbers will be accepted as valid settings for the dial.
The new function spelledToInt(val) in english.t converts a string containing a spelled-out number (e.g. 'forty-three') into an integer value (e.g. 43), or returns nil if the conversion is not possible.
The NumberedDial class now allows the player to used spelt-out numbers as well as digits in commands; e.g. TURN DIAL TO FORTY-THREE is treated as equivalent to TURN DIAL TO 43.
A number of bugs have been fixed with the spelledXXXNumber grammar productions which caused run-time errors when trying to use them to convert a spelt-out number into its integer equivalent.
Bug fixed that allowed the player to enter multiple objects even when a VerbRule restricted a particular slot to a single object (thereby allowing commands like SIT ON RED CHAIR AND BED or PUT BALL IN BOX AND BASKET).
Bug fixed that could cause a run-time error in objects of the Floor class at game start-up under certain conditions (such as if a Component is part of the floor).
Bug fixed whereby the name of a SubComponent might not completely match that of its lexicalParent, for example when the latter is proper or qualified, such as 'Locker A'.
Big fixed with the definition of the directlyWorn property of Thing.
Bug fixed whereby the parser interpreted commands such a LOOK UP X IN Y as LOOK UP "X IN Y" rather than LOOK UP "X" IN Y (e.g. LOOK UP TRAINS IN BOOK would be interpreted as a command to look up a "trains in book" topic). This occurred when no X (e.g. "trains in book") topic object was defined in the game for the parser to match. Hopefully the parser will now interpret such commands more intelligently.
Bug fixed with the SingletonInterator class that prevented foreach from iterating properly over a singleton Object.
Bug fixed that caused incorrect "no response" messages with commands like FRED, GIVE THE BOOK or FRED, TELL ME ABOUT THE BOOK.
Bug fixed that caused command strings stored for use with AGAIN or UNDO to store words ending in apostrophe-S as two words (so that, for example, BOB'S would be stored as BOB 'S).
Bug fixed that caused the exit and exitAction macros to be treated the same way, so that exitAction caused an action to be considered a failure (thereby bypassing the afterAction handling). Now only exit does this, while exitAction stops the action but allows the afterAction handling to go ahead.
Bug fixed with the (mis)definition of the isDirectlyHeldBy() method of Thing.
Bug fixed with the setSeen() method of Thing causing a run-time error.
Bug fixed with the VerbRule for the ATTACH command (when no indirect object was specified) that would cause a run-time error when issuing a command like ATTACH WIDGET and then responding to the question "What do you want to attach it to?". ATTACH WIDGET now correctly rules out the action if the widget is not attachable, or else responds correctly to the answer to "What do you want to attach it to?"
Bug fixed (or at least alleviated) that prematurely triggered the activation of topics keyed from another topic when deciding whether the keying topic should itself be listed as a suggestion. The premature triggering no longer occurs, but the keying topic may now be sometimes be suggested when there is in fact nothing for it to key.
Bug fixed that could cause a run-time error in the checkPreCondition() method of the actorInStagingLocation PreCondition.
Bug fixed whereby the message describing an actor following the player character could occasionally state that the actor was following someone else instead, for example if an order had just been given to someone else.
The missing full stop (period) has been added to the message "Done" used as the laconic response to a CLOSE command.
Version 1.0 (30 Nov 2013)
The specialDesc method of the actor class now has an additional check for an active FollowAgendaItem to avoid an unnecessary lag between the turn on which a FollowAgendaItem becomes ready and the turn on which its specialDesc is first used.
When a game is compiled for debugging, the library now automatically checks that the use of the canSitOnMe, canStandOnMe and canLieOn me properties is consistent with the values of isBoardable and contType on the same object, and issues a warning if it is not.
DefaultAnyTopic now traps attempts to give orders to NPCs (e.g. BOB, JUMP) along with other conversational commands.
The grammar for TellAboutImplicit has been changed so that it will now accept T TOPIC or or TELL TOPIC or TELL ABOUT TOPIC or T ABOUT TOPIC.
The Settable class is now defined as a Thing with isFixed = true rather than a Fixture. This (a) makes it consistent with the other gadget classes and (b) makes it possible to use gadget.t without extras.t.
A number of minor errors and typos in the documentation have been corrected.
Bug fixed whereby the debugging TEST command wouldn't move the player character to a new location even if the test required it.
Bug fixed which cause the output from DEBUG DOERS to display incorrectly for Doers whose cmd string property included a vertical bar (|).
Bug fixed whereby a plural annotation like {-ren} or {mice} at the end of the name section of a vocab string would be included in the name property.
Bugs fixed whereby entering the debugging commands GONEAR or EVAL by themselves (without any objects) would cause a run-time error.
Bugs fixed which prevented the DEBUG MESSAGES command from working properly.
Bug fixed whereby a command of the form ACTOR, GOODBYE would bypass the check whether ending the conversation is permissible (so that, for example, a NodeEndCheck would be ignored).
Bug fixed whereby a Doer might not be matched if an alternative phrasing of a command listed the objects involved in a non-standard order (such as the indirect object before the direct object). For example a Doer with a command string of 'give Thing to Actor' matched GIVE FORK TO MAX but not GIVE MAX THE FORK.
Bug fixed in which the TEST debugging command was omitting the PreParser phase of command interpretation, which could lead to errors in executing commands (such as EVAL) that rely on preparsing before execution.
Version 0.92 (24 Aug 2013)
Risk of incompatibility: Objects that are lockable (i.e. with a lockability other than notLockable) now start out locked by default. This is probably the more natural assumption since most game authors defining lockable objects generally want them to start out locked, and it can be all too easy to forget to explicitly make them locked. Game code that already defines isLocked = true on such objects will not be affected, but if you have any lockable objects that you want to start out unlocked you'll need to define isLocked = nil on them (as is the case for the subclasses of Door defined for the plane in the Airport game example in the Tutorial).
Risk of incompatibility: The sayFollowing() method of Actor and ActorState, along with actorSayFollowing(), now takes two arguments instead of one: sayFollowing(oldLoc, conn) where conn is the TravelConnector just traversed.
The three new Thing methods describePushTravel(via), beforeMovePushable(connector, dir) and describeMovePushable (connector, dest) make it easier to customize the message that's displayed to describe push-travel. The first of these is called on the direct object (the object pushed) when push-travel is via another object (up the stairs or through the door) for example, and is displayed just before the move; via is the preposition (e.g. Through, Up) relevant to the travel. The second, beforeMovePushable(connector, dir), is called on the direct object in response to push-travelling in a particular direction (e.g. PUSH TROLLEY EAST), and again displays a message just before the move. Here connector is the TravelConnector being pushed through and dir (e.g. northDir) is the direction the object is being pushed in. The third of these methods, describeMovePushable(connector, dest) is called on the direct object after the actor arrives in the new room to describe the arrival of the object in its new location (dest) after being pushed via connector.
The new Thing properties objIntoPrep and objIntoName can be used to defined the preposition and prepositional phrase used to describe motion into an object (e.g. 'onto' and 'onto the lawn'). By default objIntoName uses objIntoPrep and theName to construct the appropriate phrase. This was introduced to help push travel messages read more naturally ('You push the trolley onto the lawn' rather than 'You push the trolley into the lawn') but may have other uses.
The two new Thing properties dropItemsBehind and dropItemsUnder (both true by default) control what happens to items behind or under an object when that object is moved. The previous behaviour was inconsistent, in that objects hidden behind or under something would be left behind, while objects otherwise located behind or under (in an Underside or RearContainer) would move with the item being moved. Now if dropItemsBehind and/or dropItemsUnder is true, all such objects notionally behind and/or under are left behind, while if dropItemsBehind and/or dropItemsUnder are nil, items notionally behind and/or under the item being moved are moved with it.
There is now a new BagOfHolding mix-in class which can be used to define objects into which items in the player character's inventory will automatically be moved if his/her hands become too full to take anything else.
The new ContainerDoor class can be used to represent the door of a container defined on the remapIn property of a multiply-containing object.
Some improvements have been made to the listing of contents of items in remote locations, and in particular a remoteObjInName(pov) method has been added to Thing (so that the listing of things in a remote object can be introduced with something like 'In the bucket at the far end of the room are...' instead of just 'In the bucket are...').
The definition of Actor.actorRemoteSpecialDesc() has been changed so that it now more clearly reports that the actor is in a remote location.
There is now a new stagingLocation property on Thing and a new actorInStagingLocation PreCondition. Previously when an actor was in one nested room and entered another, s/he would be effectively teleported from one to the other, thereby passing any restrictions there might be on leaving the current nested room or entering the new one. Now the actor must be in the nested room's stagingLocation (typically its location) in order to enter it, and the appropriate GetOut/GetOff/Board and/or Enter actions will be implicitly peformed to bring the actor there.
Three new ActorTopicEntry classes have been added: AltTopic, AskTellShowTopic and AskTellGiveShowTopic. Of these the most significant is AltTopic, which makes it easier to define alternative responses to conversational commands (just like its adv3 equivalent).
A noResponse property has been added to ActorState. If this is defined it makes the ActorState behave just like an adv3 HermitActorState, i.e. the noResponse is displayed in response to any and all conversational commands (and no attempt is made to find a matching ActorTopicEntry).
The execution of Scenes has been moved from the normal list of events to schedulableList to avoid the same problem that previously occurred with AgendaItems, and the eventManager now makes an additional check to see whether an Event (Fuse or Daemon) has ever been executed in deciding whether it's now due to be executed (an Event that hasn't been executed will now be executed if the current turn count has gone beyond its next execution time — previously such an Event would never be executed). The purpose of these changes is to alleviate the problems that could otherwise occur when one Daemon or Fuse is set by the execution of another, which can happen under circumstances that may not be immediately obvious to the game author, for example by calling startFollowing() from a Scene or AgendaItem. Now that Scenes (as well as AgendaItems) are executed at an earlier and seperate phase from Daemons and Fuses, it should in future be safe to set Fuses and Daemons from them. The test for whether an Event has ever been executed should also prevent an Event from being forever passed over because its next execution time already lies in the past the first time it's looked at (as could otherwise happen when setting up a new Fuse or Daemon from another Fuse or Daemon).
The Component class has now been renamed AttachableComponent, which better reflects its function (as representing an object that become or cease to be a Component during the course of the game). There is now a new simple Component class (defined in extras.t) that can be used for permanent components (almost certainly the more common case).
There is now also a new Attachable class, which can be used to define objects that can be attached to more than one thing at a time (as well has having more than one thing attached to them at a time). This is intended for more complex cases than the SimpleAttachable model can handle, such as a cable that's needed to connect a piece of electrical equipment to a power outlet (and so needs to be plugged into both) or a rope used to tie two or more objects together (which needs to be attached to all of them).
The relationship between locks and keys can now also be defined via the new keyList property of Thing. Giving a Thing a keyList property automatically makes it lockableWithKey, and thereby makes it start out locked. This is in addition to the existing method of defining what items a Key unlocks on its actualLockList property.
Similarly, the rooms in a Region can now be initially specified in the roomList property of a Region, which can in turn be specified via a template.
The infrastructure for defining actions involving three objects has been improved, although to define an action involving a direct object, indirect object and accessory object requires the new TIAAction extension. Note that actions involving, say, two objects and a literal, or two objects and a topic, such as WRITE TEXT IN NOTEBOOK WITH PEN can now be defined without the use of an extension.
The Room class now has a number of methods like canSeeOutTo(loc), and canSeeInFrom(loc) (and equivalents for hearing and smelling) that can be used to fine-tune sensory connections within SenseRegions, in particular in cases where connections may be established or cut dynamically during the course of a game (e.g. when opening or shutting a window allows sound to pass or prevents it from passing).
There is now a collection of sample games that can either be used in conjunction with the exercises in Learning TADS 3 With Adv3Lite or simply perused on their own as illustrations of various aspects of the library.
Adv3Lite now comes with a small collection of extensions, which can be used to add functionality not provided in the main library.
Conversely, there is now also a second version of the library called adv3Liter which contains only the core modules. This may be useful for educational purposes (perhaps to start teaching people how to write in TAD3 3 with only a much reduced version of the library to learn to start off with) or for authors who want to opt in to additional library features they need rather than opting out of those they don't. There is a sense in which adv3Liter is more truly a "lite" version of adv3 than adv3Lite has now become.
Various bugs fixed that caused problems when optional modules were excluded from the build.
Bug fixed whereby the subLister did not use the plural form of 'to be' to introduce a plural list; e.g. it would say "(in which is five matches)" instead of "(in which are five matches)".
Bug fixed whereby a command consisting purely of a noun could cause a run-time error (instead of examining the noun).
Bug fixes whereby QDefaults would consider there to be no sense path to a Room from an object within that room. Note that this bug would only manifest itself when senseRegion.t was excluded from the build, since when senseRegion.t is present, its QSenseRegion is used in place of QDefaults for many of these calculations, and QSenseRegion was doing them correctly.
Bug fixed whereby an implicit Board action was reported as '(first getting in the whatever)' instead of '(first getting on the whatever)'
Bug fixed whereby the eval command could cause a run-time error when used on an object that didn't define a name property.
Bug fixed whereby SitOn, StandOn and LieOn weren't ruling out the attempt to get on something carried by the actor as illogical.
Another attempt made to fix the message parameter substitution system's tendency to use reflexive pronouns inappropriately (e.g. {my} was coming out as 'yourself' rather than 'your' when used following {I}).
Bug (or design flaw) fixed whereby addressing a conversation command to an actor could cause a 'no response' message instead of triggering an implied hello followed by the response from the new state the implied hello changed the actor into.
Bug fixed whereby CommandTopic.actionPhrase displayed '(direction)' rather than the name of the direction involved in the command given to the actor.
Bug fixed whereby objects in closed containers couldn't be heard or smelled even if the container allowed sound or smell through.
Bug fixed whereby the allContents method of Thing was listing some objects more than once.
Bug fixed whereby a Thing was counted as emitting a smell or noise even if its smellDesc or listenDesc didn't actually display anything (but weren't defined as nil); this made it difficult to define these properties conditionally, e.g. a music emitting sound only when it was on.
Bug fixed whereby a Noise couldn't be listened to and a Smell couldn't be smelt unless they were visible.
Bug fixed whereby items might be listed in room descriptions even when their isHidden property was nil.
Bug fixed whereby an object marked as mentioned might still show up in a room description listing.
Bug fixed whereby a command like ASK HER ABOUT THE WEATHER might be perversely interpreted by the parser as an AskAboutImplicit command meaning ASK HER ABOUT HER ABOUT THE WEATHER; the fix applied is to reverse the priorities of the AskAbout and AskAboutImplicit VerbRules; hopefully this won't create other problems in the course of solving this one.
Bug fixed which caused the specialDesc from a FollowAgendaItem to be used once the FollowAgendaItem was added to an Actor's agenda even if its isReady condition had not yet been met.
Thing.okayOpenMsg has been corrected.
Version 0.91 (05 July 2013)
Risk of incompatibility: The second parameter in the travelerEntering() method of Room and Region has been changed from dest to origin, on the grounds that this is likely to be more useful (the dest parameter was entirely redundant on a Room, and it seems as well to make Region consistent with it). The method thus becomes travelerEntering(traveler, origin), where origin is the Room that the traveler is on the point of leaving.
Risk of incompatibility: The method of indicating plurals in a vocab string has changed from using parentheses () to braces {}, so, for example, one would now use 'child{-ren}' rather than 'child(-ren)' or 'mouse{mice}' in place of 'mouse(mice)'. The reason for the change is to avoid a potential clash with the use of parentheses to indicate weak tokens, introduced in version 0.9. It may be that no existing game code will be affected at all, since the need to specify plurals in this way seldom arises (the library already recognizes many common irregular plurals). This is one reason why we changed the notation for plurals rather than for weak tokens, since weak tokens are likely to be used more frequently; the use of parentheses with weak tokens is also consistent with adv3.
One piece of code that will be affected is the definition of the red switch in the maintenance room in the tutorial example, where (-zz) will need to be replaced with {-zz} if you are in the process of following the tutorial and have got beyond that point. Otherwise you will only need to make changes to existing code if you have used the (xxx) notation to define any custom plurals anywhere in your own vocab strings.
Slight Risk of incompatibility: The order of end-of-turn events has now changed, so that Actors' AgendaItems and the like are run before Fuses and Daemons. This allows an AgendaItem to set a Fuse or Daemon (for example via a call to startFollowing()) without the risk of errors due to timing issues. One knock-on effect of this change is that AgendaItems that executed on the same turn as an NPC moved from one location to another (for example, as a result of following the player character) may not now execute until the following turn. If this creates problems, you can call getActor.executeAgenda() from the arrivingTurn() method of the actor's current ActorState, or, if there is none, executeAgenda() from the actor's actorArrivingTurn() method.
The documentation has undergone a bit of reordering. For one thing, it has all been moved under a docs folder in the adv3Lite directory to make for a cleaner separation between from the library source files. There is now an Adv3Lite Bookshelf (similar to the TADS 3 Bookshelf that comes with the standard TADS 3 documentation), a Quick Start Guide for adv3Lite, and a new book, Learning TADS 3 With Adv3Lite. This is very similar in format and content to the Learning TADS 3 book that comes standard with TADS 3, but has been adapted for use with the adv3Lite library. It is provided as a PDF and provides an alternative tutorial, based on a reasonably systematic tour of the adv3Lite library and TADS 3 language, rather than on the creation of a number of tutorial games (the examples in this book may need further work, since they were taken more or less intact from Learning TADS 3 and may need some adapting for use with adv3Lite).
NodeEndCheck and NodeContinuationTopic now have the nodeActive condition as part of their active property instead of their isActive property. The reason for the change is that game authors could easily override the isActive property without realizing that they needed to add the inherited condition to their own. Now they don't have to worry.
The grammar for the TELL command has been tweaked so that TELL X is parsed as TELL [topic matching X] rather than TELL [actor matching X]. This is probably more useful as a command like TELL BOB (with no more specified) is seldom useful whereas it may well be useful to be able to use a TellTopic to match commands like TELL A LIE or TELL THE TRUTH. A similar change has been made to the grammar for ASK X.
The definition of blockEndConv has been moved from NodeEndCheck to a new EndConvBlocker mix-in class, which has been added to the classlist of the Actor, ActorState and NodeEndCheck classes. This allows the canEndConversation() methods of all three classes to use blockEndConv as a possible return value.
The library now has a commLink object that can be used to establish remote communications between the player character and one or more other actors in remote locations. You can use commLink.connectTo(other) to establish a remote audio link with other, or commLink.connectTo(other, true) to establish a remote audiovisual link. Use commLink.disconnect() to sever the connection again. For further details read about the Communications Link Special in the chapter on Querying the World Model.
The new setPlayer(actor, person) function can be used to change the player character to another actor. The person parameter is used to determine whether the new player character will be referred to in the first, second or third person; it should be supplied as either 1, 2 or 3; if it is not supplied it defaults to 2.
The temporary fix for the problem with the parser matching possessives has now been replaced with a more robust solution provided by Mike Roberts (this may be invisible to game code).
The new Mentionable method filterResolveList() allows objects to adjust the list of matched objects while the parser is deciding which objects to match to a player command. This can be used for an object to exclude itself or other objects from the match list. The Unthing class now uses this to exclude any Unthings from the match list when any other objects are present; it is also used by the new CollectiveGroup class.
The new CollectiveGroup class can be used to represent (and stand in for) a group of similarly-named objects for selected actions.
The Actor method startFollowing() now checks whether there's already a following Daemon running for that actor before creating a new one; this should prevent problems that could otherwise occur if startFollowing() were called while the actor was already following the player character.
There is now an objSmellable PreCondition which is used to enforce smellability (i.e. the existence of a scent sense-path) on the SmellSomething action.
Bug fixed whereby an actor would never end a conversation through boredom (the boredomAgendaItem was never being added to Actors' agendaLists)
Bug fixed whereby issuing a CONTINUE command could cause a run-time error when there wasn't any journey to continue on.
Bug fixed whereby askMissingObject() could cause a run-time error when an existing direct object was needed to help choose a new indirect object.
Bug fixed whereby askMissingObject() was allowing the action that called it to continue instead of stopping it in the case where it executed a replacement command. A return statement was being used where an exit statement was needed to terminate the original action.
Bug fixed whereby a Component could be detached with a simple DETACH command (whereas a Component is normally a permanent attachement, unless something more specific is done to detach it).
Bug fixed whereby anything could be attached to a SimpleAttachable even if it was not in its allowableAttachments list.
Bug fixed whereby plugging something in could cause a run-time error (because the PlugInto action needed to resolve the direct object before the indirect object).
Bug fixed whereby the second half of a split inventory listing would start with a lower case letter even when its initial word should be capitalized.
Bug fixed whereby the automatic calculation of the timesToSuggest property of an ActorTopicEntry that's also an EventList was not working properly.
Bugs fixed whereby excluding actor.t from the build would cause compilation errors and warnings even if the game didn't require this module.
Version 0.9 (08 June 2013)
Slight risk of incompatibility: The mentionsAll() function has been withdrawn, since it's no longer needed, and it wasn't a good way of doing what in did anyway. Instead of testing mentionsAll(cmd) test cmd.matchedAll.
Slight risk of incompatibility: The regular verbs have been removed from the englishCustomVocab.verbParams list, since they are no longer needed. If you have any code that still uses message parameters like {appears} or {opens} with regular verbs, you'll need to change them to the regular form (appear{s/ed} or open{s/ed}). Irregular verbs like {think} or {take} are not affected.
Very slight risk of incompatibility: In a few cases the withdrawal of regular verbs from the verbParams list might have caused problems with the {don't verb} and {must verb} parameter substitutions that required the past participle of verb in some tenses. To deal with this regular verbs in these constructions should now be followed by the appropriate past participle in square brackets; e.g. {don't open[ed]} or {don't close[d]} or {must stop[?ed]}. This will only effect games in fairly unusual tenses, so it's quite likely that know existing game will actually be affected, although it has been necessary to change a few library messages to cater for this. Once again, irregular verbs (e.g. {must take} or {don't know}) are not affected.
Very slight risk of incompatibility: The properties showReport and giveReport have both been renamed to summaryReport, in the interests of consistency and ease of use. Since the use of these properties wasn't documented anywhere and they didn't quite work properly anyway, it's unlikely that any existing game code will be affected, but if any existing game code does make use of them it will need to rename them accordingly.
It is now possible to summarize the results of a GIVE or SHOW command acting on a set of objects, rather than getting an individual report for each object. The newly-named summaryReport property is now correctly reset in the execGroup() method of Give, Show, GiveImplicit and ShowImplicit and correctly used in the report phases of dobjFor(Give), dobjFor(Show), dobjFor(GiveImplicit) and dobjFor(ShowImplicit) on Thing. It is joined by a new property summaryProp defined and deployed in the same places. summaryProp can be set to a property pointer to execute a method on the current interlocutor at the end of a GIVE or SHOW command executed on a set of objects. Instructions on how to use these properties can be found in the new section on Summarizing Give and Show.
A number of library messages that were found to be erroneous when making the foregoing changes have now been corrected.
In previous versions the extraReport() macro did not carry out any message parameter substitutions. This may not be what all game code expects. extraReport() has accordingly be changed from a macro to a function, and unless the second, optional, parameter is specified as nil it will carry out message parameter substitutions before displaying its text.
The message parameter substitutions {donot verb} and (equivalently) {doesnot verb} have been added. These work just like {dont verb} and {doesnt verb}, except that the negation isn't contracted (e.g. "Fred does not respond" instead of "Fred doesn't respond").
An Instructions module has been added to the English-specific part of the library. This allows games to provide a set of standard set of instructions for playing Interactive Fiction. It's based closely on the adv3 equivalent (from which it's largely taken), with one or two minor adaptations for adv3Lite. This is the first of several new features aimed at making adv3Lite more approachable to new players.
A second feature aimed at new players is the optional module newbie.t in the English-specific part of the library. This looks out for various kinds of malformed commands that new players often attempt to use and provides more helpful responses than the standard parser error messages, in an attempt to nudge new players in the right direction. It also allows the game to watch out for when players seem to be getting stuck, particularly at the start of the game, so it can offer them some help.
The third newbie-friendly feature that's been added is the ExtraHint mechanism, which allows game authors to display hints to players who look as if they may be getting stuck.
The English part of the library now contains a yesOrNo() function which simply reads a command-line response and returns true for an affirmative response and nil otherwise. The Instructions module makes use of this, and it seemed worth adding it for general use.
The SimpleAttachable class now has attachTo(obj) and detachFrom(obj) methods, which should make it easier and to attach and detach objects by programmatic fiat (e.g. when a magnet attracts a small item to itself).
Thing now has a new hideFromAll(action) method, which can be used to exclude an object from the list of things the parser chooses in response to ACTION ALL.
Thing now has a new ownerNamed property (in the English-specific part of the library). If this is true then the theName (but not the aName) property of this object will be followed by its name preceded by the possessive form of its owner's name, e.g. "Bob's wallet" or "Jane's mouth". This may be particularly useful in defining body parts, but is potentially useful in any situation where an object has a specific owner (do can in any case be referred to as "Bob's wallet" or "Jane's mouth" by the player) and we want to include the name of the owner when referring to the specific object in game output, e.g. "You take Bob's wallet" (it was lying on the table) but "Bob is carrying a wallet".
The library now defines a new objUnlocked PreCondition. This isn't actually used anywhere in the library, but game code is free to use it. It would normally only be meaningful to do so in the dobjFor(Open) preCond list of objects with a lockability of either lockableWithoutKey or lockableWithKey. In the latter case the objUnlocked PreCondition will only attempt to unlock the object if the actor is carrying a key that might plausibly work.
There is now an Unthing class which can be used to represent objects that are absent.
The Thing class now as an isHidden property which can be used to hide things from view. TravelConnector now accordingly defines isConnectorApparent = !isHidden, so that a hidden TravelConnector (such as a concealed Door) is automatically not apparent.
It's now possible to define weak tokens in a vocab string by placing them in parentheses. E.g. '(her) foot' would match 'her foot' or 'foot' but not 'her', or alternatively by following the word with the special token '[weak]', e.g. 'her[weak] foot'. These two methods are currently functionally equivalent to defining the vocab as 'her[prep] foot' but having a special syntax for weak tokens looks more intuitive and should allow for weak tokens and prepositions to be treated differently in the future should this turn out to be necessary.
The VerbProduction class (and hence VerbRules) now has an isActive property, which can specify the conditions under which the VerbRule is matched (this makes it possible, for example, for the newbie.t module to switch off a whole lot of its VerbRules when a conversation is in progress so as not to intercept potentially valid conversational commands). An isActive property has also been added to the StringPreParser class, for similar reasons.
The library defines two new macros gLocation and gRoom to get the player character's current location and current room respectively (often these will be the same, but they need not be if the player character's immediate location is something other than a Room, such as a bed or chair). It also defines a new trio of macros gTopic, gTopicText and gTopicMatch, which give the ResolvedTopic of any current TopicAction or TopicTAction, the text corresponding to that ResolvedTopic (i.e. the text it attempted to match) and the getBestMatch property of that ResolvedTopic (the Topic object it best matches).
The library now attempts to be a bit smarter about combining implicit action reports, so that, for example:
(first taking the coin)
(first taking the coin)
(first taking the coin)
should become:
(first taking three coins)
The Actor class now provided some default output in actorSpecialDesc. This is to ensure that NPCs are listed in room descriptions even if the game author doesn't define this property or a specialDesc.
There has been some rearrangement of the verify methods of conversational commands. These are now all defined on Thing and not overridden on Actor. The new property canTalkToMe is nil on Thing and true on Actor (and normally shouldn't be overridden by game code); this allows conversational commands on Actor but not Thing. The main purpose of this is to allow Actor to inherit the new verify tests on Thing preventing people talking to themselves (or giving or showing things to themselves).
The new Thing property opened tracks whether an object has ever been opened. This will be nil for an object that starts out open and has never been closed and reopened.
If one side of a Door starts out open, the library now assumes that the other side should start out open too.
Thing now has a getFacets property, which can be set to a list of other Things that are facets of the object it's defined on (and which can thus be regarded as potential pronoun antecedents of the same object). The only objects for which this is automatically set by the library are the two sides of the same door.
The getCarriedBulk() method now excludes anything fixed in place from its calculation of total bulk as well as anything worn. The reason is that anything fixed in place inside an actor is likely to be a body part, not something carried.
The TravelConnector class now has a noteTraversal(actor) method which is invoked when it is traversed by actor. The travelDesc method is now called via noteTraversal(). This gives game authors a little more flexibility in defining the side-effects of travel when the traveler is not the player character.
TravelConnector's travelDesc() method now calls doScript() by default if the TravelConnector in question is also a Script (i.e. EventList). This makes it straightforward to vary the message that is shown when the player character traverses the connector.
Room's roomDaemon() method now likewise calls doScript() by default if the Room is also a Script. This makes it easy to define a series of atmospheric messages on the Room (simply by mixing it in with an EventList class and giving it an eventList property)
The new Thing method isVehicle allows a Booth or Platform to be used as a vehicle. If the player issues a travel command while the player character is in (or on) an object for which isVehicle is true, then that object will travel with the player character in (or on) it.
It's now possible for Doer's cmd strings to match commands like 'go south' or 'go east|west' and to work as expected (i.e. matching GO SOUTH in the first case and GO EAST or GO WEST in the second). The former method of defining matching directions on the Doer's direction property still remains, both for backward compatibility and because internally the library still uses it (it simply scans the cmd string for direction names and adds the corresponding directions to the Doer's direction property).
The Room class now defines two new properties/methods allowCompassDirections and allowShipboardDirections. If either of these is nil then referring to a compass or shipboard direction respectively in a command will result in the command being blocked with "Compass/Shipboard directions have no meaning here." This check enforced by the new Doer method checkDirection(), which is invoked from Doer.exec() if the command refers to a direction. By default allowCompassDirection is true for all rooms (although game code can, of course, override this) whereas allowShipboardDirections is true only on rooms that actually define a non-nil shipboard direction exit (fore, aft, port or starboard). This should make it easier for games to block the execution of seemingly meaningless commands like THROW BALL PORT in locations where PORT has no meaning.
The <.roomdesc> style tag now works (it was ignored before), and a new <.roomcontents> style tag has been added for formatting the listing of a rooms's contents.
Bug fixed whereby one got an inappropriate response to FOO ALL when there was nothing available to foo.
Bug fixed whereby an adjectival possessive (e.g. "drivers's" in a name like "driver's license") couldn't be matched to the name of an object.
Bug fixed whereby the cquoteOutputFilter failed to recognize (and so ignore) HTML tags containing double quote marks (e.g. '<a href="foo" </a>'. It now does so does not attempt to replace any quotation marks within them. This makes it easier to output strings using the aHref() function or explicit anchor tags. HTML tags containing single quote marks were already recognized before.
Bug fixed whereby message parameter substitutions were still a bit too eager to use reflexive pronouns. Reflexive pronouns should now occur only (a) when the parameter explicitly requests them (e.g. {himself dobj}) or when the noun/pronoun being substituted for refers to the same object as the last grammatical subject encountered in the sentence.
The subLister (responsible for messages like '(in which was a gold coin)') previous omitted a space after the introductory text (thus producing text like '(in which wasa coin').) This has now been corrected.
Version 0.8 (17 May 2013)
Slight risk of incompatibility: Some of the DMsg() and BMsg() identifier names have been changed, or messages merged. This is mostly to correct the occurrence of duplicate identifiers that had crept in, but in one or two cases was in the interests of naming consistency (in particular names beginning 'cant' have been changed to names beginning 'cannot'). This will only affect game code if you have defined a CustomMessages object to customize some of the library messages, and even then only a few messages are affected.
You can now control whether or not other actors in the vicinity "overhear" information imparted to the current interlocutor. By default a <.inform tag> tag calls the setInformed(tag) on every actor within earshot. This can now be prevented by setting informOverheard = nil on the current ActorState, or actorInformOverheard = nil on the Actor (when the current ActorState is nil). To prevent the overhearing behaviour globally, set informOverheard = nil on the actor or on the whole Actor class.
Templates have been added for EventList and ShuffledEventList.
The English-language library now automatically sets the name of a thing to the appropriate pronoun ('I', 'we', or 'you') if its person is 1 or 2; this may make it slightly easier to define the player-character object.
The new Actor method travelVia(conn) makes the actor travel via the TravelConnector conn and reports the actor's movement if it is visible to the player character.
There is also a new Actor method sayArriving(fromLoc), which is called by Actor.travelVia() (as is sayDeparting()). By default sayArriving(fromLoc) calls sayArriving(fromLoc) on the current ActorState which by default in turn calls sayActorArriving(fromLoc) back on the Actor. The sayArriving(fromLoc) method displays only the most basic default message, which most games will probably want to customize. It can also be suppressed altogether by supplying nil as the second (optional announceArrival) parameter when calling travelVia(), since it may sometimes be easier to call travelVia() followed by your own custom arrival message than to customize sayArriving().
Before Travel notifications are now triggered when an actor tries to travel via a direction that's defined as a method or double-quoted string. That means that when you define the direction property of a Room as a method or double-quoted string, beforeAction(gActor, direction) will be called on every object in scope (allowing any one of them to veto the proposed travel with an exit macro if desired). Note that normally before travel notifications are called as beforeAction(traveler, connector), but since in this case there's no connector object to pass as a parameter we pass the direction object (e.g. westDir if the actor is trying to go west) instead.
Additionally, if the direction property is defined as a method, then the current room's notifyDeparture(actor, destination) method will be triggered, providing libGlobal.extraDestInfo has a non-nil destination for the proposed travel.
The Distant class now defines its decorationActions property as [Examine] only, rather than inheriting [Examine, GoTo] from Decoration. This is probably the better default since most Distant objects are, by their nature, too far away for the player character to go to them (e.f. the sun, moon, sky or a distant mountain). In some cases a Distance object may be 'locally distant', however, such as a sign mounted too high up on the wall to touch. In that case it may be appropriate for game code to override the decorationActions property of the Distant object to include GoTo, since the player might reasonably use GO TO SIGN to take the player character to the location of the sign.
It's now possible to set up test scripts for the purposes of debugging which can be run with commands like TEST FOO. For further details see the Debugging Commands section of the manual.
The Parser.defaultActions option has now been switched back on by default. This is the option that allows a command that consists entirely of a noun phrase (such as ME or RED BALL) to be treated as an examine command with the noun as its object. It's now possible to restore this behaviour since the bug that caused it to be a bit too wayward has now been fixed (see below).
Game code can now use the tense-switching message substitution {present-str|past-str}; this simply displays past-str if the game is in the past tense and present-str otherwise. This does much the same tSel('present-str', 'past-str'), but does it more concisely.
Previously, attempting to use a message parameter substitution verb without a corresponding subject (e.g. "There {is} not much here") would cause a run-time error. Now the English-library defaults to a third-person singular dummy subject in such cases (so that "There {is} no much here" is effectively equivalent to "There {dummy} {is} not much here"). This change avoids the need to include an explicit {dummy} subject in such cases. An explcit dummy {plural} subject is still needed to make the verb take a plural form, however.
A number of adv3-style verb conjugation parameters have been added to the English library: {s/d}, {s/ed}, {es/ed}, {ies/ied} and {s/?ed}. These can be use to conjugate regular verbs in message parameter substitutions like "{I} close{s/d} the door and cross{es/ed} the room. " In addition, over two hundred irregular verbs are now defined in the English-specific part of the library. This should largely remove the need to define CustomVocab objects (and to check whether they need defining) in order to define new message parameter substitutions for additional verbs, since all regular verbs can now be dealt with the {s/d} type endings, and the library should now recognize most common irregular verbs.
For further details see the sub-section on Conjugations and Tenses in the Messages chapter.
The englishCustomVocab currently defines a number of regular verbs in its verbParams list (along with over 200 irregular ones). These regular verbs are likely to be removed from the list in a future version, since they are no longer needed there. now that the library has an alternative means of conjugating regular verbs. The regular verbs have been left in the list for the time being for backward compatibility. In any case, library messages that make use of such regular verbs will first need to be changed to use the alternative conjugation method (e.g. {achieves} will need to become achieve{s/d}). Game code that uses the old-style message parameter substitutions for regular verb (e.g. {achieves} rather than achieve{s/d}) will not be affected for now, but it will be advisable to replace any such old-style substitutions with the new-style ones in time for the next update.A tweak has been made to the way the message system handles reflexive antecedents. The original Mercury library substituted a reflexive pronoun wherever an object occurred more than once in successionin the same sentence, but this could generate ungrammatical messages such as "You can't take the rug while you're standing on itself." This feature was disabled altogether in an earlier version of adv3Lite, but that meant one might get messages like "You can't eat you" rather than the more grammatical "You can't eat yourself." The reflexive antecedent mechanism has now been tweaked again so that the reflexive pronoun is automatically used when it refers back to the subject of the sentence. There are cases where you might want to use a reflexive pronoun to refer to the object of the sentence, such as the "You can't put the box in itself" example originally envisaged by the Mercury library, but these are usually particular cases where you can use the {himself dobj} message parameter substitution to generate the reflexive pronoun (because, for example, the message is being called from an illogicalSelf() macro in a verify routine to prevent the same object being used in two different and incompatible roles simultaneously).
In TADS 3.1.3 and above, it should now be possible to create new adv3Lite projects directly from Workbench's New Project wizard (provided the adv3Lite library directory is where Workbench expects to find it). For details, see the section on Starting Out — A Minimal Game Definition
The new Actor method actorSay(str) can be used to output a string representing all or part of a conversational exchange in contexts where simply using say() or a double-quoted string could potentially confuse the conversation system and give rise to hard-to-find bugs in game code. For a fuller discussion see the subsections on Actor-Specific and General Tags and on the use of actorSay() to initiate NPC conversation.
The suggestedTopicLister now separates out the methods showListPrefix(lst, pl, explicit), showListSuffix(lst, pl, explicit) and showListEmpty(explicit). This brings it more into line with the Lister class and also makes it easier for game code to customize these parts of a list of suggested topics.
The sceneManager now runs the scene-checking mechanism for the first time at the Init stage, i.e. just before the first room description is displayed. Previously, the scene-checking mechanism was run for the first time at the end of the first turn, which made it difficult to define a Scene that starts out active right at the start of play. Note that this means that the whenStarting() method of a Scene whose startsWhen condition starts out true will be executed before the first room description is displayed.
The Library Reference Manual is now included as a standard part of the documentation set. This is the adv3Lite equivalent of the Library Reference Manual that comes with adv3, namely a fully indexed and hyperlinked set of HTML files that allows you to look up every class, object, macro, property, method, or function defined in the library and see where it is defined in the source code, and, in the case of a class or object, what classes it inherits from, and what properties and methods it defines.
The adv3Lite version of the Library Reference Manual additionally includes a Messages tab to help track down library messages and their BMsg or DMsg IDs. Jerry Ford's discovery-tool-generated messages CSV file is also included with the documentation set in order to provide an additional means of searching for library messages. For further details see Finding Message IDs in the Messages chapter.
The Library Manual now has an index, which immediately follows this change log.
The adv3Lite documentation now provides a link to the TADS 3 System Manual in one or two places. This is done via the file sysman.htm in the adv3Lite directory. By default this redirects to the on-line version of the System Manual on www.tads.org, because the location of your local version will vary according to what operating system you're using. If you prefer you can edit sysman.htm to make it redirect to the local copy of the System Manual on your system. For instructions see the section on the System Manual in the setup chapter.
Bug fixed whereby every Actor was inadvertently sharing the same informedAboutTab table (so that if one Actor was informed about something, all Actors ended up being informed about it).
Bug fixed in which the behaviour of checkReachIn() might not have been what was expected. Previously, checkReachIn() might block reaching from A to B even when A and B were on the same Platform (for example) that defined the checkReachIn() method. That was because the checkReachIn() method used the commonInteriorParent() method to determine whether A was trying to reach inside the object in question, but commonInteriorParent() only counts a parent as common if its a Room or if its contType is In. The library now defines a new commonContainingParent() method that finds the common parent in the containment tree regardless of containment type; QDefaults.reachProblemCheck() now uses commonContainingParent() rather than commonInteriorParent() when checking checkReachIn() conditions, which should produce more intuitive results.
Bug fixed whereby the sayDeparting() method of FollowAgendaItem did not work as stated in the manual (since it was never being invoked).
Bug fixed whereby an apostrophe was incorrectly occurring in certains plurals, e.g. "20's" instead of "20s".
Bug fixed whereby responding to a What do you want to foo? prompt when Foo is a LiteralAction might cause a run-time error if the player responded with the name of an object in scope.
Bug fixed whereby responding to a What do you want to foo? prompt when Foo is a LiteralAction or TopicAction might cause the response "I don't understand that command" instead of executing the command with the specified literal or topic.
Bug fixed whereby the compiler would create a couple of warnings if the game contains no me object (because the player character object is called something else).
Bug fixed which could cause a run-time error in calculating scope when the player character isn't the me object.
Bug (or bugs?) fixed whereby odd interactions between the parser and the spelling checker could cause seemingly inconsistent responses to commands involving non-existent objects (e.g. X FOO when there's no FOO in the game, or just FOO when defaultActions is true). Thanks are due to Mike Roberts for providing the fix.
Bug fixed which truncated the library message shown in the past tense to say that there were no topics to suggest.
Version 0.7 (10 April 2013)
Risk of incompatibility: The way the activated property of an ActorTopicEntry works has been substantially changed. The activated property now starts out true by default on all ActorTopicEntries; if it becomes nil the ActorTopicEntry becomes inactive regardless of the value of its isActive property. Thus, for an ActorTopicEntry to be active, both its isActive property and its activated property must be true.
The <.activate key> tag works as before, setting the activated property to true of all ActorTopicEntries whose convKeys match tag. There is now also a <.deactivate key> tag which does the reverse, i.e. setting the activated property to nil of all ActorTopicEntries whose convKeys match tag. The topicResponse method of an ActorTopicEntry can also call the new deactivate() method to deactivate itself, which may be useful, for example, in making an ActorTopicEntry no longer available once it has been viewed.
If you have used the activated property in existing code, search for every ActorTopicEntry in your game that uses the activated property as part of its isActive condition, then remove activated from the isActive condition (or remove the isActive condition altogether if it simply defines isActive = activated) and instead defined activated = nil on the ActorTopicEntry in question.
While this change might be a minor nuisance, it should hopefully make it easier to activate and deactivate ActorTopicEntries in future. For further details see the discussion in the section on ActorTopicEntry.
Risk of incompatibility: As many library messages as can be have now been moved off the libMessages object (to make use of BMsg() or DMsg() at the points where they are actually needed in the library). This makes the library message system more consistent, since the libMessages object was largely a historical hang-over. Game code should not be affected unless you have specifically referred to the libMessages object in your code.
It has nevertheless proved necessary to retain the libMessages object for use with the webUI (part of which expects it to be present) and the menu system (which also makes use of it in ways that would be too fiddly to be worth changing). It should not now be used for any other purpose.
Slight risk of incompatibility: A number of redundant methods, properties, and functions have been removed from the library, many of them on Thing or LMentionable. These were methods etc. that were not being used anywhere else in the library and looked unnecessary for author game code. None of them was documented (in the manual or tutorial) and so game code should not have used them.
Slight risk of incompatibility:: At the check stage the preconditions are now checked before the check routines on the direct/indirect object. Previously it was the other way round, but checking the preconditions first seems a more logical order (for example, it means when the player character tries to open an obejct we now check whether the object is touchable before determining whether it's locked, which makes better sense since if the PC can't touch an object s/he may not be able to determine whether it's locked by trying to open it).
A new extraReport() macro has been added, for use in action() methods. This is to allow an action method to output a brief message like "(with the brass key)" without suppressing the default message from the report stage. It's now used on dobjFor(Lock) and dobjFor(Unlock) to allow the default messages for these actions to be moved to the report stage, which is more consistent with how other actions work.
Actor-initiated conversation via a ConvAgendaItem or TopicEntry now notes the initiating actor as a possible pronoun antecedent (so that, for example, if Bob addresses the player character the player can refer to Bob as 'him' on the next turn).
The mechanism by which ' (providing light)' is added to the name of an object in a listing has been made a bit more generalizable. Previously this string was hard-coded into the English-language item lister; now the item lister obtains it from the State object, and the same mechanism could be used to add similar state-specific information from user-defined State objects if so desired. This should make no difference to existing code.
GoTo has been added to the list of actions (previously only Examine) that can be performed on a Decoration (since this seems a more natural response to a GO TO command than seeing the notImportantMsg would be), but going to a Decoration is regarded as slightly less logical (logicalRank(90)) than going to a non-Decoration.
Where a Room doesn't define a vocab property, it now takes its vocab (and hence its name) from a lower case version of its roomTitle property, provided its autoName property is true. This saves typing the same name twice when the name and the roomTitle are the same (while still allowing them to be different when required). If a Room's roomTitle is meant to be a proper name (such as 'Market Street'), you can prevent the conversion to lower case by defining proper = true on the Room.
A sayDeparting() method has been added to several classes to provide a default message describing the departure of an NPC. The sayDeparting(traveler) method On TravelConnector describes traveler leaving via that connector. On the base class this is described as the traveler leaving in the appropriate compass direction. On Door, StairwayUp and StairwayDown this is overridden to describe the traveler leaving through the door or up or down the stairway.
The new Actor method sayDeparting(conn) calls sayDeparting(conn) on the current ActorState which in turn calls sayActorDeparting(conn) on the actor which in turn calls sayDeparting() on conn, allowing customization at any point.
At the moment these methods are only used by the new FollowAgendaItem (see below), but they can also be called by game code to describe actor travel as desired.
The new Actor methods sayActorCatches(obj) and sayActorDropsCatch(obj) have been separated out from the action handling of iobjFor(ThrowTo) to make it easier for game code to customize the messages for an actor catching or failing to catch an object thrown to that actor.
The test for Q.canThrowTo(gActor, self) in the action handling of Actor iobjFor(ThrowTo) has been moved from senseRegion.t to actor.t to allow these two files to be included or not included in a project independently of each other. Previously senseRegion.t modified the Actor class, which means actor.t would have had to be present if senseRegion.t was present.
The new FollowAgendaItem class can be used to make an NPC move along a predefined path in response to a FOLLOW command of which the NPC is the direct object. For example, if Bob has an active FollowAgendaItem then when the player types FOLLOW BOB, Bob will move through the next connector in his FollowAgendaItem's connectorList and the player character will follow him. For details see the section on AgendaItems.
The Thing method checkReachIn() now has a second (optional) parameter target which is the object the actor is trying to reach.
The library now defines three new macros to act as named constants for use with ConvAgendaItems: InitiateConversationReason (1), ConversationLullReason (2) and DefaultTopicReason (3). This may help make code that uses these constants a little more readable.
The quoteFilter OutputFilter object has been moved from actor.r to output.t, where it more logically belongs. This allows games to get the benefit of the quoteFilter (which checks and corrects for unbalanced smart quotes) even when actor.t is not present.
When a SpecialTopic is about to create a new Topic object from its matchPattern property (to allow matching Topics to be created on the fly in game code), it first checks that that an equivalent Topic doesn't already exist; if one does exist, the SpecialTopic uses it as its matchObj instead of creating a new Topic for the purpose. This may make for more efficient topic matching.
The library now defines an TellTalkShowTopic class, which responds to TELL X ABOUT Y or TALK ABOUT Y or SHOW Y
The keyTopics list property of an ActorTopicEntry can now contain control tags (such as <.arouse key> or <.activate key>) as well as convKeys strings. This is to allow a group of topic entries to be activated or aroused just prior to being suggested; e.g. keyTopics = ['<.activate bob-info>', bob-info].
The library now defines an ObjectPreCondition class, which can be used to construct custom preconditions that apply to specific, pre-determined objects, rather than the direct/indirect object of the command.
The library now defines two new methods on the Region class: regionBeforeAction and regionAfterAction. These methods are called just before and just after an action takes place in any room in the region.
The Mentionable class now defines the ambiguouslyPlural property which allows objects with names like 'pair of shoes' or 'flight of stairs' to be referred to as either 'it' or 'them'.
In the English library the ambiguouslyPlural property can be set automatically from the vocab property by including both 'it' and 'them' in the pronoun property. To make the object actually plural, put 'them' first.
The new Room method getDirection(conn) returns the direction in which one would have to travel from the room in order to travel via conn (i.e. the direction corresponding to the direction property on which conn is defined). For example, if frontDoor was assigned to the north property of a room called hall, hall.getDirection(frontDoor) would return northDir.
The new outputFilter method captureOutputIgnoreExit() works the same as captureOutput() but attempts to ignore any exit signal thrown by the function whose output it's capturing. This is principally to allow for the use of exit macros in check routines, where they are not needed but may be used by authors used to adv3.
The handling of the LookIn, LookUnder and LookBehind actions has been streamlined slightly, to make them more consistent with one another, to make proper use of remapping to appropriate remapXXX objects and refactor some common code into shared methods. Also, lookInMsg, lookUnderMsg and lookBehindMsg are now displayed using the display() method, which means they can be specified as double-quoted strings or methods in addition to single-quoted strings.
The Q.reachProblem() method now builds its list of reach problems by calling two new Query methods in succession: reachProblemVerify() and reachProblemCheck(). This allows the touchObj PreCondition to call Q.reachProblemVerify() at the verify stage and Q.reachProblemCheck() at the check stage, which avoids the code relating to the check stage being called twice (with possibly undesirable side-effects). The check code was called twice before since it was part of reachProblem, which was called from the verify stage of touchObj, which is called twice (once for disambiguation, and once when seeing if the action can go ahead).
Bug fixed in which included an article ('a' or 'the') in the name of a topic (e.g. ASK BILL FOR THE TIME) could confuse the parser. The English library now strips any articles from the tokens it's trying to match before attempting to match a Topic.
Bug fixed whereby "forward" was not recognized by the parser as the name of a direction even though it might be shown in the exit lister. "Fore", "forward" and "f" are now all recognized as referring to the forward direction.
Bug fixed whereby the LOCK and UNLOCK commands would ask for a key even when an item was defined as lockableWithoutKey (this bug was introduced in version 0.6).
Bug fixed with the capitalization of 'You' in the standard library message for setting something to.
Bug fixed whereby attempting to travel through a closed door which may not be opened via an implicit action (because opening the door verifies to nonObvious or dangerous) would display nothing at all, leaving it unclear what had happened. Such travel now results in a message saying that the door is in the way.
Bug fixed in the Thing method display(prop), which failed to display anything if prop was a method that returned a single-quoted string; now the single-quoted string is displayed.
Bug fixed whereby using OOPS caused a run-time error.
Bug fixed that caused a run-time error with the <.topics> tag.
Bug fixed whereby a <.convnode> tag in the invokeItem() method of a ConvAgendaItem didn't work properly when the ConvAgendaItem was triggered by a DefaultAgendaTopic.
Bug fixed whereby a QueryTopic template could be misinterpreted (by the compiler) if the QueryTopic was combined with an EventList and the qType and matchPattern were combined in a single string.
Bug fixed whereby the suggestedTopicLister would have output a list of AskForTopics twice instead of a list of suggested AskForTopics followed by a list of suggested CommandTopics.
Bug fixed whereby making a Component part of something that's not a SimpleAttachment could cause a run-time error at preinit.
Bug fixed which stopped the verifyReach() method working properly.
Bug fixed whereby an UnlistedProxyConnector (one created using the asExit() macro) might be treated as invisible in the dark even when the connector it was a proxy for was visible.
Bug fixed which prevented inheritance of vocab from superclasses after the first member of the class.
Bug fixed whereby nothing at all (not even a contents listing) would be shown after the room name for a Room whose desc property had not been defined.
Bug fixed whereby the valToList() function failed to return the correct value when its argument was a Vector; it now converts a Vector to a List.
Bug fixed whereby use of the exit macro in the checkPreCondition method of a PreCondition would cause the game to terminate with an unknown exception. There is actually no need to use an exit macro in this situation, and game code should avoid doing so, but authors used to adv3 might include one and it is as well for the adv3Lite library to handle it gracefully.
Bug fixed whereby isChild(obj, typ) and isDirectChild(obj, typ) ignored the value of the typ (containment type) parameter. (The Mercury parser uses these methods in a couple of places in contexts where the correction is unlikely to make much practical difference, but the fix has been made just in case, and also just in case game code wants to make direct use of these methods).
Bug fixed in the location method of MultiLoc which could have returned false results when a MultiLoc was located in something other than a top-level room. At the same time the logic of MultiLoc.location() has been overhauled to give more meaningful results in certain other cases.
Bug fixed whereby the parser might fail to recognize a response to a disambiguation request as referring to one of the options offered when one of the options is actually a SubComponent (e.g. because a command like LOOK IN BOX has been redirected to the remapIn object of the box, which doesn't have any vocab to match). The matchNameDisambig() method of SubComponent now calls the equivalent method on its lexicalParent to circumvent this problem.
Version 0.6 (2 March 2013)
Risk of incompatibility: The long form of remap (using remapTo() or maybeRemapTo() or a list defined on a remap property) has been withdrawn. This feature was deprecated from the first, and we said we might withdraw it all along. The same functionality is better implemented using a Doer (see below on the new Doer doInstead() method).
Note that the short form of remap (where remap simply evaluates to another object that replaces the current object in the same command) remains unaffected. The short form remap will remain a permanent part of the library.
Risk of incompatibility: The Doer method travel() has been withdrawn, as it is no longer needed. Use the new doInstead() method with the new Go action instead (see below), e.g. doInstead(Go, northDir), or, if you prefer, the new goInstead() macro, e.g. goInstead(north)
Risk of incompatibility: Some isXXXable properties have been renamed as canXXXMe properties where XXX contains a preposition and the isXXXable form looks too barbarous: e.g. isJumpOffable has been changed to canJumpOffMe.
Slight risk of incompatibility: The touchObj PreCondition has been reconfigured to make use of the new Query method reachProblem(a, b). This ensures that almost the entire logic of checking for reachability is handled by the Query object, rather than duplicated between the Query object and the touchObj PreCondition, so that if a Special wants to enforce different reachability rules these will be respected by touchObj without game authors needing to modify touchObj.
The reachProblem() method must return either an empty list (meaning that there's no difficulty with A reaching B) or a list of one or more ReachProblem objects. A ReachProblem object must define a verify() method and a check(allowImplicit) method (which can be called by touchObj.verifyPreCondition and touchObj.checkPreCondition respectively). The verify method must either do nothing, or else use the same macros (inaccessible, illogical, implausible, etc.) that are used elsewhere in verify routines. The check method should return true to allow the action to proceed or nil to fail it at the check stage; if it returns nil it should display a message explaining the problem. The check method may optionally also attempt to rectify the problem by carrying out an implicit action.
The reachProblem() method on QDefaults carries out the same checks that were formerly coded directly on touchObj, so game behaviour should not be altered in any way unless your game modifies touchObj.
QDefault.canReach(a, b) now returns true if Q.reachProblem(a, b) returns an empty list.
Slight risk of incompatibility: Previously an implicit SAY command (text interpreted as a SAY command during a conversation when the player's command did not explicitly start with SAY) would attempt to match an AskTopic or a TellTopic if it failed to match a SayTopic. This is probably needlessly complex, and may not be altogether intuitive to players. The handling of implicit SAY commands has thus been changed so that the game will only attempt to match SayTopics (including DefaultTopic types that include SayTopics).
Slight risk of incompatibility: The Action methods getDobj() and getIobj() have been removed. Since all they did was to return curDobj and curIobj respectively, they seemed an unnecessary piece of indirection. It is unlikely that game code would call these methods directly, but if it does, just use curDobj (or gDobj) and curIobj (or gIobj) instead.
Slight risk of incompatibility: A few message properties (particularly relating to scoring) have been moved off the libMessages object and replaced with DMsg/BMsg constructs. The intention is to complete this process in the next release.
Slight risk of incompatibility: A new isConnectorVisible property has been added to TravelConnector. This functions rather like isConnectorApparent did before, but allows isConnectorApparent to be defined as nil or true directly by game authors (instead of being derived from other properties, like isConnectorListed and the lighting conditions. The new set of relationships is now as follows: isConnectorApparent is true by default but can be overridden by game authors. isConnectorListed is (isConnectorApparent) by default but can be separately overridden by game authors. isConnectorVisible is a derived property dependent on the value of isConnectorApparent and the lighting conditions, and should not normally be overridden by game authors (though it obviously can be if special effects are desired). This change is intended to make it easier to make whether or not a connector is listed independent of whether or not it is available for attempted traversal.
Game code that doesn't override any of these properties shouldn't be affected, but if you've overridden isConnectorListed anywhere in your game code you may want to check whether it would be better to override isConnectorApparent instead (since previously the value of isConnectorListed determined the value of isConnectorApparent, but that's no longer the case).
Slight risk of incompatibility: The behaviour of GetOff and GetOutOf has now been decoupled. Previously a GetOff action was simply redirected to a GetOutOf action. The two actions now work very slightly differently, respecting the difference between something an actor is on and something an actor is in. This gives slightly better implicit action reports; it also allows these two (now separate) actions to make proper use of the remapIn and remapOn properties (as Board and Enter now do also) in cases where the object in question implements multiple containment. The TravelAction has also been modified to choose the appropriate action (GetOff or GetOutOf) when responding to an OUT commmand or using an implicit action to get the actor out of his or her immediate container before attempting travel.
Very slight risk of incompatibility: The action handling for a TI action now adds the direct object of a command to it actionList even if the action is dealt with on the indirect object. This is probably better behaviour that what was there before, and means that gActionListStr returns a useful value for report() methods (usually defined on the direct object) even when the action handling has taken place on the indirect object (as may sometimes be more appropriate).
Very slight risk of incompatibility: The action handling for PutIn, PutOn, PutUnder and PutBehind has been moved from the direct object to the indirect object of the action, since game code is more likely to want to customize the effects of the action there (for example, a Container is more likely to behave in a non-standard way to having things inserted in it than the things being inserted in it are).
Very slight risk of incompatibility: The action handling for a number of actions on Thing and one or two other classes has been tweaked to produce a more consistent scheme. Wherever possible, actions that need to be blocked are blocked at the verify stage rather than the check stage, and actions are reported on at the report stage rather than the action stage. This scheme was more or less followed before, but not quite as consistently as it might have been.
Note that there are still some exceptions where (in the first case) it still seems appropriate to perform some additional checks at the check stage and perhaps rule an action out there and (in the second case) where the main point of an action (e.g. EXAMINE, LOOK IN) is the output it produces, which is then best left at the action stage.
Very slight risk of incompatibility: The scoreObjects() method of Action now multiplies the verify score by 100 when calculating the overall score for each object in its matchList. This is to allow other scoreObject() methods along the way to tweak the scores of particular objects by small amounts to allow fine tuning of the parser's choice of object while giving priority to the verify results.
replaceAction() and nestedAction() are now functions, not macros, although they still do exactly the same thing. They are joined by two new functions replaceActorAction() and nestedActorAction(), which can be used when you wish to specify the actor. Game authors are, however, encouraged to use the new methods doInstead() and doNested() (see below) in place of replaceAction() and nestedAction() since these provide greater functionality and a more consistent interface.
Doer, Action, Thing and ActorTopicEntry all define two methods, doInstead() and doNested() which can be used to divert one action to another (in the first case) or to execute one action in the course of another (in the second case), e.g. doInstead(PutIn, redBall, greenBox) or doNested(Drop, gDobj). See the discussion on Doer for details.
Note that the existing Doer method redirect() still exists and works as before, but is now a service method used by doInstead(). Existing code that uses redirect() will still work, but game authors are encouraged to use doInstead() instead.
There is now a new Go action to make it easier to synthesize travel commands. This action is never triggered directly by a player command, but can be used in doInstead(), doNested, replaceAction(), replaceActorAction, nestedAction() and nestedActorAction() in the form doInstead(Go, northDir).
If you prefer, you can use the new macros goInstead() and goNested() instead. For example, goInstead(north) would be exactly equivalent to doInstead(Go, northDir).
A new macro gActionListObj has been added for use in report() methods. It evaluates to an object that can be used in situations where we want gActionListStr to be the subject of a sentence (so that any verbs need to agree with it in number depending on whether gReportList represents one or more objects). Consult the section on the Report phase of Actions Results for further details.
Two new verification macros have been added: dangerous and nonObvious. Both of these allow the action to go ahead unless it's an implicit action, but nonObvious is given the same logical rank as illogical. For further details see the Verify section of the Action Results article.
To allow these two new verification results to work, parts of the verification and implicit action handling have had to be tweaked along with the checkPreCondition methods of most PreConditions. As things stood before it was possible to create a VerifyResult with allowImplicit = nil, but nothing took any notice of this value.
Two new macros have been added to assist with verification: gTentativeDobj and gTentativeIobj. These contain the lists of objects that the current Command is considering as possible direct and indirect objects. These can be used in the verify routines of TIActions on the first object to be resolved when it would be helpful to know what the other object might turn out to be before it has been fully resolved. Note that unlike the similarly named macros in adv3, these ones do actually results in lists of actual objects, not npMatches or the like.
A new function askMissingObject(action, role) has been added, which may be called via the new macros askForDobj(action) and askForIobj(action). This function (or the macros that translate to it) causes the player to be prompted to supply the missing object for action (unless it can find the object for itself, see below), and the input is then parsed in the normal way, as if the query had arisen from the parser; meaning that if the player supplies a valid object action will be executed with that object.
The askMissingObject() function first attempts to find the missing object before prompting the player to supply one. It does so by finding the highest scoring object in scope for the requested role in the requested action. It uses this object if and only if (a) no other object it finds has so high a score and (b) if the action were tried with the object found it would pass the verify stage and would be allowed as an implicitAction (so we don't pick an object with a dangerous or nonObvious verify result, for example). If these conditions are met the requested action is executed with the best match object in the request role without the player being prompted to supply an object.
The behaviour of the Lock and Unlock actions (LOCK DOOR or UNLOCK DOOR without specifying a key) has been altered slightly to take advantage of askForDobj(). Now if the player attempts to lock or unlock something without specifying a key and the player character isn't holding an appropriate key the player is asked to specify a key; previous s/he was told the player character wasn't holding an appropriate key. This seems better behaviour in general, but also in particular when a puzzle requires using something unobvious to unlock (or lock) something with.
The behaviour of several other actions have also been tweaked to take advantage of askMissingObject(), namely Sit, Lie (as in Lie down), Write, Type, and Look up (as in Consult).
A number of new actions have now been implemented (more or less completing the set envisaged in the Mercury version of grammar.t apart from some system actions that are being left out on purpose as probably not needed). The new actions include Lie (as in lie down, not as in tell an untruth), PlugIn, PlugInto, Unplug and UnplugFrom, together with the rest of the PushTravel actions: PushTravelThrough, PushTravelEnter, PushTravelGetOutOf, PushTravelClimbUp and PushTravelClimbDown.
In order to facilitate the implementation of the Plug set of actions a new PlugAttachable mix-in class has been added. For details see the appropriate part of the Attachables section.
In order to facilitate the implementation of the PlugAttachable class there has been some tweaking of the SimpleAttachable and NearbyAttachable classes, including some changes to the NearbyAttachable class that now make it usable (it was fundamentally broken before).
Two new macros asDobjWithoutVerifyFor() and asIobjWithoutVerifyFor() have been added, which do what they say, namely make one set of action handling routines behave like those of another on the same object, apart from the verify stage.
The main purpose of these new macros is to facilitate a slight tweak in the way the SitOn, StandOn and LieOn actions are implemented. Previously these were treated as synonyms of Board. They still are, except at the verify stage, so that game authors have more control over which items actors can apparently sit, stand or lie on (although there is no difference in the end result). For details see the new paragraph on Pseudo-Postural Properties in the section on Thing.
Four methods have been added to the LMentionable class in the English-specific library to facilitate the manipulation of the vocabulary that can be used to refer to objects (and optionally the name as well): replaceVocab(voc), addVocab(voc), removeVocabWord(word, matchFlags?) and addVocabWord(word, matchFlags). For details see the paragraph on Manipulating vocab at run-time in the section on Thing.
It's now possible to specify a matchPhrase (and, if desired, a separate disambigMatchPhrase) that the player's input must match in order to refer to a particular object. For example, if an object with vocab 'dark green bottle; glass' is given a matchPhrase of 'dark green', then it will match DARK GREEN BOTTLE but not just GREEN BOTTLE. For the full story see the paragraph on Phrase Matching in the section on Thing.
Sections of the vocab property can now be selectively inherited from superclasses. For details, see the explanation of the vocab property in the Thing section of the manual.
The new Thing property vocabLikelihood can be used to make the parser prefer one object over another, other things (notably verify results) being equal. It is recommended that the value given to this property (if it is used at all) be relatively small, say in the range 0 to 10, to ensure that verify results take precedence.
There is now a SecretDoor class. A SecretDoor is a kind of Door that only acts as a Door when it's open. For details see the Extras section.
Two new classes have been added to the conversation system: TopicGroup and ConvNode These don't enable game authors to do anything that couldn't be done before, but they may make it more convenient, especially when definining Conversation Nodes.
Four new types of DefaultTopic have been added to the conversation system: DefaultSayTellTopic, DefaultTalkTellTopic, DefaultSayTellTalkTopic and DefaultAskQueryTopic, since these seem natural groupings for DefaultTopics responding to attempts to impart information or ask questions respectively.
The query type and topic vocab of a QueryTopic may now be given together in a single single-quoted string (in the QueryTopic template), e.g. 'where he was born' as an alternative to 'where' 'he was born'.
The behaviour of ActorTopicEntry.curiositySatisfied has been changed so that if an ActorTopicEntry defines a non-nil keyTopics property, its curiositySatisfied becomes true if and only if showing a list of the topics it keys would show an empty list (that is, it in effect has no subtopics to suggest). This ensures that ActorTopicEntries whose function is to suggest subtopics are suggested for as long as they have subtopics to suggest.
The new gameMain option againRepeatsParse controls how the AGAIN command is interpreted. If it is nil AGAIN repeats the resolved command, that is, the command as it was interpreted on the previous turn, with the same objects. If it is true (the default), then the text of the previous command is reparsed, which may result in a different interpretation involving different objects. For example, suppose there are two coins on the floor. If againRepeatsParse is nil then TAKE COIN followed by AGAIN will result in one of the coins beingtaken, followed by an attempt to take the same coin again (which will fail with a message that you're already holding the coin. If againRepeatsParse is true, however, than TAKE COIN followed by AGAIN will result in one coin being taken, and then the other, just as if the player had typed TAKE COIN twice. Which is the better behaviour depends on context; while in the coin example the second interpretation seems better, if a player were to type EXAMINE BOOK and be prompted to say which one, the second interpretation would result in the disambiguation prompt being repeated, which might seem perverse.
There is thus an additional gameMain option autoSwitchAgain which tries to give the player the best of both worlds by switching againRepeatsParse between true and nil depending on whether the command to be repeated is the kind of command it would make sense to repeat with the same objects (if it isn't, the command is reparsed in the hope of finding a more sensible match). This is far from absolutely foolproof, and should be regarded as experimental. It is true (switched on) by default, but game authors may wish to set it to nil if it proves troublesome.
The new Thing method fluidName makes it easier to produce satisfactory messages relating to objects doing duty both as fluid containers and the fluid they contain (e.g. an oilcan notionally containing oil). Library messages referring to drinking and pouring now use the new fluidName property to refer to the direct object of such actions rather than the theName property (although fluidName is set to theName by default).
There is now an additional debugging command, DEBUG DOER, which shows which doer (identified by its cmd string) is being executed.
The behaviour of the FOLLOW command with an actor as its target has now been enhanced. If the command FOLLOW X is issued and X is not in sight, but the player character is in the location from where s/he last saw X depart, the FOLLOW X command will cause the player character to take the same exit that the player character saw X leave by (i.e. the player character will follow X's last known move). Otherwise, if FOLLOW X is issued when the player character is in the same room as X, then the player character will follow X if X subsequently moves on the same turn.
The new function senseSay(val, obj, prop=&canSee) can be used to output text only when obj is visible to the player character. This may be particularly useful when reporting the movements and other actions of NPCs who may or may not be visible to the player character.
The new AgendaItem method report(msg) simply calls senseSay(msg, getActor), thereby saving a bit of typing in this commonly useful case. If required report() can pass a property pointer as a second optional parameter (e.g. &canHear) to use a different sense from sight.
The draft Tutorial has now been completed.
Work has begun on an Action Reference. This is currently still work in progress, but once it is complete it will list all the actions defined in the library referenced by an alphabetical list of the commands used to invoke those actions. Eventually it will also contain summary information about key properties relating to each action and links to further information.
Bug fixed whereby the command GO TO X could cause a run-time error when X was last seen in the current location but was no longer there.
Bug fixed whereby using an implicit ASK FOR, SHOW or GIVE command (e.g. ASK FOR HELP or SHOW TICKET, without specifiying the addressee) could cause a run-time error: the problem was that no implicit ask for, give to or show to actions had been defined; this has now been remedied.
Bug fixed in conversation method Actor.showSuggestions(explicit, tag), where the tag parameter wasn't handled property (leading to bugs and possible run-time errors in handling a TOPICS command).
Bug fixed whereby an implicit TOPICS command (e.g. from TALK TO SO-AND-SO) didn't respect the value of the suggestionKey property.
Bug fixed whereby a word ending "'s" (apostrophe-S) in the vocab of a Topic would never be matched, because the tokenizer separates the apostrophe-S into a separate token, while the initVocab() routine suppresses it altogether. TopicPhrase now strips any apostrophe-S out of the player's input for the purposes of matching it to a topic so that it doesn't cause a mismatch.
Bug fixed whereby trying to UNDOing a SAY command entered without an explicit SAY would undo a previous command instead (since the implicit form of SAY didn't set a savepoint).
Bug fixed whereby an AskTopic or TellTopic might be preferred to a SayTopic with the implicit form of the SAY command where the vocabulary overlapped, because only the strongest vocab match was being obtained (which is not necessarily the appropriate behaviour for Topic matches).
Bug fixed whereby TopicEntries corresponding to the actors activeKeys list weren't prioritized when the Actor's current ActorState was non-nil.
Bug fixed whereby certain forms of Give and Show had the wrong PreConditions. Now GIVE (or GIVE TO) always has an objHeld PreCondition on its direct object, while SHOW and SHOW TO enforce objHeld on portable objects and objVisible on fixed ones.
Bug fixed whereby finishOptionScore and finishOptionFullScore weren't causing a display of the final score, but finishOptionScore was generating a spurious additional comma in the list of post-game options.
Bug fixed whereby the TAKE FROM command might result in an object being taken even if it was fixed in place.
Bug fixed whereby the TAKE FROM command might result in an object being taken even if the actor didn't have room to hold it. The dobj handling of TakeFrom now used the asDobjWithoutVerify() macro to copy all its direct object handling apart from the verify stage from Take, while retaining its own verify handling.
Various bugs fixed that could occur when the player character was inside a SubComponent, especially when the SubComponent was closed (thereby preventing the player from referring to the enclosing lexicalParent).
Bug fixed whereby the default "You see nothing special..." description was not always shown for objects that lacked a description, so that examining such objects might result in there being no output at all.
Version 0.5 (16 January 2013)
Several changes have been made to the MultiLoc class, partly to fix a bug, and partly to enhance its flexibility.
The problem was that the locationList property was being used for slightly conflicting purposes: both as way to set the initial list of locations in which the MultiLoc should start out and to keep track of the list of locations in which the MultiLoc currently resides. The conflict arose from the fact that it made sense to allow Regions in the list for the first purpose, but not for the second, one slightly obscure consequence of which being that the isDirectlyIn(loc) and isIn(loc) methods behaved unreliably when loc was nil.
MultiLoc now defines a separate initialLocationList property for specifying the initial list of locations in which a MultiLoc starts out (which can include Regions), and reserves the locationList property for keeping track of the MultiLoc's current list of locations (rooms and/or objects within rooms, but not Regions; i.e. any Regions specified in the initialLocationList are expanded into their constituent rooms in locationList). However, to maintain backward compatibility and ease of use it is still legal to define an initial list of locations (including Regions) on the locationList property. If the library finds that initialLocationList is empty when it initializes a MultiLoc, it will simply copy the locationList to the initialLocationList before proceeding.
MultiLoc now also defines an initialLocationClass property and an isInitiallyIn(obj) method, which are intended to work together. If initialLocationClass is not nil then every instance of that class will be added to the MultiLoc's locationList provided isInitiallyIn(obj) returns true for that instance (where obj is the instance in question). This introduces an existing adv3 feature into adv3Lite; the main reason for doing so at this stage is to facilitate the implementation of the new Floor class (see below).
Note that any locations added to the location list via initialLocationClass will be in addition to those defined on initialLocationList, and that any locations defined in the exceptions list will be removed from the location list after those defined in both initialLocationList and initialLocationClass have been added.
The addToContents() method of Thing and Region now has a second, optional, parameter vec. This is intended purely for internal use by the library to facilitate initiating the locationList of a MultiLoc from its initialLocationList and initialLocationClass, and shouldn't directly impact on user code.
The library now defines a Floor class, and one instance of it, defaultGround. This is basically a MultiLoc, Decoration that is added into every Room. Its main purpose is to facilitate the parser's ability to disambiguate items by their locations. Formely, if, say, there were two identical coins, one on a table and one directly in the room, the parser would have to ask "Which do you mean, the coin on the table or the coin?", which is unclear and fails to give the player an easy way of selecting the latter. Now the parser can ask "Which do you mean, the coin on the table or the coin on the ground?" and the player can refer to "the coin on the ground" to disambiguate.
The defaultGround object now present in every room does incidentally perform the secondary purpose of allowing players to refer to 'the ground' or 'the floor' which must be implicitly present in nearly every room, but its implementation is deliberately minimalistic to discouraage players from trying to interact with it. The library will translate PUT SOMETHING ON FLOOR or THROW SOMETHING AT FLOOR to DROP SOMETHING, and X GROUND/FLOOR will of course work, as will TAKE X FROM FLOOR, and, in a limited fashion, STAND ON FLOOR or GET ON FLOOR, but that's about it (everything else gets the standard decoration response 'The ground is not important'). STAND ON FLOOR or GET ON FLOOR will either report "You are standing on the floor" (if the player char is in the outermost room) or else be translated into a GetOut action.
If you want to define a custom Floor object for a particular location, or omit it altogether (e.g. for a room at the top of a tree), you can do so by overring the floorObj property, either to point to your custom Floor object, or to nil (in the case of a room without a floor). You should do this even if you implement your custom floor object as a Fixture in a single location rather than using the custom Floor class, but you might find it better to use the Floor class even for a custom floor that appears only in one room, since it's designed to facilitate the parser disambiguation just described. If you do decide to define your own Fixture, you'll need to copy most of the methods and properties of the Floor class onto it to make it work properly as a floor.
The gameMain option storeWholeObjectTable has been removed (and attempting to set it will no longer have any effect). Tests showed that the resources saved by setting this value to nil were negligible. The alternative to storing the whole object table (for use with tags in the conversation system) was always complex and unreliable, and it seemed best just to get rid of it.
There are now options to precede the failure messages at produced by check and verify routines with the name of the object they refer to in commands applying to multiple direct objects (e.g. TAKE ALL), in case it isn't clear which objects the messages apply to. These options are controlled by the properties announceMultiVerify and announceMultiCheck, which can be overridden globally on TAction, or else on individual actions. By default announceMultiVerify is nil (most library verify messages make it clear what they refer to) and announceMultiCheck is true.
Multiple identical verify reports are now suppressed (i.e. only the first is shown). This most commonly pertains when an action applying to multiple direct objects fails the verify test on the indirect object, so that, for example, a command like PUT ALL ON WALLPAPER where the wallpaper is a Decoration would result in multiple displays of "The wallpaper is not important"; clearly the player only needs to see this message once. Note that this repetition suppression only takes place if announceMultiVerify is nil.
There is now a DEBUG command that breaks into the debugger, just as it does in adv3. There are also DEBUG ACTIONS, DEBUG MESSAGES and DEBUG SPELLING options. For details see the section in the manual on Debugging Commands.
Thing now has two properties controlling whether you can pour something onto or into the Thing. canPourIntoMe and canPourOntoMe control whether it's possible; by default canPourIntoMe is true if ContType is In and nil otherwise, and canPourOntoMe is true. The properties allowPourIntoMe and allowPourOntoMe control whether you actually want to allow pouring into or onto this object; both are nil by default. This ensures that a game will give a reasonably sensible response where the canPour property of some object has been set to true and there's no other specific handling on objects that might be poured into or onto.
The {I} and {me} message parameter substitutions now use the theName and theObjName properties of the actor rather than the name and objName properties; this generally reads more naturally.
Bug fixed that caused a run-time error in the GoOut action (the action triggered by EXIT or LEAVE), and in the GoIn action (triggered by ENTER without an object).
Bug fixed that caused a run-time when the player attempted to issue an order to an NPC (or even the PC) with the "bob, whatever" syntax.
Bug fixed that caused things with visibleInDark = true not to be visible in the dark.
Bug fixed that could wrongly suppress action reports at the report() stage when Doer.redirect() was used.
Bug fixed that placed the player character's immediate container out of reach of the player character.
Bug fixed whereby the actionPhrase() method used to reconstruct the text of a command in a CommandTopic or DefaultCommandTopic failed to use the correct pronouns when one of the objects of the command was either the player character or the actor at whom the command was targeted. These are now rendered as 'me' or 'yourself' respectively, since the text output by actionPhrase() is intended to be used in the representation of the direct speech of the player character to the target actor.
Bug fixed whereby a Doer redirect aimed at a specific object would apply to all successive objects on the same command (for example if a Doer redirected TAKE BLUE BALL to the Examine action, TAKE ALL would result in everything processed after the blue ball in the same command being examined as well).
Bug fixed whereby detaching an object from another object left it located in the other object (and thus seemingly still attached); the detached object was being move to its own location (which left it where it was) instead of the location of the object it had just been detached from.
Bug fixed whereby opening a container would report "Opening the X reveals Y" followed by an unnecessary "You open the X" (due to inappropriate recursive sublisting).
Bug fixed whereby trying to drop a fixture would result in the odd message "The whatever is part of you" instead of "You aren't holding the whatever".
Bug fixed whereby the message reporting that a particular key wouldn't work on a particular objecty caused a run-time error.
Bug fixed whereby the antecedent of a pronoun could become a SubComponent rather than the object of which it is a part. For example the sequence OPEN SUITCASE. TAKE IT. Might mysteriously generate the response "The suitcase is fixed in place" because IT now referred to the SubComponent representing the suitcase's interior rather than the suitcase itself.
Version 0.4 (12 January 2013)
Risk of incompatibility: The properties allowPutIn, allowPutUnder and allowPutBehind have been renamed canPutInMe, canPutUnderMe and canPutBehindMe to make these names more consistent with the naming scheme used elsewhere in the library. By default these properties are true if the contType is of the appropriate type (In, Under or Behind respectively). If one of these properties is overridden to true and the contType is not of the appropriate type, any item put in, under or behind the object in question will be stored in its hiddenIn, hiddenUnder or hiddenBehind property and moved into nil. Note that there is no canPutOnMe property, since the hiddenOn property that would then be needed wouldn't make much sense, and it wouldn't make any sense to allow game authors to override the rule that items can be put on an object if and only if its contType is On.
Risk of incompatibility: The Thing property transparent has been renamed isTransparent to bring its name into line with similar properties of Thing.
Risk of incompatibility: The default value of the specialDescBeforeContents property of Thing has been hanged from true to (location && location.ofKind(Room)). In other words the default is true for an object directly in a room and nil otherwise. This gives more satisfactory results for specialDescs shown as part of the listing of the contents of some other item, where the contents lister for that item may already have introduced the fact that its contents are about to be shown.
Correspondingly, the specialDescs of items contained in other objects are now listed (as well as the listing of any other items). Previously this was not the case, which was arguably a bug.
Risk of incompatibility: The handling of KISS and ATTACK on the Actor class has changed. The default behaviour is now to display the actor's shouldNotKissMsg or shouldNotAttackMsg (at the check stage). If you want to use KissTopics and HitTopics (or you want to define your own handling at the action stage), set allowKiss and/or allowAttack to true.
The reason for this change is that defining a shouldNotKissMsg and/or shouldNotAttackMsg is more straightfoward than having to define a complete KissTopic or HitTopic for the great majority of actors who do not need this kind of fine tuning.
Minor risk of incompatibility: The Thing properties openingContainerMsg has been withdrawn, since its function is now performed by openingContentsLister. The okayOpenMsg property is now employed at the report() stage of dobjFor(Open) and is intended primarily for doors.
An optional parameter, paraBrk, has been added to the show() method of Lister. The default value of this parameter is true, but if it is passed as nil the paragraph break at the end of the list is suppressed. This change has been introduced mainly to facilitate several of the listing changes that follow, and may not have much effect on game code.
The Thing method listSubcontentsOf() now takes a second parameter, namely the lister to be used for the listing of any miscellaneous items. The default is examineLister (which is now a property of Thing). Since this method is mainly used internally in the library this change may have little direct on game code, but in principle the method is also available to be called from game code.
The inventory lister now splits worn items and carried items into two different lists (e.g. "You are wearing an old coat and a silly hat, and you are carrying a walking stick and a pencil.") If you prefer the single listing style, override Inventory.splitListing to nil.
The depth of listing contents of contents in inventory listings can now be controlled by the value of subLister.maxNestingDepth. The default is 1, which gives results like "You are carrying a glass box (in which is a red box)". A value of 2, for example, would give "You are carrying a glass box (in which is a red box (in which is a battery))."
Miscellaneous items in room listings and items that are examined and have visible contents may now list their contents in parentheses immediately after their name to the depth defined in subLister.maxNestingDepth. To enable this style of listing set gameMain.useParentheticalListing to true. To change the behaviour of individual listers (examineLister, openableContentsLister and RoomContentsLister) override their showSubListing property to true or nil (rather than having them pick it up from gameMain.useParentheticalListing).
Paragraph breaks between the sentences listing the contents of items in a room description can be suppressed by setting paraBrksBtwnSubcontents to nil, either on a room-by-room basis or globally on gameMain. For further details on this and the previous change consult the section on Room Descriptions.
The room contents listing has been tweaked so that if the actor looking around is not directly in a room, the actor's immediate location is mentioned first (e.g. "You are in a big wooden box") followed by a listing of the location's contents.
The listing mechanism has been thoroughly overhauled to make fuller use of Lister objects. A new subclass of Lister, ItemLister, is now used as the base class for several kinds of lister used in room, examine and search listings. The ItemLister class defines a contentsListedProp, the default value of which is &contentsListed; this is the property defined on the object whose contents are to be listed that determines whether that object wishes to allow its contents to be listed.
As a result of these changes the library should now respect the values of the Thing properties lookListed, examineListed, searchListed, contentsListedInLook, contentsListedInExamine and contentsListedInSearch. The first three of these determine whether an item is listed as part of the miscellaneous contents of its parent in response to a LOOK command, or when its parent is EXAMINED, or when its parent is searched (with SEARCH or LOOK IN/UNDER/BEHIND) respectively. The second three determine whether the contents of the item on which it is defined are listed in response to a LOOK, EXAMINE or SEARCH command. By default examineListed, lookListed and searchListed all take their value from the isListed property. The contentsListedInLook and contentsListedInExamine properties both take their default values from the contentsListed property (which is true by default). The default value of contentsListedInSearch, however, is simply true, since it's hard to think of many cases where you wouldn't want an object to reveal its contents when explicitly searched; the property is nevertheless provided for completeness.
The new Thing property examineLister defines the lister to be used to list an object's contents when it is examined. The default value is descContentsLister.
Perhaps somewhat experimentally, the various listers now attempt two consolidate multiple identical items in a list into a single enumerated occurrence, so that, for example, instead of "You are carrying a gold coin, a gold coin and a gold coin" the game will output "You are carrying three gold coins." I have marked this as experimental in case there are instances where it does not work appropriately.
A new function, makeMentioned(obj), has been added that simply makes obj.mentioned true. The obj parameter can also be a list of Things, in which case each item in the list will be marked as mentioned. With a embedded expression the same function can be written as << exclude obj >>. The purpose of the function is to allow game authors to exclude certain items from room (and other listings), perhaps because they've already mentioned them under another name or description.
Two new Thing properties allowReachOut(obj) and autoGetOutToReach have been added to allow game authors to control what happens when an actor tries to reach one object from within another (e.g. while the actor is on a bed or chair and tries to reach something elsewhere in the room). These properties should be defined on the object the actor is in. If allowReachOut(obj) returns true for the obj the actor is trying to reach (the default), then reaching is allowed. Otherwise, if autoGetOutToReach is true (the default) the actor will try to get out of his/her immediate container to reach the object. Otherwise (if autoGetOutToReach is nil) reaching is prohibited and a message is displayed saying that the actor can't reach the target object from his/her present location.
The new Thing method checkReachIn(actor) can be used to put the contents of an object out of reach of an actor outside the object (for reasons other than enclosure), e.g. if the object is meant to be out of reach. The default behaviour is to put the contents of an object out of reach if its own checkReach(actor) method puts it out of reach; checkReachIn(actor) simply calls checkReach(actor). The contents of the object are considered out of reach if its checkReachIn() method dislays anything at all.
Thing now defines three new properties, maxBulkHiddenIn, maxBulkHiddenUnder and maxBulkHiddenBehind that limit the amount that can be but in, under or behind an object that ends up in hiddenIn, hiddenUnder or hiddenBehind list. The corresponding methods getBulkHiddenIn, getBulkHiddenUnder and getBulkHiddenBehind return the total bulk of the items currently contained in the corresponding lists.
It's now legal to use the name of the lexicalParent instead of its remapIn property when defining the objects a Key locks and unlocks in the plausibleKeyList and actualKeyList properties of a Key. For example, in the following definition the silver key will work as presumably intended:
cabinet: Fixture 'cabinet' remapIn: SubComponent { lockability = lockableWithKey isLocked = true isOpenable = true } remapOn: SubComponent {} ; silverKey: Key 'silver key' plausibleLockList = [cabinet] actualLockList = [cabinet] ;
QDefaults.canReach(a, b) has been amended to take account of the checkReach() and checkReachIn() methods of the objects along the containment path from a to b.
Room and Region both now define two new methods: travelerLeaving(traveler, dest) and travelerEntering(traveler, dest). These are both invoked just before travel actually takes place, the first on the room or region that's about to be left, and the second on the room or region that's about to be entered. The traveler parameter is the actor doing the traveling, while dest is the room that's about to be entered. These methods are only called on regions when the starting room and destination rooms are in one or more regions that are not common to them both.
The checkRoomToHold() method (used by the TAKE action to enforce inventory limits) now uses the new method getBulkCarried() instead of getBulkWithin() as before; getBulkCarried() excludes items that are being worn from the total, since these presumably do not contribute to the total bulk carried in an actor's hands. The Doff action therefore now also enforces checkRoomToHold() in its check() method.
The default value of disambigOrder (a property of Mentionable) has been changed to (listOrder), and that of disambigGroup has been changed from nil to 0 (zero). This means that the default behaviour of the library will be to list items in disambiguation prompts in the order of their listOrder property, which is probably what's most frequently required when a listOrder has been specified.
The attempt to implicitly open a closed door before travelling through it has been moved from the travelVia() method to the execTravel() method of the Door class. This means that the before travel notifications are carried out before any attempt is made to open the door, which gives better results when travel via the door is prohibited (by an NPC, for example).
The function makeListStr(lst) now sorts the objects in lst in ascending order of their listOrder property before constructing the string version of the list.
The handling of the PURLOIN debugging verb has been changed so that it's no longer possible to purloin objects that are fixed in place. Purloining a fixed object causes it to become a component of the player character (which probably isn't what's intended) and risks playing havoc with the world model, so it seems better to rule it out. If authors/testers really need to move fixed objects around this can be done with EVAL obj.moveInto(wherever).
The grammar for the EXAMINE verb has been extended so that it will look accept LOOK X or L X as well as LOOK AT X or L AT X (plus the other various valid forms).
The Lever class now as an isPushed property as well as an isPulled property. By default isPushed = !isPulled, but the existence of the separate isPushed property makes it easier to decouple the two if you want a lever that can also be in a position between the two extremes (when both isPushed and isPulled would be nil). The verify routine for dobjFor(Push) on the Lever thus now tests for isPushed rather than !isPulled.
GameMainDef.newGame() now sets gAction to a new Look action (the action effectively about to be performed just before the first turn) and gActor to the player character. This makes it more likely that any user startup code that assumes the existence of an action context, such as using gMessageParams() in gameMain.showIntro() or within the initial room description, will work as expected rather than causing a run-time error.
The message parameter substitutions {a obj}, {an obj}, {a subj obj} and {an subj obj} have been added; these work just like {the obj} and {the subj obj} but use the indefinite article instead of the definite article (or rather the aName property of obj rather than the theName property).
Parser.defaultActions is now nil by default. This means that the parser no longer tries to treat commands it doesn't understand as possible noun phrases referring to the direct object of an EXAMINE command (or a GO TO command for rooms). The behaviour during conversations is not affected; any command the parser can't make sense of during a conversation is still taken as a SAY command. The former behaviour (i.e. with FOO treated as EXAMINE FOO) was causing inconsistent behaviour (sometimes reporting 'You see no foo here' and sometimes reporting 'I don't understand that command' with no apparent rhyme or reason). Since it is not normal IF parser behaviour (to treat a command consisting purely as a noun phrase as the target of an unstated EXAMINE or other default command), it seems reasonable to turn this behaviour off by default. Game authors who want this behaviour can restore it by setting Parser.defaultActions to true (or could provide a custom command to allow players to turn it on and off).
The StairwayUp, StairwayDown and Passage classes have been amended to respect the values ot the isClimbable, isClimbDownable and isGoThroughable properties respectively (these properties now being true by default for each of these classes in turn). Previously these classes overrid the verify() methods supplied by Thing so that these properties were effectively ignored, which made the behaviour of these classes inconsistent with what users might reasonably expect.
Bug fixed in which a dropped object was moved into the actor's outermost room instead of the immediate location. The new Thing property dropLocation now defines where an object dropped in a location should land. By default dropLocation is simply self.
Bug fixed which could cause a run-time error when the player supplied the missing noun of a command in response to a parser query.
The bug that prevented a Doer from always matching a command specification involving specific problems has re-emerged, and has once again been fixed.
Bug fixed in which the HTML entities ” and “ used to replace double-quote marks in textual outpit lacked the terminating semilcolon.
Bug fixed whereby the parser would ask a pointless disambiguation question in response to a command involving one of a number of identical objects; e.g. TAKE COIN would result in the message, "Which to do mean, a coin?".
Bug fixed whereby commands involving a specified number of objects would sometimes result in the parser making perverse choices; for example, if there were two coins on the floor and a third being carried by the player, TAKE TWO COINS might be interpreted to mean taking one of the coins on the floor plus the one the player character already holds, instead of the two on the floor as the player presumably intended.
Bug fixed whereby commands involving a specified number of objects would result in the wrong error message if more objects were specified than were available; for example TAKE FOUR COINS might result in "You see no four coins here" instead of "There aren't that many available."
Various bugs fixed concerning the resolution of the pronouns 'you' and 'your', including the bug that caused a crash when 'your' was used in a command and the failure of the parser to recognize that 'you' and 'your' referred to the player character in contexts where this would be the player's clear intention.
Various bugs fixed concerning inappropriate or run-time-error-causing error-messages when a command referred to something by its owner (e.g. X BOB'S COIN when Bob doesn't have a coin).
Version 0.3 (18 December 2012)
Risk of incompatibility: The Thing property nothingThroughMsg has been renamed lookThroughMsg, which better reflects its function. The default text of this message remains unchanged.
Similarly nothingInMsg, nothingUnderMsg and nothingBehindMsg have been renamed lookInMsg, lookUnderMsg and lookBehindMsg.
Risk of incompatibility: The Thing properties autoTakeOnLookUnder and autoTakeOnLookBehind have been abolished, and the behaviour of LOOK BEHIND and LOOK UNDER slightly changed. Two new properties and three new methods have been introduced instead. Tne new autoTakeOnFindHidden property determines whether an object may be automatically taken when it's moved from a hiddenXXXX list. The default value of autoTakeOnFindHidden is (isFixed), the idea being that if we look in, under, or behind something fixed (like a pile of junk or a piece of furniture) and there's nowhere else for the objects discovered to go, we'll probably take them, but that if we look under or behind something portable, like a rug or a blanket, we probably move the rug or blanket a little to do so and leave the item discovered where it notionally was all along (in the same location as the portable item we've just looked under/behind). The new property findHiddenDest determines where an object is moved to from a hiddenXXXX list (when there's no obvious container for it); by default if autoTakeOnFindHidden is true, then findHiddenDest is gActor (the actor who will take the items discovered), otherwise it's the location of the object that's just been looked in/under/behind. These properties are actually used in the three new methods findHiddenIn(), findHiddenUnder(), and findHiddenBehind().
The sequence of events with LOOK UNDER X is now as follows:
- If X has a contType of Under then this is the target object we'll work with.
- Otherwise, if it has an associated remapUnder object, we'll work with that.
- If the target object has a contType of Under then move everything from the hiddenUnder list to the target object and then list the contents of the target object as being underneath it (or say there's nothing under it if there's nothing there).
- Otherwise, if there's anything in the hiddenUnder list, call findHiddenUnder().
- Otherwise, say there's nothing there.
The findHiddenUnder() method then moves everything from the hiddenUnder list to findHiddenDest and displays an appropriate message.
LOOK IN X and LOOK BEHIND X work in much the same way (except with hiddenIn and hiddenBehind respectively and contTypes of In and Behind respectively).
This may all seem a bit complicated, but it should provide reasonable default behaviour most of the time, while being relatively easy to customize for exceptional cases.
A hiddenIn property has been added to Thing. It can be used in much the same way as hiddenUnder or hiddenBehind now do. It can be used either for objects in a container that won't be noticed until the container is explicitly searched or for objects hidden in things like piles of junk or haystacks that aren't containers in the normal sense.
The action handling for ENTER has been decoupled from that for BOARD (along with the vocabulary used to trigger these actions). ENTER now handles getting inside something that has a contType of In. BOARD handles getting on something that has a contType of On. The new isEnterable flag determines whether an actor can get inside something (the contType must also be In). Note that this does not effect the Enterable class (which is used for things like buildings which can be entered by traveling to a new room representing their interior), but that the Booth class is now defined with isEnterable = true rather than isBoardable = true.
A number of methods (such as lookAroundWithin() and methods it calls) have been moved from Room to Thing. This is to allow a Thing (particularly a closed Booth) to describe its interior properly when the player character is contained within it. Since Room inherits from Thing, this should not affect any existing code.
In several places getOutermostRoom (in particular gPlayerChar.getOutermostRoom) has been replaced with outermostVisibleParent() (e.g. in the implementation of the LOOK command, and in other places where a look around is performed) to ensure that the right description is presented when looking around from within a closed container (such as a booth).
Thing.statusName(actor) has been amended to give sensible results when looking around from within a closed container.
A new interiorDesc property has been added to Thing. This is used as the room description when looking around from inside a closed container.
The touchObj precondition and the QDefaults.canReach() method have been changed so that if the object that one is trying to reach is the object that's blocking the reach path, it's now considered touchable. This is to allow, for example, an actor to open a closed container from the inside (previously you would have got a message like "You can't reach the large wooden box through the large wooden box.")
The default value of Thing.isOpen has been changed from nil to (!isOpenable). This makes the definition of a simple container (by adding contType = In) just a little easier and more intuitive, and so is probably the better default case. Note that this doesn't effect the Container class (which already defines isOpen = true) or the OpenableContainer class (which defines isOpen = nil). The isOpen property of Door is now explicitly nil by default to ensure that doors normally start out closed.
The handling of the INVENTORY command has been changed to make use of inventoryLister. inventoryLister has been changed to optionally allow the display of additional information (such as 'providing light') after the names of items in an inventory list, and to optionally display the contents of items in an inventory list (e.g. 'You are carrying a big bag (in which is a blue ball). '). To facilitate the latter a new subLister has been created and a new buildList() method added to the Lister class. The buildList(lst) method returns a single-quoted string containing what show(list, 0) would have displayed, minus the terminating paragraph break.
Two new properties isProminentSmell and isProminentNoise have been added to Thing, both true by default. The smellDesc and listenDesc properties of an object are only displayed in response to an intransitive SMELL or LISTEN command respectively if these properties are true. These properties have no effect on the transitive SMELL SOMETHING and LISTEN TO SOMETHING commands. This allows game authors to exclude items being listed in response to an intransitve LISTEN or SMELL while still making them respond to being explicitly listened to or smelled.
A number of redundant methods (that aren't actually used anywhere) have been removed, such as Thing.lookAround(pov). These are generally methods that were defined in Mercury or adv3 but which are not needed in adv3Lite, either because they have no function in adv3Lite at all (such as some of the methods and properties relating to senseCache on libGlobal) or because adv3Lite defines its own version to perform the appropriate function (e.g. lookAround(pov) is not needed because adv3Lite defines lookAroundWithin()).
The Actor class now defines contType = Carrier by default (as it should have done all along).
The Thing class now has a new display(prop) method, where prop is a property pointer. If prop contains a double-quoted string or a method, the display() method simply calls self.(prop). If prop contains a single-quoted string or integer, display calls say(self.(prop)). This simplifies the creation of code that will display a text property correctly whether it has been defines as a single-quoted string, a double-quoted string and a method, and several routines have been adapted to take advantage of it.
It's now possible to prevent the use of ALL (e.g. EXAMINE ALL) with all but basic inventory handling verbs (TAKE, DROP, PUT and DOFF). Some people feel that the use of ALL with all the other verbs (EXAMINE ALL, SHOW ALL TO FRED etc.) allows a bit too much of a blunderbus approach to playing Interactive Fiction. If you wish to disable it, you can define the new allVerbsAllowAll property on gameMain to be nil (the default is true). You can also allow and disallow ALL for individual actions by setting their allowAll property to true or nil (which takes precedence over the allVerbsAllowAll setting).
The library now defines SIT ON and LIE ON actions. The default behaviour is simply to BOARD the object in question, since avd3Lite does not provide any support for postures. Games can override SIT ON and LIE ON to do something different if they need to. STAND IN, SIT IN and LIE IN actions have also been added; by default they're all equivalent to ENTER (although again this can be overridden). If you want SIT ON & SIT IN (or LIE ON and LIE IN) to act equivalently, e.g. for a chair or bed, define the chair or bed as a Surface with isBoardable = trueand dobjFor(Enter) asDobjFor(Board).
The library now suppresses the default "You see nothing special about the whatever" description of an object when the object has any state-specific information to add to its description. (This only makes a difference to objects where the author hasn't explicitly defined the desc property).
If the actor is in a "NestedRoom" (i.e. a Container or Surface rather than a Room) then the command OUT now takes the actor out of the actor's immediate location; previously it was taken to be a command to leave the Room.
Bug fixed whereby at several places in the library the non-existent property isPlural was referenced instead of the correct property, plural. Note however that this may change in a future release where 'is' may be prefixed to several property names (plural, transparent etc.) to provide a more consistent naming scheme across the library.
Bug fixed whereby opening a container caused all its contents to be listed, instead of only its listable contents.
Bug fixed that could prevent a Doer properly matching certain TI Actions for which resolveIobjFirst = true (since this caused the Doer matching mechanism to see the direct and indirect objects in reverse order).
Bug fixed whereby a light source in a closed transparent container failed to illuminate a room.
Bug fixed whereby when an action was applied to multiple objects and the name of each object was announced, any implied action reports came before the name of the object instead of after.
Bug fixed whereby a run-time error could occur when verifying the second object of a TIAction when the verify routine depended on the first object having been identified but the first object had been selected without any need for disambiguation.
Bug fixed whereby an actor getting off something that had an associated container attached (a table with a drawer, say) would cause an implied action opening the associated container.
Version 0.2 (November 2012)
Facilities added to allow better control over the way items are displayed in room descriptions. The specialDescOrder property can now be used to control the order in which specialDescs are shown. The specialDescBeforeContents property can be used to show whether an item's specialDesc should be shown before or after the listing of miscellaneous items in the the room description. The <<list of>> <<list of is>> and <<is list of>> embedded expressions can be used to customize the way an item's contents are listed in a room description. The <<mention a>> and <<mention the>> embedded expressions can be used to have one item in a room description listing mention another (and thereby suppress the subsequent listing of the same item). For full details see the new section on Room Descriptions.
The new SenseRegion class can be used to define regions with sensory connections, that is regions where it is possible to see (and possibly smell and hear) ojects in one room from another. For details see the new SenseRegion section of the manual.
It is now possible to compile adv3Lite games for use with the WebUI (i.e. for playing on-line via a browser).
Mainly to support the WebUI, a number of inputManager methods have been implemented (which are analogous to their adv3 counterparts). It is recommended that you always use these rather than the interpreter console i/o function equivalents. Note that in the adv3Lite version of these methods, there is no need to supply any arguments to inputManager.getInputLine() or inputManager.getKey() (since adv3Lite does not support real-time processing).
The Parser's DefaultAction (for a command that consists purely of a noun) has been changed to the new ExamineOrGoToAction. This works exactly like the Examine action unless (a) the noun entered by the player is a room known to the player character; (b) the player character is not already in that room; and (c) the pathfind module is included in the build. If all these three conditions are fulfilled the ExamineOrGoTo action behaves like a GoTo action, thereby allowing the player to navigate the map just by entering the name of the location s/he wants the player character to head towards.
The default value of GameMainDef.storeWholeObjectTable has been changed to true, since this is the safer option, and the memory requirement of storing the complete object table is unlikely to be an issue on a modern computer. If it is set to nil an additional setting now comes into effect: objTablePreinit.lookInMethods. If this is nil (the default), then objTablePreinit won't attempt to execute code (i.e. methods) to find conversation tags indicating objects it needs to store in the object table; this is the safer option since executing methods out of context at preinit can easily cause run-time errors. For now, lookInMethods can be set to true to restore the previous behaviour, but this should be regarded as provisionally deprecated.
The library preinit now marks the player character's immediate contents as known to the player character. This avoids the otherwise seemingly odd situation whereby a player familiar with the game tries to refer to something the player character is holding in conversation and it's not recognized by the parser as a valid topic (because the player has not yet taken inventory or performed any other action that would normally mark what the player character is holding as seen or known).
A minor change has been made to the way the hiddenUnder and hiddenBehind properties work. The new thing properties autoTakeOnLookUnder and autoTakeOnLookBehind allow you to specify that anything hidden under or behind the object in question should be taken by the actor when s/he looks under or behind it. If a look behind or look command action results in one or more objects being moved into the location of the object that has just been looked under/behind, then the message displayed now makes it clearer that the objects that have just been moved have been left in plain sight (rather than remaining concealed under or behind something else).
An objOpen PreCondition has been added. This isn't (currently) used in the library (which uses containerOpen) but might prove useful to some game code.
The documentation of the Thing class now explains the use of the owner and ownsContents properties. These properties were present before but weren't previously documented in the manual.
The setRevealed(tag) method of conversationManager so that the notification of other actors when a <.revealed> tag now only takes place when there's a respondingActor (i.e., when the <.revealed> tag is used in conversation). This corrects a bug whereby using a <.reveal> tag outside a conversation (e.g. to have an object description set a flag to trigger some other event) would cause a run-time error.
The message "You find nothing of interest under the whatever" has been corrected (it did not display correctly before).
Bug fixed whereby the player character's enclosing room was declared to be not visible when attempting to examine it.
Bug fixed whereby the default action (i.e. entering a noun without a verb as a command) was taken to be a conversational command just after the current interlocutor had gone out of scope.
Bug fixed whereby using a <.convnode> tag while a Conversation Node is active leaves the first Conversation Node still active (while activating the second one as well). A <.convnode> tag now overwrites the effect of any <.convnode> tag issued on a previous turn.
Bug fixed in which the name of canEndConversation() method of ActorState was mis-spelled, so that ActorStates always tried to prevent conversations ending by default (since the non-existent method was deemed to be returning nil).
Bugs fixed whereby a conversational command that triggered an implicit greeting would display a spurious "The x does not respond" message when no HelloTopic was found, or when a conversation was ended implicitly and no ByeTopic was found.
Bugs fixed whereby HELLO and BYE commands (not explicitly directed to a specific actor) might either result in no response at all, or the response "The [cobj] does not respond" (where [cobj] should have been the name of the actor in question).
Bug fixed in which the condition for deciding whether a SimpleAttachable should be listed separately was the wrong way round.