Actor States

The Purpose of Actor States

If you have an NPC whose behaviour is very basic, such as a guard whose sole purpose is to block an exit, or a fusty old clerk who never moves from her desk, you probably won't need to use Actor States with it. For more complex NPCs whose state can change, Actor States can be a very valuable way of modelling that state change. If the guard can be put to sleep by giving him too much to drink, then you might want to use one ActorState to represent the guard while he's alert and active, and another while he's somnulent. If the fusty old clerk turns into an animated conversationalist when you talk to her you might want to use one ActorState to represent her bent over her desk and another to represent her in animated conversation. The coding pattern might look something like this:

guard: Actor 'burly guard; strong powerful; man; him' @doorway
    "He looks incredibly strong and powerful. "
;

+ guardAlertState: ActorState
   isInitState = true
   specialDesc = "A burly guard blocks your path, eyeing you suspiciously. "
   stateDesc = 'You certainly don\'t want to mess with him. '
   
   beforeTravel(traveler, connector)
   {
      if(traveler == gPlayerChar && connector == forbiddenDoor)
      {
          "The guard blocks your path with a warning snarl. ";
          exit;
      }
   }
;

+ guardSleepingState: ActorState
   specialDesc = "The burly guard lies sprawled on the ground, snoring loudly. "
   stateDesc = 'At least he might be strong and powerful when he\'s awake, but right now he\'s dead
     to the world. '
     
   noResponse = "The guard is far too deep in his slumbers to hear you. "
;


clerk: Actor 'fusty old clerk;; woman; her' @procrastinationOffice
   "She doesn't look a day under sixty. "
;


+ clerkWorkingState: ActorState
   isInitState = true
   specialDesc = "A fusty old clerk sits bent over her desk, working her way through
     dusty ledgers. "
   stateDesc = 'She seems totally intent on her ledgers. '
;
  
+ clerkTalkingState: ActorState
   specialDesc = "The clerk sits looking up at you from behind her desk, eagerly 
     awaiting you to continue the conversation. "
   stateDesc = 'But the rapt expression on her face and the animated sparkle in her bright
     blue eyes as she hangs on your every word somehow make her seem half that age. '
;

Note that the stateDesc on the current ActorState is appended to the desc defined on the Actor when the Actor is examined. (Authors familiar with the adv3 library might also like to note that adv3Lite defines only the one ActorState class; defining the property as in the above example replicates the function of a HermitActorState, and other adv3 ActorState classes are similarly implemented in different ways in adv3Lite).

If you wish, you can make use of the ActorState template to define the specialDesc property and, optionally, the stateDesc property as well. For example the guardSleepingState above could have been defined as:

 + guardSleepingState: ActorState
   "The burly guard lies sprawled on the ground, snoring loudly. "
   'At least he might be strong and powerful when he\'s awake, but right now he\'s dead
     to the world. '
     
   noResponse = "The guard is far too deep in his slumbers to hear you. "
; 
 

Defining an ActorState: the Common Properties

As you may have gathered from the foregoing examples, one property you will nearly always want to define on an ActorState is the specialDesc, which provides a separate paragraph in a room description describing the Actor while it's in this state. You may also often wish to define the stateDesc, which is appended to the Actor's desc property when the Actor is examined. Finally, if an Actor has one or more ActorStates, one of them is presumably the ActorState the Actor starts out in; you indicate which one this is by defining isInitState = true on the ActorState in question.

As shown in the examples above, ActorStates are always located directly within the Actor to which they belong. ActorStates can also contain TopicEntries; any TopicEntries contained within an ActorState will only be active while the Actor is in that state. This allows you to customize the Actor's reponse to conversation commands (such as ASK and TELL) depending on what state the Actor is in; responses common to all states can be placed directly within the Actor.

The following properties and methods have the same meaning as they would on Thing (or Actor), except that the Actor delegates them to the current ActorState, so you can write state-specific responses:

In addition, the following methods/properties defined on Actor may also be defined on ActorState; if the Actor has a current ActorState the version defined on the current ActorState is the one that will be used:

And finally, there are some methods and properties that are peculiar to ActorState:


If desired, an ActorState can be mixed in with an EventList class to define a list of 'fidget' (atmospheric) messages describing what the actor is doing while in that state, in order to make the actor appear a little more lifelife, for example:

+ bobStackingState: ActorState, ShuffledEventList
    specialDesc = "Bob is busily stacking cans. "
    eventList = [
	  'Bob picks up a can and studies its label. ',
	  'Bob puts another can on the stack. ',
	  'Bob pauses to inspect his stack of cans. ',
	  'Bob takes a can from one part of the stack and places it on another part. '
	]
;

With this definition, one of the messages from the eventList will be displayed on each turn that Bob is in bobStackingState and not engaged in something more urgent, such as responding to conversation or executing an AgendaItem.


Switching ActorState

The whole point of having ActorState objects is to represent different states your NPCs can get into during the course of your game. It follows that if you are using ActorStates at all you will almost certainly need some means of switching from one state to another. The most common means is by calling setState(stat) on the Actor, where stat is the new ActorState you want to change to, for example:

   /* In the code where the guard drinks too much wine */
   guard.setState(guardSleepingState);
   
   /* In the code in which you engage the clerk in conversation */
   clerk.setState(clerkTalkingState);

The second method, which can be useful if you're outputting a string just before changing ActorState is to use the <.state newstate> tag:

   /* In the code where the guard drinks too much wine */
   "The wine bottle slips out of the guard's hand as he slips into a deep slumber. <.state guardSleepingState>";
   
   /* In the code in which you engage the clerk in conversation */
   "The clerk looks up at you expectently. <.state clerkTalkingState>";

Note that there may be limitation on where this will work; these will be discusses further below.

A third method is to use a GreetingTopic (HelloTopic or ByeTopic) and define its changeToState property to change state on beginning or ending a conversation, for example:

clerk: Actor 'fusty old clerk;; woman; her' @procrastinationOffice
   "She doesn't look a day under sixty. "
;


+ clerkWorkingState: ActorState
   isInitState = true
   specialDesc = "A fusty old clerk sits bent over her desk, working her way through
     dusty ledgers. "
   stateDesc = 'She seems totally intent on her ledgers. '
;

++ HelloTopic
   "<q>Hello there!</q> you say.\b
    <q>Why, hello!</q> she replies, looking up at you with a surprisingly bright smile. "
    
    changeToState = clerkTalkingState   
;
   
  
+ clerkTalkingState: ActorState
   specialDesc = "The clerk sits looking up at you from behind her desk, eagerly 
     awaiting you to continue the conversation. "
   stateDesc = 'But the rapt expression on her face and the animated sparkle in her bright
     blue eyes as she hangs on your every word somehow make her seem half that age. '
;

++ ByeTopic
   "Well, goodbye then, you say.
    Goodbye, she replies crisply, turning her attention back to her ledgers. "
    
    changeToState = clerkWorkingState
;

This code will cause the clerk to switch to her clerkTalkingState when she's first addressed, and back to her clerkWorkingState when the conversation ends. The use of HelloTopics and ByeTopics will be discussed in more detail when we come to look at Greeting Protocols below.