# V2 Dialogue Tree Format

`DialogueTreeFormat_V2_Contract.json` defines the Phase 72 dialogue tree data
format for authored conversations. The format is intentionally graph-first:
nodes describe what happens at a point in the conversation, and edges describe
transitions, including the conditions that decide whether a transition is
available.

## Source Of Truth

- Contract:
  `V2/ue/Content/V2/Gameplay/Dialogue/DialogueTreeFormat_V2_Contract.json`
- Sample tree:
  `V2/balance/dialogue/trees/asha-storm-market-intro.v2dialogue.json`
- Localization table:
  `V2/balance/dialogue/localization/asha-storm-market-intro.v2dialogueloc.json`
- Validator: `V2/ue/Tools/check-v2-dialogue-tree-format.py`
- CI workflow: `.github/workflows/v2-build.yml`
- Horde job: `V2/ue/Build/Horde/v2-buildgraph-job.json`

Dialogue tree assets use schema `v2.dialogue.tree.v1`, `formatVersion: 1`, and
stable ids. Dialogue ids start with `dlg.`, node ids start with `n.`, edge ids
start with `e.`, choice ids start with `choice.`, and player-facing line ids
start with `loc.dialogue.`.

## Top Level Shape

Every tree contains these fields:

| Field           | Purpose                                                               |
| --------------- | --------------------------------------------------------------------- |
| `schema`        | Must be `v2.dialogue.tree.v1`.                                        |
| `dialogueId`    | Stable authoring id for save keys, telemetry, imports, and redirects. |
| `formatVersion` | Data format version, starting at `1`.                                 |
| `title`         | Authoring title for editor/search surfaces.                           |
| `startNodeId`   | Node id where traversal begins.                                       |
| `participants`  | Player, NPC, narrator, or system speakers with display line ids.      |
| `variables`     | Local, persistent per-NPC, and global story variable declarations.    |
| `nodes`         | Graph nodes with one of the canonical node kinds.                     |
| `edges`         | Directed transitions between nodes with ordered conditions.           |
| `localization`  | Source locale and required line ids.                                  |
| `voice`         | Voice bank root, cue fields, and subtitle fallback policy.            |
| `metadata`      | Authoring owner, review status, priority, and tags.                   |

## Node Kinds

The canonical node kinds are:

| Kind        | Required fields                           | Runtime meaning                                         |
| ----------- | ----------------------------------------- | ------------------------------------------------------- |
| `text`      | `id`, `kind`, `speakerId`, `lineId`       | Display one localized speaker line.                     |
| `choice`    | `id`, `kind`, `speakerId`, `promptLineId` | Present player choices from outgoing edge metadata.     |
| `condition` | `id`, `kind`, `predicate`                 | Evaluate game-state predicates without displaying text. |
| `action`    | `id`, `kind`, `actions`                   | Run side effects before traversal continues.            |
| `random`    | `id`, `kind`, `seedScope`                 | Pick a deterministic weighted outgoing edge.            |

Terminal text nodes set `terminal: true` and must have no outgoing edges.
Non-terminal nodes must be able to reach a terminal node.

## Edge Transitions

Edges carry the transition contract:

- Required transition fields are `id`, `from`, `to`, `priority`, and
  `conditions`.
- `conditions` is always present. Use an empty array for unconditional edges.
- Lower `priority` edges are considered first when multiple edges are available.
- Edges from a `choice` node also include `choiceId`, `choiceLineId`, and
  `choiceTags`.
- Edges from a `random` node include positive `weight` values.
- Edges may include side-effect `actions` when a transition needs an atomic
  choice consequence.

The first format version supports these condition references: `quest_state`,
`inventory_count`, `relationship_value`, `time_of_day`, `player_stat`,
`local_variable`, `persistent_variable`, `global_story_variable`, and
`choice_history`.

The first format version supports these action references: `set_variable`,
`emit_event`, `grant_item`, `modify_relationship`, `play_animation`,
`spawn_entity`, and `start_quest`.

## Localization And Voice

Authoring uses line ids for player-facing text. Inline English may appear only
in comments, tooling diagnostics, or non-shipping editor previews. Display names
for speakers use line ids as well, so runtime localization can resolve player,
NPC, narrator, and system labels the same way it resolves dialogue lines.

Voiced `text` nodes provide `voiceCue` and `subtitleTimingId`. If a localized
voice cue is missing, the runtime falls back to localized subtitles through the
tree `voice.fallbackPolicy`.

Runtime localization tables use schema `v2.dialogue.localization.v1`. Each table
declares a source locale, repeats every required `loc.dialogue.*` line id for
every shipped locale, and stores per-locale `voiceCue` and `subtitleTimingId`
references for voiced lines. Dialogue runtime code resolves display text by line
id and locale, then falls back to the table source locale when a requested
locale is unavailable.

## Save And History

Save data records stable ids rather than authored order:

- Visit state is keyed by `dialogueId` and node id.
- Player choice history is recorded by `choiceId`.
- Random selections are recorded by edge id for deterministic reload.
- Local variables persist for the active conversation.
- Persistent variables use an NPC or object scope.
- Global story variables use a story scope.

These rules let later Phase 72 tasks implement runtime traversal, conditions,
actions, variables, consequence tracking, localization, and save/load without
changing the tree format.

## Validation

Run these commands after changing the dialogue tree format:

```bash
python3 V2/ue/Tools/check-v2-dialogue-tree-format.py
python3 V2/ue/Tools/check-v2-ci-workflow.py
python3 -m json.tool V2/ue/Content/V2/Gameplay/Dialogue/DialogueTreeFormat_V2_Contract.json
python3 -m json.tool V2/balance/dialogue/trees/asha-storm-market-intro.v2dialogue.json
python3 V2/tools/validate-v2-docs.py
npx prettier --check V2/docs/modes/dialogue-tree-format.md V2/ue/Content/V2/Gameplay/Dialogue/DialogueTreeFormat_V2_Contract.json V2/balance/dialogue/trees/asha-storm-market-intro.v2dialogue.json
```
