# Moods and Stances

## Overview

In many games it may be enough (or more than enough) to track what various actors know and believe, but human beings have affective as well as cognitive properties, and if we're trying to create lifelike NPCs in our game, it may be that we want to track something about their emotional lives too. Moods and Stances in adv3Lite provide a framework for tracking each Actor's current emotional state (Mood) and (positive or negative) attitude towards the player character (and, if we so wish, towards other NPCs).

An Actor's mood and/or stance can be tested (and changed) in game code to affect the way the Actor behaves, for example in his or her converational responses or AgendaItems.

## Moods

A Mood is a simple representation of an Actor's current emotional state. Moods are objects of the Mood class. Each Mood object has a programmatic name ending in Mood (e.g., happyMood) with a corresponding name< property giving the name of the Mood as a single-quoted string (e.g., 'happy'). A number of Moods come predefined in the language dependent part of the library (english.t): neutral, calm, happy, euphoric, contented, sad, depressed, angry, furious, afraid, terrified, confident, bold. lonely, bored, and excited. You can easily define more if you want them. For example, to define an irritable Mood you'd just use:

     DefMood(irritable);

This would create the following object:

     irritableMood:Mood
         name = 'irritable'
    ;

The Actor class defines the following properties and methods to support the use of Moods:

- mood: The Actor's current mood (e.g. neutralMood). This should be treated as read-only, since it returns the mood defined on the actor's current ActorState (if there is one) or else the value of actorMood. To change the Actor's mood either set actorMood or use the setMood() method.
- actorMood: The mood this actor is in if and when he or she isn't in any ActorState, or if his/her current ActorState's mood is nil (the default), or the Actor's stateDependentMoods property is set to nil.
- setMood(mood_): sets the Actor's current ActorsState's mood to mood_, or the Actor's actorMood to mood_ if the Actor has no current ActorState. If you want to avoid changing the current ActorState's mood just use actorMood = newMood instead, or set the Actor's stateDependentMoods property to nil. Note thst setMood(mood_) will complain (and not set the mood) if mood_ is not a Mood object.
- stateDependentMoods: If you don't want moods to be related to ActorStates (which would be perfectly reasonable if, for example, you were using ActorStates to model what actors were doing and the like regardless of their mood) then you can set this to nil, either on individual Actors or on the Actor class.

The default initial actorMood for an Actor is the value of libGlobal.defaultMood, which in the english library is neutralMood. It's done this way so that translators (or game authors) working in different languages can readily define their own default mood.

The library also defines the following macros to work with moods:

- gMood: get getActor's current mood.
- gMoodIs(name): test whether getActor's current mood is name
- gMoodIn(name1, name1...): test whether getActor's mood is one of name1, name1...
- gSetMood(name): set getActor's mood to name.
- aMood(actor): get actor's current mood.
- aMoodIs(actor, name): test whether actor's current mood is name
- aMoodIn(actor, name1, name1...): test whether actor's mood is one of name1, name1...
- aSetMood(actor, name): set actor's mood to name.

In each case the name parameter is the name of the Mood without the suffix 'Mood', so that, for example, you would use gMoodIs(happy) rather than gMoodIs(happyMood).

The macros with names starting with g all relate to getActor in contexts where getActor makes sense, i.e. in an ActorTopicEntry, TopicGroup or AgendaItem where getActor is the actor any of these belong to). To get or set the mood of any other actor, or in any other context, you need to use one of th macros beginning a and specify the actor parameter to denote the actor in question.

The macros gMood and aMood(actor) return the Mood object e.g. happyMood.

Moods can be used in various ways to customize NPC responses in various ways. Here's one very simple example:

    ++ AskTopic @bob
         "<q>How are you today?</q> you enquire.\b
          <q>I'm quite <<gMood.name>>,</q> he replies. "
    ;

More typically, we might do something like this:

    ++ AskTopic @bob
        "<q>How are you today?</q> you enquire.\b
        <q>I'm <<if gMoodIn(happy, euphoric, excited, confident)>>great<<else if gMoodIn(
            sad, depressed, lonely, bored)>>not so good<<else>>okay<<end>>,</q> he tells you. "
    ;

You can also extend the Mood framework in any way you think fit. For example, if you wanted to add strength and affect properties to Mood (so that Moods with the same affect could, for example, be grouped together and compared for their strength) you could do something like this:

    #define ModMood(mood_, strength_, affect_)\
        modify mood_ ## Mood\
        strength = strength_\
        affect = #@affect_

    modify Mood
        strength = 0
        afffect = 'none'
    ;

    ModMood(furious, 50, anger);
    ModMood(angry, 25, anger);
    ModMood(happy, 25, happiness);
    ModMood(euphoric, 50, happiness);
    ;

    // and so on

The macro expansion would then result in:

    modify furiousMood
       strength = 50
       affect = 'anger'
    ;

    // and so on

We don't do this in the library since we assume that different game authors will want to adapt the moods framework in different ways. The above example would allow embedded expressions (or other such tests) like "<<if gMood.affect == 'happines'>>happy text<<else if gMood.affect == 'anger'>> angry response<<else ...>>".

## Stances

Stances provide a simple representation of the the (positive or negative) attitude an NPC has towards the Player Character (and also, if you wish to track it, towards other NPCs). Stances are not ActorState dependent, but they are Actor-dependent in the sense that an NPC's stance towards other actors in the game may obviously vary by actor. Unlike Moods, stances can be ranked by score, a crude measure of the degree of positivity or negativity an actor has towards the Player Character (and possible other actors).

Stances are objects of the Stance class. Each Stance object has a programmatic name ending in Stance(e.g., friendly) with a corresponding name< property giving the name of the Stance as a single-quoted string (e.g., 'friendly'), along with an associated score<, e.g. 20. A number of Stances come predefined in the language dependent part of the library (english.t); in ascending order of score (from -50 to 50) these are: loathing, rancorous, hostile, unfriendly, cool, neutral, lukewarm, friendly, warm, loving, and amorous. You can easily define more if you want them. For example, to define a cordial Stance with a score 25 of you'd just use:

     DefStance(cordial, 25);

This would create the following object:

     cordialStance: Stance
         name = 'cordial'
         score = 25
    ;

The Actor class defines the following properties and methods to support the use of Stances:

- stance: The Actor's current stance towards the Player Character (e.g. neutralSTance). This should be treated as read-only, since it returns the value of stanceTowards(gPlayerChar). To change the Actor's stance use the setStanceToward() method.
- stanceToward(actor): The stance this Actor has towards actor.
- setStanceToward(actor, stance): sets the Actor's current stance towards actor to stance.If actor is not an Actor and/or stance is not a Stance this method will complain about it rather than attempting to update anything.
- likesMost(): returns a list of actors to whom this Actor has the most positive stance (of the stances s/he holds).
- likesLeast(): returns a list of actors to whom this Actor has the least positive stance (of the stances s/he holds).
- mostLikedBy(): returns a list of actors who hold the most positive stance to this Actor(of the stances they hold).
- leastLikedBy(): returns a list of actors who hold the least positive stance to this Actor(of the stances they hold).

In the case of the final four of these, the Actor is excluded from the list under consideration (consider the case where Bob has a positive stance towards everyone else but his stance towards himself has been left at neutralStance; to learn that Bob likes himself the least probably isn't the information we'd be looking for here).

As with Mood, there are a number of macros that can be used with Stance; the following all concern other actors' stances towards the Player Character.

- gStance: get getActor's current stance towards the Player Character (PC).
- gStanceIs(name): test whether getActor's current stance towards the PC is name
- gStanceIn(name1, name1...): test whether getActor's stance towards the PC is one of name1, name1...
- gSetStance(name): set getActor's stance towards the PC to name.
- aStance(actor): get actor's current stance towards the PC.
- aStanceIs(actor, name): test whether actor's current stance towards the PC is name
- aStanceIn(actor, name1, name1...): test whether actor's stance towards the PC is one of name1, name1...
- aSetStance(actor, name): set actor's stance towards the PC to name.

In each case the name parameter is the name of the Stance without the suffix 'Stance', so that, for example, you would use gStanceIs(friendly) rather than gStanceIs(friendlyStance).

The macros with names starting with g all relate to getActor in contexts where getActor makes sense, i.e. in an ActorTopicEntry, TopicGroup or AgendaItem where getActor is the actor any of these belong to). To get or set the stance of any other actor towards the player character, or in any other context, you need to use one of th macros beginning a and specify the actor parameter to denote the actor in question.

The macros gStance and aStance(actor) return a Stance object e.g. friendlyStance.

Because Stances have an associated score, they can be ranked and compared by score. The following operators are available to compare Stances:

- a - b: equivalent to a.score - b.score
- a >> b: equivalent to a.score > b.score
- a << b: equivalent to a.score < b.score
- a >>> b: equivalent to a.score >= b.score

(The last three of these operators were chosen in place of the more conventional ones as being the closest available operators TADS can override).

There are a further trio of Stance operators which may perhaps be useful to some game authors:

- whateverStance[a] = [b]: Sets whateverStance to be a's stance to b.
- whateverStance[a]: returns a list of people towards whom a holds this stance.
- whateverStance * a: returns a list of people who hold this stance towards a.

If you need to set up a fair number of attitudes at the start of play, you can make use of the stanceInitializer object, modifying it to define a list of stances, each stance entry being a list of the form [actor1, stance, actor2], meaning actor1 starts out holding stance towards actor2. To avoid having to keep typing 'Stance' at the end of each stance name, you can make use of the Sta macro, for example:

     modify stanceInitializer
        stances = [
            Sta(me, friendly, bob),
            Sta(bob, warm, me),
            Sta(bob, amorous, mavis),
            Sta(mavis, loving, bob),
            Sta(me, lukewarm, mavis),
            Sta(mavis, cool, me)
        ]
    ;

Note that you don't need to add any entries for the neutralStance, since this is the default.

A simple example of what can be done with Stances might be varying greeting responses according to stance:

    ++ HelloTopic
        "<q>Hello, Bob,</q> you say.\b
        <q>Hello,</q> he replies. "
    ;

    +++ AltTopic
         "<q>Hi there, Bob,</q> you say.\b
        <q>Hi, great to see you!</q> he declares. "
       isActive = gStance >> neutralStance
    ;

    +++ AltTopic
        "Hello, you say.\b
        In reply Bob merely grunts. "
        isActive = gStance << coolStance
    ;

Or you could do something like this:

    ++ QueryTopic 'how Mavis feels about you; does feel me'
        "<q><<if aStanceIn(mavis, neutral, lukewarm, warm, friendly, loving)>>I think she quite likes
        you<<else>>I'd rather not say<<end>>,</q> he tells you. "
    ;

Or as an extreme example of using a Stance in connection with an AgendaItem:

     bobLoathingAgenda: AgendaItem
        invokeItem()
        {
            "Bob snarls as you enter the room. <q>I <i>hate</i> you</q>!\b
            So saying, he snatches up the nearest heavy blunt object and smashes
            it down on your head with all the force he can muster.\b";

            finishGameMsg(ftDeath, [finishOptionUndo]);
        }

        agendaOrder = 50
        initiallyActive = true
        isReady = gStanceIs(loathing) && gRoom == getActor.getOutermostRoom
    ;

No doubt game authors will be able to come up with many more ingenious uses for Moods and Stances than the examples given here, but hopefully we have suggested enough to get you started.

adv3Lite Library Manual
Table of Contents | Actors > Moods and Stances
Prev: Giving Orders to NPCs Next: String Tags and Object Tags