Note that, by default, an Actor can be picked up and moved with commands like TAKE, PUT IN, and so on. This is suitable for some kinds of actors but not for others: it might make sense with a cat or a small dog, but not with a bank guard or an orc. For an actor that can't be taken, use the UntakeableActor or one of its subclasses.
An actor's contents are the things the actor is carrying or wearing.
An Actor has a "referral person" setting, which determines how we refer to the actor; this is almost exclusively for the use of the player character. The typical convention is that we refer to the player character in the second person, but a game can override this on an actor-by-actor basis.
This is for internal bookkeeping only, and it applies to the current travel only. This is NOT a general "follow mode" setting, and it shouldn't be used to get me to follow another actor or another actor to follow me. To make me accompany another actor, simply override accompanyTravel() so that it returns a suitable ActorState object.
Note that this state is part of the actor, even though it's usually managed by the InConversationState object. The state is stored with the actor rather than with the state object because it really describes the condition of the actor, not of the state object.
A word of caution on these is in order. Many authors worry that it's unrealistic if the player character can carry too much at one time, so they'll fiddle with these properties to impose a carrying limit that seems realistic. Be advised that authors love this sort of "realism" a whole lot more than players do. Players almost universally don't care about it, and in fact tend to hate the inventory juggling it inevitably leads to. Juggling inventory isn't any fun for the player. Don't fool yourself about this - the thoughts in the mind of a player who's tediously carting objects back and forth three at a time will not include admiration of your prowess at simulational realism. In contrast, if you set the carrying limit to infinity, it's a rare player who will even notice, and a much rarer player who'll complain about it.
If you really must insist on inventory limits, refer to the BagOfHolding class for a solution that can salvage most of the "realism" that the accountancy-inclined author craves, without creating undue inconvenience for the player. BagOfHolding makes inventory limits palatable for the player by essentially automating the required inventory juggling. In fact, for most players, an inventory limit in conjunction with a bag of holding is actually better than an unlimited inventory, since it improves readability by keeping the direct inventory list to a manageable size.
The referral person depends on the specifics of the language. In English, a command like "bob, go north" is a second-person command, while "tell bob to go north" is a third-person command. The only reason this is important is in interpreting what "you" means if it's used as an object in the command. "tell bob to hit you" probably means that Bob should hit the player character, while "bob, hit you" probably means that Bob should hit himself.
Conceptually, these senses are intended to be only those senses that the actors would *naturally* use to communicate, because senses in this list allow direct communications via the most ordinary game commands, such as "bob, go east".
If some form of indirect communication is possible via a sense, but that form is not something the actor would think of as the most natural, default form of communication, it should *not* be in this list. For example, two sighted persons who can see one another but cannot hear one another could still communicate by writing messages on pieces of paper, but they would ordinarily communicate by talking. In such a case, sound should be in the list but sight should not be, because sight is not a natural, default form of communications for the actors.
It's not necessary to initialize this if the actor doesn't take advantage of the ActorState mechanism. If this isn't initialized for a particular actor, we'll automatically create a default ActorState object during pre-initialization.
This is used to disambiguate target actors in commands, so this should provide an indication of what should be obvious to a player, because the purpose of this information is to guess what the player is likely to take for granted in specifying a target actor.
By default, this is true, which means that we wait for other actors to finish all of the commands we issue before we take another turn.
If this is set to nil, we'll continue to take turns while the other actor carries out our commands. In this case, the only time cost to us of issuing a command is given by orderingTime(), which normally takes one turn for issuing a command, regardless of the command's complexity. Some games might wish to use this mode for interesting effects with NPC's carrying out commands in parallel with the player, but it's an unconventional style that some players might find confusing, so we don't use this mode by default.
As with 'seenProp' above, if you want to keep track of each NPC's knowledge separately, you must override this property for each NPC who's to have its own knowledge base to use a separate property name. For example, if you want to keep track of what Bob knows individually, you could define 'knownProp = &bobKnows' in Bob.
Note that we make the simplifying assumption that an object can be held by only one actor at a time (multi-location items are generally not portable), which means that we can use a simple property in each object being held to store its holding index.
Consider this command line:
>Bob, go north and get fuel cell. Get log tape.
If this flag is nil, then the second sentence ("get log tape") is interpreted as a command to Bob, because Bob is explicitly designated as the target of the command, and this remains in effect until the end of the entire command line.
If this flag is true, on the other hand, then the second sentence is interpreted as a command to the player character, because the target actor designation ("Bob,") lasts only until the end of the sentence. Once a new sentence begins, we revert to the issuing actor (the player character, since the command came from the player via the keyboard).
We choose a scheduling order that schedules actors in this relative order:
100 player character, ready to execute
200 NPC, ready to execute
300 player character, idle
400 NPC, idle
An "idle" actor is one that is waiting for another character to complete a command, or an NPC with no pending commands to perform. (For the player character, it doesn't matter whether or not there's a pending command, because if the PC has no pending command, we ask the player for one.)
This ordering ensures that each actor gets a chance to run each turn, but that actors with work to do go first, and other things being equal, the player character goes ahead of NPC's.
By default, we give each actor all of the human senses that we define, except touch. In general, merely being able to touch an object doesn't put the object in scope, because if an object isn't noticed through some other sense, touch would only make an object accessible if it's within arm's reach, which for our purposes means that the object is being held directly by the actor. Imagine an actor in a dark room: lots of things might be touchable in the sense that there's no physical barrier to touching them, but without some other sense to locate the objects, the actor wouldn't have any way of knowing where to reach to touch things, so they're not in scope. So, touch isn't a scope sense.
Some games might want to track each NPC's sight memory separately, or at least they might want to track it individually for a few specific NPC's. You can do this by making up a new property name for each NPC whose sight memory you want to keep separate, and simply setting 'seenProp' to that property name for each such NPC. For example, for Bob, you could make the property bobHasSeen, so in Bob you'd define 'sightProp = &bobHasSeen'.
These senses are used to determine what objects should be listed in room descriptions, for example.
By default, the only sight-like sense is sight, since other human senses don't normally provide a clear picture of the spatial relationships among objects. (Touch could with some degree of effort, but it can't operate passively or instantly, since deliberate and time-consuming action would be necessary.)
An actor can have more than one sight-like sense, in which case the senses will act effectively as one sense that can reach the union of objects reachable through the individual senses.
This routine performs only the simplest check, since it doesn't have access to the specific action being performed. This is intended as a first check, to allow us to bypass noun resolution if the actor simply won't accept any command from the issuer.
Returns true to accept a command, nil to reject it. If this routine returns nil, and the command came from the player character, a suitable message should be displayed.
Note that most actors should not override this routine simply to express the will of the actor to accept a command, since this routine performs a number of checks for the physical ability of the actor to execute a command from the issuer. To determine whether or not the actor should obey physically valid commands from the issuer, override obeyCommand().
By default, we won't accept a command if we have any work pending.
In concrete terms, this generally adds a message such as "(sitting on the chair)" to the name of a room if we're in a nested room within the room. When we're standing in the main room, this generally adds nothing.
Note that we pass the room we're describing as the "container to ignore" parameter, because we don't want to say something like "Phone Booth (standing in the phone booth)" - that is, we don't want to mention the nominal container again if the nominal container is what we're naming in the first place.
Items can be added here if they must be notified of actions performed by the actor even when the items aren't connected by containment with the actor at the time of the action. All items connected to the actor by containment are automatically notified of each action; only items that must receive notification even when not in scope need to be registered here.
We return true if we can understand the communication, nil if not. There is no middle ground where we can partially understand; we can either understand or not.
Note that this routine is concerned only with our ability to sense the communication. The result here should NOT pay any attention to whether or not we can actually communicate given a clear sense path - for example, this routine should not reflect whether or not we have a spoken language in common with the other actor.
This is a service method for canTalkTo. This is broken out as a separate method so that individual actors can override the necessary conditions for communications in particular senses.
Actors might want to override this to be more tolerant. For example, an actor might want to wait until five turns elapse to give up on following, in case the target actor returns after a brief digression; or an actor could stay in follow mode until it received other instructions, or found something better to do.
In order for the player character to issue a command to a non-player character (as in "bob, go east"), the NPC must be able to sense the PC via at least one communication sense that the two actors have in common.
Likewise, in order for a non-player character to say something to the player, the player must be able to sense the NPC via at least one communication sense that the two actors have in common.
Travel connectors normally call this before invoking our travelTo() method to carry out the travel. The darkness check usually must be made before any barrier checks.
In the present tense, this is pretty easy: we add an 's' for the third person singular, and leave the verb unchanged for every other case. The only complication is that we must check some special cases to add the -s suffix: -y -> -ies, -o -> -oes.
In the past tense, we use the inherited handling since the past tense ending doesn't vary with person.
By default, we'll show the basic "there's no response" message. This isn't a very good message in most cases, because it makes an actor pretty frustratingly un-interactive, which gives the actor the appearance of a cardboard cut-out. But there's not much better that the library can do; the potential range of actors makes a more specific default response impossible. If the default response were "I don't know about that," it wouldn't work very well if the actor is someone who only speaks Italian. So, the best we can do is this generally rather poor default. But that doesn't mean that authors should resign themselves to a poor default answer; instead, it means that actors should take care to override this when defining an actor, because it's usually possible to find a much better default for a *specific* actor.
The *usual* way of providing a default response is to define a DefaultAskTopic (or a DefaultAskTellTopic) and put it in the actor's topic database.
By default, we'll just show "there's no response" as a default message. We'll show this in default mode, so that if the caller is going to show a list of suggested conversation topics (which the 'hello' and 'talk to' commands will normally try to do), the topic list will override the "there's no response" default. In other words, we'll have one of these two types of exchanges:
>talk to bob
There's no response
>talk to bill
You could ask him about the candle, the book, or the bell, or
tell him about the crypt.
As with defaultAskResponse, this should almost always be overridden by each actor, since the default response ("there's no response") doesn't make the actor seem very dynamic.
The usual way of providing a default response is to define a DefaultTellTopic (or a DefaultAskTellTopic) and put it in the actor's topic database.
'contToIgnore' is a container to ignore. If our nominal container is the same as this object, we'll generate a description without a mention of a container at all.
The reason we have the 'contToIgnore' parameter is that the caller might already have reported our general location, and now merely wants to add that we're standing or standing or whatever. In these cases, if we were to say that we're sitting on or standing on that same object, it would be redundant information: "Bob is in the garden, sitting in the garden." The 'contToIgnore' parameter tells us the object that the caller has already mentioned as our general location so that we don't re-report the same thing. We need to know the actual object, rather than just the fact that the caller mentioned a general location, because our general location and the specific place we're standing or sitting or whatever might not be the same: "Bob is in the garden, sitting in the lawn chair."
This call is mostly useful when the actor's current state is an InConversationState, since the main function of this routine is to switch to an out-of-conversation state.
We set up an ActorTurnAction environment and invoke our executeActorTurn() method. In most cases, subclasses should override executeActorTurn() rather than this method, since overriding executeTurn() directly will lose the action environment.
Note that we don't differentiate here based on whether or not an item is being worn, or anything else - we deliberately leave such distinctions up to the getEncumberingBulk routine, so that only the objects are in the business of deciding how bulky they are under different circumstances.
If we have a special traveler explicitly set, it overrides the traveler indicated by the location.
Note that we deliberately only consider our direct contents. If any of the items we are directly holding contain further items, getEncumberingWeight will take their weights into account; this frees us from needing any special knowledge of the internal structure of any items we're holding, and puts that knowledge in the individual items where it belongs.
If a particular actor looks a lot like an inanimate object, it might want to override this to participate in 'all' for most or all actions.
In "player" mode, each implied command is announced with a description of the command to be performed; DEFAULT responses are suppressed; and failures are shown. Furthermore, interactive requests for more information from the parser are allowed. Transcripts like this result:
(first opening the door)
(first unlocking the door)
What do you want to unlock it with?
In "NPC" mode, implied commands are treated as complete and separate commands. They are not announced; default responses are shown; failures are NOT shown; and interactive requests for more information are not allowed. When an implied command fails in NPC mode, the parser acts as though the command had never been attempted.
By default, we return ModePlayer if we're the player character, ModeNPC if not (thus the respective names of the modes). Some authors might prefer to use "player mode" for NPC's as well as for the player character, which is why the various parts of the parser that care about this mode consult this method rather than simply testing the PC/NPC status of the actor.
'state' is the ActorState to switch to for the conversation. This will normally be an InConversationState object, but doesn't have to be.
You can pass nil for 'state' to use the current state's implied conversational state. The implied conversational state of a ConversationReadyState is the associated InConversationState; the implied conversation state of any other state is simply the same state.
'node' is a ConvNode object, or a string naming a ConvNode object. We'll make this our current conversation node. A valid conversation node is required because we use this to generate the initial NPC greeting of the conversation. In most cases, when the NPC initiates a conversation, it's because the NPC wants to ask a question or otherwise say something specific, so there should always be a conversational context implied, thus the need for a ConvNode. If there's no need for a conversational context, the NPC script code might just as well display the conversational exchange as a plain old message, and not bother going to all this trouble.
By default, we'll recognize any Topic object marked as known, and we'll recognize any game object for which our knowsAbout(obj) returns true. Games might wish to override this in some cases to limit or expand an actor's knowledge according to what the actor has experienced of the setting or story. Note that it's often easier to control actor knowledge using the lower-level knowsAbout() and setKnowsAbout() methods, though.
If 'verbose' is true, then we'll show the full description in all cases. Otherwise, we'll show the full description if the actor hasn't seen the location before, or the terse description if the actor has previously seen the location.
This method need not do anything at all, since the caller will take care of running the pending command. The purpose of this method is to take care of any changes an actor wants to make when it receives an explicit command, as opposed to running its own autonomous activity.
By default, we cancel follow mode if it's in effect. It usually makes sense for an explicit command to interrupt follow mode; follow mode is usually started by an explicit command in the first place, so it is usually sensible for a new command to replace the one that started follow mode.
By default, we don't do anything here, because we don't have any default code to send a command from one NPC to another. Any custom NPC actor that sends a command to another NPC actor might want to use this to deal with problems in processing those commands.
This description should include only the constant, fixed description of the character. Do not include information on what the actor is doing right now, because that belongs in the ActorState object instead. When we display the actor's description, we'll show this text, and then we'll show the ActorState description as well; this combination approach makes it easier to keep the description synchronized with any scripted activities the actor is performing.
By default, we'll show this as a "default descriptive report," since it simply says that there's nothing special to say. However, whenever this is overridden with an actual description, you shouldn't bother to use defaultDescReport - simply display the descriptive message directly:
npcDesc = "He's wearing a gorilla costume. "
When this routine is called, the action has been determined, and the noun phrases have been resolved. However, we haven't actually started processing the action yet, so the globals for the noun slots (gDobj, gIobj, etc) are NOT available. If the routine needs to know which objects are involved, it must obtain the full list of resolved objects from the action (using, for example, getResolvedDobjList()).
When there's a list of objects to be processed (as in GET ALL), we haven't started working on any one of them yet - this check is made once for the entire command, and applies to the entire list of objects. If the actor wants to respond specially to individual objects, you can do that by overriding actorAction() instead of this routine.
This routine should display an appropriate message and return nil if the command is not to be accepted, and should simply return true to accept the command.
By default, we'll let our state object handle this.
Note that actors that override this might also need to override wantsFollowInfo(), since an actor that accepts "follow" commands will need to keep track of the movements of other actors if it is to carry out any following.
If 'turns' is zero, the conversation can start the next time the actor takes a turn; so, if this is called during the PC's action processing, the conversation can start on the same turn. Note that if this is called during the actor's takeTurn() processing, it won't actually start the conversation until the next turn, because that's the next time we'll check the queue. If 'turns' is 1, then the player will get at least one more command before the conversation will begin, and so on with higher numbers.
An actor is aware of an object if the object is within reach of the actor's senses, and has some sort of presence in that sense. Note that both of these conditions must be true for at least one sense possessed by the actor; an object that is within earshot, but not within reach of any other sense, is in scope only if the object is making some kind of noise.
In addition, objects that the actor is holding (i.e., those contained by the actor directly) are always in scope, regardless of their reachability through any sense.
The purpose of this routine is to simplify scripted travel for simple cases where directional connectors are available for the desired travel. This routine is NOT suitable for intelligent goal-seeking NPC's who automatically try to find their own routes, for two reasons. First, this routine only lets an NPC move to an *adjacent* location; it won't try to find a path between arbitrary locations. Second, this routine is "omniscient": it doesn't take into account what the NPC knows about the connections between locations, but simply finds a connector that actually provides the desired travel.
What this routine *is* suitable for are cases where we have a pre-scripted series of NPC travel actions, where we have a list of rooms we want the NPC to visit in order. This routine simplifies this type of scripting by automatically finding the connectors; the script only has to specify the next location for the NPC to visit.
If only one object is present, we'll set the object to be the antecedent of 'it', 'him', or 'her', according to the object's gender. We'll also set the object as the single antecedent for 'them'.
If we have multiple objects present, we'll set the list to be the antecedent of 'them', and we'll forget about any antecedent for 'it'.
Note that the input is a list of ResolveInfo objects, so we must pull out the underlying game objects when setting the antecedents.
Pass an argument list consisting of ResolveInfo lists - that is, pass one argument per noun slot in the verb, and make each argument a list of ResolveInfo objects. In other words, you call this just as you would setPronoun(), except you can pass more than one list argument.
We'll store the multiple objects as antecedents. When we need to resolve a future singular pronoun, we'll figure out which of the multiple antecedents is the most logical choice in the context of the pronoun's usage.
Note that this method must be overridden if the actor does not use a conventional 'contents' list property to store its full set of contents.
We'll show the list of suggested topics associated with our current conversational partner. If there are no topics, we'll say nothing unless 'explicit' is true, in which case we'll simply say that there are no topics that the player character is thinking about.
The purpose of this method is to let the game author keep an "inventory" of topics with this actor for a given conversational partner. This inventory is meant to represent the topics that on the player character's mind - things the player character wants to talk about with the other actor. Note that we're talking about what the player *character* is thinking about - obviously we don't know what's on the player's mind.
When we enter conversation, or when the player asks for advice, we'll show this inventory. The idea is to help guide the player through a conversation without the more heavy-handed device of a formal conversation menu system, so that conversations have a more free-form feel without leaving the player hunting in the dark for the magic ASK ABOUT topic.
The TOPICS system is entirely optional. If a game doesn't specify any SuggestedTopic objects, then this routine will simply never be called, and the TOPICS command won't be allowed. Some authors think it gives away too much to provide a list of topic suggestions like this, and others don't like anything that smacks of a menu system because they think it destroys the illusion created by the text-input command line that the game is boundless. Authors who feel this way can just ignore the TOPICS system. But be aware that the illusion of boundlessness isn't always a good thing for players; hunting around for ASK ABOUT topics can make the game's limits just as obvious, if not more so, by exposing the vast number of inputs for which the actor doesn't have a good response. Players aren't stupid - a string of variations on "I don't know about that" is just as obviously mechanistic as a numbered list of menu choices. Using the TOPICS system might be a good compromise for many authors, since the topic list can help guide the player to the right questions without making the player feel straitjacketed by a menu list.
'obj' is the object that is seen to be leaving, and 'conn' is the TravelConnector it is taking.
'conn' is the connector being traversed. If we're simply being observed in this location (as in a call to setHasSeen), rather than being observed to leave the location, the connector will be nil.
'from' is the effective starting location of the travel. This isn't necessarily the departing object's location, since the departing object could be inside a vehicle or some other kind of traveler object.
Note that this notification is sent only to actors with some sort of containment connection to the object that's moving, because a containment connection is necessary for there to be a sense connection.
Note that these preconditions apply only when the actor is the traveler. If the actor is in a vehicle, so that the vehicle is the traveler in a given travel operation, the vehicle's travelerPreCond conditions are used instead of ours.
Travel within a location is not restricted by darkness; we assume that if the nested objects are in scope at all, travel among them is allowed.
This type of travel does not trigger calls to travelerLeaving() or travelerArriving(). To mitigate this loss of notification, we call actorTravelingWithin() on the source and destination objects.
If holding the new object would exceed the our maximum holding capacity, we'll go through our inventory looking for objects that can reduce our held bulk with implicit commands. Objects with holding affinities - "bags of holding", keyrings, and the like - can implicitly shuffle the actor's possessions in a manner that is neutral as far as the actor is concerned, thereby reducing our active holding load.
Returns true if an implicit command was attempted, nil if not.
If we're configured to wait for completion of orders given to other actors before we get another turn, we'll set ourselves up in waiting mode. Otherwise, we'll do nothing.
By default, the player character tracks everyone, and NPC's track only the actor they're presently tasked to follow. Most NPC's will never accept 'follow' commands, so there's no need to track everyone all the time; for efficiency, we take advantage of this assumption so that we can avoid storing a bunch of tracking information that will never be used.