Skip to content
/a/ FaceCue Performance Studio

Dialogue State

Whether the character is being spoken to, and whether it owes an answer.

This is the lane that gives a character the one state it cannot infer from its own audio, which is Listening.

The Source

Implement IDialogueStateSource and assign it to the brain's DialogueStateSource.

Member What it returns
bool IsListeningToSpeaker { get; } Whether someone is currently speaking to this character
bool IsWaitingForPlayerResponse { get; } Whether this character has finished and is waiting on the player
FaceCueCharacter ListeningTo => null; Optional. The FaceCue character speaking to it, read only while it is listening
FaceCueCharacter AwaitingResponseFrom => null; Optional. The FaceCue character it waits on, read only while it is waiting

This is the interface a dialogue system implements once. It already knows who is talking to whom, and answering these two questions from that is usually a few lines. A shipped example, the simple dialogue state source under Examples, shows the whole of it as two switches a conversation flips.

Two Values, Each Its Own Lane

The two are overridden, released and owned separately. A cutscene can claim the listening lane without touching the waiting one, and each can be held by a different owner.

brain.SetListeningToSpeaker(this, true);
brain.SetWaitingForPlayerResponse(this, false);
Member What it does
void SetListeningToSpeaker(bool value) Claims the anonymous lane
void SetListeningToSpeaker(object owner, bool value) Claims the lane as this owner
bool ReleaseListeningToSpeakerOverride() Gives back the anonymous lane. True when there was one to give back
bool TryReleaseListeningToSpeakerOverride(object owner) Gives the lane back only if this owner still holds it. True when it did
bool ForceClearListeningToSpeakerOverride() Takes the lane back whoever holds it. True when there was an override to clear

WaitingForPlayerResponse has the same five, named the same way (SetWaitingForPlayerResponse, ReleaseWaitingForPlayerResponseOverride and so on). bool ForceClearDialogueStateOverrides() clears both lanes at once.

Naming the Other Character

When the one speaking is another FaceCue character, say which. The character keeps whom it listens to, and your code can read it back.

guard.SetListeningToSpeaker(true, captain);
guard.SetListeningToSpeaker(this, true, captain);   // as this owner
Member What it does
void SetListeningToSpeaker(bool listening, FaceCueCharacter speaker) Claims the anonymous lane, naming the speaker
void SetListeningToSpeaker(object owner, bool listening, FaceCueCharacter speaker) Claims the lane as this owner, naming the speaker
void SetWaitingForPlayerResponse(bool waiting, FaceCueCharacter responder) Claims the anonymous waiting lane, naming whom it waits on
void SetWaitingForPlayerResponse(object owner, bool waiting, FaceCueCharacter responder) The same, as this owner

They are the same lanes as the calls above, released the same way. Pass null when the other one is not a FaceCue character, the player included. A character named alongside false is ignored, since a character that is not listening is not listening to anyone.

An override replaces the source's answer whole. While it is set, the source's character is not read either, so an override that names nobody reports nobody.

A destroyed character reads back as nobody, and the character carries on listening, since your game said it is.

The Listener Context offers every listening and waiting call on this page as well, so code that holds the listener needs nothing else.

Asking About It

Member Tells you
bool IsListeningToSpeaker { get; } The resolved value, override or source
bool IsListeningToSpeakerOverridePresent { get; } Whether an override is masking the source
bool IsListeningToSpeakerOverrideOwner(object owner) Whether this owner holds it
object ListeningToSpeakerOverrideOwner { get; } Who holds it
InputOverrideOwnerKind ListeningToSpeakerOverrideOwnerKind { get; } None, Anonymous or Explicit
bool IsWaitingForPlayerResponse { get; } The resolved value, override or source
bool IsWaitingForPlayerResponseOverridePresent { get; } Whether an override is masking the source
bool IsWaitingForPlayerResponseOverrideOwner(object owner) Whether this owner holds it
object WaitingForPlayerResponseOverrideOwner { get; } Who holds it
InputOverrideOwnerKind WaitingForPlayerResponseOverrideOwnerKind { get; } None, Anonymous or Explicit
FaceCueCharacter ListeningTo { get; } Whom the character listens to, override or source. Null when it is not listening or nobody was named
FaceCueCharacter AwaitingResponseFrom { get; } Whom it waits on. Null when it is not waiting, or waits on the player

On the Listener Context, two more:

Member Tells you
FaceCueCharacter ListeningTo { get; } Whom the character attends to. The one to read when you want to know whom it is listening to
ListeningInput ListeningDecidedBy { get; } What made it listen: DirectCall for your code, DialogueSource for the source, None while it is not listening

Events

event Action<DialogueStateOverrideChange> DialogueStateOverrideChanged fires when either lane's override changes. Its DialogueStateOverrideChange carries:

Field Holds
DialogueStateMember Member Which value changed: ListeningToSpeaker or WaitingForPlayerResponse
InputOverrideTransitionKind Transition Which kind of change. See Sources and Overrides
bool HadPreviousOverride Whether an override was present before
bool PreviousValue What it was
InputOverrideOwnerKind PreviousOwnerKind How it was held before: None, Anonymous or Explicit
object PreviousOwner Who held it before. On a Vacated change this is a destroyed object: compare it, never use it
bool HasCurrentOverride Whether an override is present now
bool CurrentValue What it is now
InputOverrideOwnerKind CurrentOwnerKind How it is held now
object CurrentOwner Who holds it now
FaceCueCharacter PreviousCharacter The character it named before, or null. It may be destroyed: compare it, never use it
FaceCueCharacter CurrentCharacter The character it names now, or null

One event serves both lanes, so check Member first.

Where It Reaches

Into the conversant state, which resolves to Talking, Listening or Idle and is read by the eyes and by breath. What each of those states changes is set out in Speaking and Listening.

Listening Is the Reason This Lane Exists

A character can tell it is Talking from its own audio. It cannot tell it is Listening, because nothing is playing. This lane is how it finds out, and until you wire it up a character will never resolve to Listening at all.