# V2 Dialogue Authoring Guide

This guide is the author-facing workflow for Phase 72 dialogue content. It
connects the graph data format, runtime behavior, localization, narrative
importers, and validation gates that protect shipped conversations.

## Source Of Truth

- Tree format contract:
  [DialogueTreeFormat_V2_Contract.json](../../ue/Content/V2/Gameplay/Dialogue/DialogueTreeFormat_V2_Contract.json)
- Runtime contract:
  [DialogueRuntimeEngine_V2_Contract.json](../../ue/Content/V2/Gameplay/Dialogue/DialogueRuntimeEngine_V2_Contract.json)
- Authoring guide contract:
  [DialogueAuthoringGuide_V2_Contract.json](../../ue/Content/V2/Gameplay/Dialogue/DialogueAuthoringGuide_V2_Contract.json)
- Sample tree:
  [asha-storm-market-intro.v2dialogue.json](../../balance/dialogue/trees/asha-storm-market-intro.v2dialogue.json)
- Sample localization:
  [asha-storm-market-intro.v2dialogueloc.json](../../balance/dialogue/localization/asha-storm-market-intro.v2dialogueloc.json)
- Ink fixture:
  [asha-storm-market-route.ink](../../balance/dialogue/importers/asha-storm-market-route.ink)
- Yarn Spinner fixture:
  [asha-storm-market-route.yarn](../../balance/dialogue/importers/asha-storm-market-route.yarn)
- Runtime implementation:
  [V2DialogueRuntime.cpp](../../ue/Source/V2Gameplay/Private/V2DialogueRuntime.cpp)
- Automation spec:
  [DialogueRuntime.spec.cpp](../../ue/Source/V2Tests/Private/Gameplay/DialogueRuntime.spec.cpp)

## Authoring Workflow

1. Choose or create a stable `dialogueId` that starts with `dlg.`.
2. Define participants before writing nodes. Use `speaker.player` for player
   choices and stable NPC ids such as `npc.asha_storm` for authored speakers.
3. Write the conversation as a `*.v2dialogue.json` graph with `text`, `choice`,
   `condition`, `action`, and `random` nodes.
4. Put branching requirements on edge `conditions`, not in prose.
5. Put side effects in `action` nodes or edge `actions` when the side effect
   must happen atomically with a selected transition.
6. Add every player-facing line id to the localization table before review.
7. Run the validation commands in this guide and include the command output in
   the content review.
8. Land tree, localization, imported source, and documentation changes in the
   same review when they are part of one authored conversation.

## Stable Ids

Dialogue content is saved, localized, tested, and analyzed by stable ids. Do not
encode authored order into ids unless that order is permanent.

| Artifact    | Prefix          | Example                                         |
| ----------- | --------------- | ----------------------------------------------- |
| Dialogue    | `dlg.`          | `dlg.asha_storm.market_intro`                   |
| Node        | `n.`            | `n.player_choice`                               |
| Edge        | `e.`            | `e.choice.ask_route`                            |
| Choice      | `choice.`       | `choice.ask_route`                              |
| Line        | `loc.dialogue.` | `loc.dialogue.asha.market_intro.route_response` |
| Subtitle    | `sub.dialogue.` | `sub.dialogue.asha.market_intro.route_response` |
| Participant | `npc.`          | `npc.asha_storm`                                |

If a shipped id needs to change, keep the old id in redirect metadata for the
release that migrates saves and analytics.

## Graph Rules

Every tree starts at `startNodeId` and must reach an explicit terminal text
node. Terminal nodes set `terminal: true` and have no outgoing edges.

Use these node kinds consistently:

| Kind        | Use For                                             |
| ----------- | --------------------------------------------------- |
| `text`      | One speaker line resolved through localization.     |
| `choice`    | Player-authored choice menus from outgoing edges.   |
| `condition` | Silent branching based on game state.               |
| `action`    | Silent side effects before traversal continues.     |
| `random`    | Deterministic weighted variants, never story gates. |

Every non-terminal node needs an outgoing edge. Every node must be reachable
from `startNodeId`, and every reachable node must be able to reach a terminal
node. Condition nodes must also be reachable; otherwise the branch is authored
but untestable. Runtime and CI validation use `AuditDialogueTreeGraph` to report
unreachable nodes, dead ends, missing terminal paths, and unreachable condition
nodes.

## Conditions

Use conditions for game-state facts that determine whether a transition is
available. Supported condition references are:

- `quest_state`
- `inventory_count`
- `relationship_value`
- `time_of_day`
- `player_stat`
- `local_variable`
- `persistent_variable`
- `global_story_variable`
- `choice_history`

Conditions should be specific enough for QA to set up. Prefer a named quest,
item, stat, NPC, or story variable over a generic flag. When two outcomes are
required, author an explicit fallback edge with a lower priority.

## Actions

Actions represent side effects. Supported action references are:

- `set_variable`
- `emit_event`
- `grant_item`
- `modify_relationship`
- `play_animation`
- `spawn_entity`
- `start_quest`

Action nodes are best for visible or story-significant side effects. Edge
actions are reserved for consequences that must be recorded exactly when a
choice is selected.

## Variables And Choice Consequences

Use local variables for state that only matters during the active conversation.
Use persistent NPC variables for per-character memory, and global story
variables for cross-character state. Choice consequences are recorded by
`choiceId` and by `dialogueId.choiceId`, so future conversations can query
whether the player made a previous choice.

## Localization And Voice

All player-facing text uses `loc.dialogue.*` line ids. Tree files reference line
ids; localization tables provide text, voice cues, and subtitle timing per
locale. The source locale is `en-US`.

Voiced text nodes should include both `voiceCue` and `subtitleTimingId`.
Localized voice can be missing during development, but localized subtitle text
must be present for every required line id before content review.

## Text Tags And Display

Inline dialogue tags use square brackets and are stripped before typewriter
display. Supported tag kinds are pause, emotion, emphasis, speed, and event.

Examples:

```text
Hold [pause=0.5][concerned]steady [speed=1.2]now.
```

The typewriter display consumes tag-stripped plain text, reveals by
characters-per-second, supports fast-forward, and can skip directly to the full
line. Author tags for presentation cues, not for branching logic.

## Bark And Priority Usage

Barks are short context-sensitive lines selected by context, required tags,
blocked tags, priority, and cooldown. Use barks for combat, exploration, and
idle responses that do not require graph traversal.

Dialogue priority determines whether queued conversations interrupt the active
conversation. Use `Ambient` for low-stakes barks, `Casual` for optional
conversations, `Standard` for normal authored conversations, `Urgent` for
interruptions that matter immediately, and `Critical` for non-skippable safety
or story-critical moments.

## Ink And Yarn Spinner Imports

Use the importers when writers author in external narrative tools. The supported
subset imports line-based Ink knots and Yarn Spinner title blocks into
`FV2DialogueTree` and `FV2DialogueLocalizationTable`.

Supported metadata tokens:

- `#line:loc.dialogue...`
- `#speaker:npc...`
- `#choice:choice...`
- `#tag:quest`
- `#condition:global_story_variable:story.market_unlocked=true`
- `#action:start_quest:Quest.MarketRoutes=active`

Yarn commands such as `<<set $asked_for_route = true>>` become action nodes. Ink
commands such as `~ set asked_for_route = true` do the same. Jumps and diverts
become graph edges.

## Review Checklist

Before content review, confirm:

- The tree uses schema `v2.dialogue.tree.v1` and `formatVersion: 1`.
- Every node, edge, choice, and line id has the correct prefix.
- Every non-terminal node has an outgoing edge.
- Every node is reachable from `startNodeId`.
- Every reachable node can reach an explicit terminal node.
- Every condition node and condition-bearing edge is reachable.
- Every choice edge has `choiceId`, `choiceLineId`, and `choiceTags`.
- Every random edge has a positive `weight`.
- Every voiced text node has `voiceCue` and `subtitleTimingId`.
- Every required line id is present in the localization table.
- Any imported Ink or Yarn source is committed with the generated tree changes.

## Validation Commands

Run these commands after changing dialogue authoring docs, trees, localization,
imported source, or runtime graph behavior:

```bash
python3 V2/ue/Tools/check-v2-dialogue-authoring-guide.py
python3 V2/ue/Tools/check-v2-dialogue-unit-tests.py
python3 V2/ue/Tools/check-v2-dialogue-narrative-importers.py
python3 V2/ue/Tools/check-v2-dialogue-tree-format.py
python3 V2/ue/Tools/check-v2-dialogue-runtime-engine.py
python3 V2/ue/Tools/check-v2-ci-workflow.py
python3 -m json.tool V2/ue/Content/V2/Gameplay/Dialogue/DialogueAuthoringGuide_V2_Contract.json
python3 -m json.tool V2/ue/Build/Horde/v2-buildgraph-job.json
python3 V2/tools/validate-v2-docs.py
pnpm exec prettier --check V2/docs/modes/dialogue-authoring-guide.md V2/ue/Content/V2/Gameplay/Dialogue/DialogueAuthoringGuide_V2_Contract.json V2/ue/Build/Horde/v2-buildgraph-job.json
```
