Skip to main content

Conversation Policies

Conversation policies control the side effects of entering and leaving a conversation -- what gets paused, what gets blocked, and when a conversation should end.

The system uses five policy interfaces, each responsible for one aspect of conversation lifecycle management.

The five policy types

IConversationEndPolicy

Determines when a player conversation should close for reasons other than reaching an end node. For example, a policy might close the conversation when the player looks away from the NPC for too long.

The built-in implementation is SettingsDrivenConversationEndPolicy, which reads its behaviour from module settings.

IConversationPlayerControlPolicy

Controls whether the player can move and look during a conversation. The built-in implementation is SettingsDrivenConversationPlayerControlPolicy, which reads Disable Player Movement and Disable Player Look from module settings, applying any per-conversation overrides on top.

Blocking is re-evaluated as the conversation moves between nodes, so a conversation can tighten its hold partway through without restarting. Other systems -- the dialogue camera, a cutscene -- can also request blocking while the conversation runs; the player stays blocked until every one of them has released.

The policy decides whether to block. Which player rig actually gets blocked is IPlayerInputBinding's business:

BindingTarget
FirstPersonPlayerInputBindingThe controller shipped with the package. Tried first.
StarterAssetsInputBindingUnity's Starter Assets controller. Fallback.
CompositePlayerInputBindingTries each in turn and uses whichever is present in the scene.

The composite is what gets registered, and it works out which rig is in the current scene rather than assuming one, so a project using either controller works without configuration. To drive a custom controller, register your own IPlayerInputBinding.

IConversationWorldPausePolicy

Controls whether the game world pauses during a player conversation. SettingsDrivenConversationWorldPausePolicy reads its behaviour from module settings, allowing you to toggle world pausing without code changes.

IConversationCursorPolicy

Controls the mouse cursor during conversations. SettingsDrivenConversationCursorPolicy reads its behaviour from module settings:

  • Manage Cursor During Dialogue -- whether the policy should change cursor state at all
  • Show Cursor During Dialogue -- whether the cursor is visible during conversations
  • Cursor Lock Mode During Dialogue -- the lock mode to use (typically None so the player can click options)

On conversation open, the policy shows/locks the cursor as configured. On close, it restores the previous cursor state.

IConversationAgentControlPolicy

Controls whether agents are paused during conversations. This policy uses a multi-registration pattern -- multiple policies can be registered and they are all evaluated through a composite resolver.

Requires CIVIL-AI-SYSTEM

When CIVIL-AI-SYSTEM is installed, the integration layer automatically registers CivilConversationAgentControlPolicy. This policy pauses the agent's CivilAI behaviour tree when a conversation starts and resumes it when the conversation ends. Without CivilAI, a no-op fallback is used and agents continue their non-dialogue activity during conversations.

The resolver pattern

ConversationEndPolicyResolver and ConversationAgentControlPolicyResolver aggregate multi-registered policies into a single composite. This means you can register additional policies alongside the built-in ones without replacing them.

For example, you could register a custom agent control policy that also disables navigation alongside the CivilAI policy that pauses behaviour trees. Both would run.

Conversation overrides

Policies read their behaviour from module settings, which makes it project-wide. Overrides let one conversation depart from that without a custom policy.

Whatever starts the conversation -- a trigger volume, a cutscene -- authors a ConversationOverrides block and pushes it to IConversationOverrideService for the duration. SettingsDrivenConversationEndPolicy, the player control policy, and the cursor policy all consult the override service before falling back to module settings.

Six fields can be overridden:

FieldType
End When Player Stops InteractingConversationOverrideMode
Disable Player MovementConversationOverrideMode
Disable Player LookConversationOverrideMode
Manage CursorConversationOverrideMode
Show CursorConversationOverrideMode
Cursor Lock ModeConversationCursorLockOverride

ConversationOverrideMode has three values: Inherit, Enable, Disable. ConversationCursorLockOverride has Inherit, None, Locked, and Confined.

Inherit is the default on a newly added component, so an override block you have not touched changes nothing. Each field is independent: a cutscene trigger can force the player to stand still while leaving cursor handling exactly as the project configured it.

Pushing and clearing

NameParametersDescription
Pushobject owner, ConversationOverrides overridesRegisters overrides under an owner key.
Clearobject ownerRemoves that owner's overrides.
ClearAllN/ARemoves every override.

The owner key lets two systems push overlapping overrides safely -- each contributes its own fields and clears only its own on the way out.

Push before opening the conversation, and clear when it ends, including on the path where it fails to start. Trigger volumes do both for you.

No-op defaults

Each policy type has a no-op implementation that does nothing. When no specific policy is registered (for example, when running Dialogue standalone without CivilAI), the no-op version is used automatically. This means the system always has valid policies and does not need null checks.

Providing a custom policy

To add a custom policy:

  1. implement the relevant policy interface
  2. register it in a module registrar using RegisterMulti (for agent control and end policies) or Register (for player control and world pause)
  3. the system will pick it up at initialization

Custom registrars should use an order higher than 200 (the dialogue registrar's order) to ensure dialogue services are available.

Practical advice

The default policies work well for most setups. The most common customisation is adjusting the world pause behaviour through module settings rather than writing code.

If you need a conversation that does not pause the world (for example, a quick one-liner exchange), consider configuring this through the policy settings rather than removing the policy entirely.

Reference

Next step

Continue to Input System.