# 40 — BPC_DialoguePlaybackSystem

## Blueprint Spec — UE 5.5–5.7

---

### Parent Class
`ActorComponent`

### Dependencies
- [`DA_DialogueSequence`](47_DA_NarrativeDataAssets.md) data assets
- [`WBP_SubtitleDisplay`](../06-ui/49_WBP_SubtitleDisplay.md)
- [`BPC_NarrativeStateSystem`](58_BPC_NarrativeStateSystem.md)
- [`BPC_DialogueChoiceSystem`](41_BPC_DialogueChoiceSystem.md)

### Purpose
Manages the playback of dialogue sequences: line queuing, timing, subtitle routing, audio playback, and lip-sync. Serves as the audio/visual delivery layer for all spoken narrative content.

### Responsibilities
- Receive dialogue sequence data from `DA_DialogueSequence`
- Queue lines and play in order with timing
- Trigger subtitle display via dispatcher
- Play voiceover audio
- Fire narrative flags on line completion (if configured in sequence data)
- Pause/interrupt dialogue on player action or external event
- Support skip-to-next-line and full-skip-sequence

### Does NOT Handle
- Choice presentation (that is [`BPC_DialogueChoiceSystem`](41_BPC_DialogueChoiceSystem.md))
- What dialogue plays when (that is level or narrative flow)
- Subtitle styling (that is `WBP_SubtitleDisplay`)

### Variables

| Name | Type | Description |
|------|------|-------------|
| `ActiveSequence` | DA_DialogueSequence | Currently playing sequence asset |
| `LineQueue` | Array of S_DialogueLine | Remaining lines to play |
| `bIsPlaying` | Bool | Dialogue currently active |
| `bIsPaused` | Bool | Dialogue paused |
| `CurrentLineIndex` | Integer | Index in sequence |
| `LineTimer` | TimerHandle | Auto-advance timer |
| `bBlockInputWhilePlaying` | Bool | Suppress player input during dialogue |

### Structs

| Struct | Fields | Description |
|--------|--------|-------------|
| `S_DialogueLine` | SpeakerTag: GameplayTag, LineText: FText, VoiceAudio: USoundBase, Duration: Float, LipSyncData: UAnimSequence, FlagToSetOnComplete: GameplayTag, AnimTag: GameplayTag, bIsChoicePoint: Bool | One dialogue line with metadata |
| `S_DialoguePlaybackOptions` | bCanSkipLine: Bool, bCanSkipSequence: Bool, bShowSubtitles: Bool, SubtitleDelay: Float | Per-sequence playback settings |

### Functions / Events

| Name | Inputs | Outputs | Description |
|------|--------|---------|-------------|
| `PlaySequence` | Sequence: DA_DialogueSequence | — | Loads and begins playback of a dialogue sequence |
| `PlaySequenceWithOptions` | Sequence, Options: S_DialoguePlaybackOptions | — | Play with overrides |
| `QueueSequence` | Sequence | — | Adds sequence to pending queue (for chaining) |
| `PlayNextLine` | — | — | Advances to next line in queue |
| `SkipCurrentLine` | — | — | Ends current line early, plays next |
| `SkipSequence` | — | — | Aborts entire sequence |
| `PauseDialogue` | — | — | Pause audio, hold subtitles |
| `ResumeDialogue` | — | — | Resume from pause |
| `IsDialoguePlaying` | — | Bool | Query |
| `SetSpeakerOverride` | SpeakerTag: GameplayTag | — | Override speaker for accessibility |
| `GetCurrentLine` | — | S_DialogueLine | For UI binding |
| `GetRemainingLineCount` | — | Integer | For UI progress indicator |
| `EnqueueDialogueFromVolume` | OverlapActor | — | Called by trigger volume overlap |

### Event Dispatchers

| Name | Parameters | Fired When |
|------|-----------|-----------|
| `OnDialogueStarted` | SequenceTag: GameplayTag | Sequence begins |
| `OnLineStarted` | Line: S_DialogueLine | New line begins playback |
| `OnLineCompleted` | Line: S_DialogueLine | Line audio finishes |
| `OnSequenceCompleted` | SequenceTag: GameplayTag | Full sequence done |
| `OnDialogueSkipped` | SequenceTag: GameplayTag | Player skipped sequence |
| `OnDialoguePaused` | — | Pause triggered |
| `OnDialogueResumed` | — | Resume triggered |
| `OnChoicePointReached` | Choices: Array of S_DialogueChoice | Sequence reaches a branching point |

### Blueprint Flow

```
[PlaySequence called]
  └─► If bIsPlaying → return (or QueueSequence)
  └─► Set bIsPlaying = true
  └─► Validate sequence conditions (RequiredFlags from DA_DialogueSequence)
  └─► Load line queue from sequence asset
  └─► Broadcast OnDialogueStarted
  └─► Call PlayNextLine

[PlayNextLine]
  └─► Queue empty? → Broadcast OnSequenceCompleted → bIsPlaying = false → return
  └─► Get next S_DialogueLine
  └─► Start LineTimer (Duration)
  └─► Play VoiceAudio
  └─► Broadcast OnLineStarted
  └─► If line has AnimTag → notify ABP via dispatcher
  └─► If line is choice point → hand off to BPC_DialogueChoiceSystem
  └─► Wait for LineTimer or SkipCurrentLine

[OnLineCompleted]
  └─► If line has FlagToSetOnComplete → BPC_NarrativeStateSystem.SetFlag()
  └─► Advance CurrentLineIndex
  └─► Call PlayNextLine
```

### Communications With

| Target System | Method | Why |
|---------------|--------|-----|
| [`WBP_SubtitleDisplay`](../06-ui/49_WBP_SubtitleDisplay.md) | Dispatcher | Show/hide subtitles |
| [`BPC_NarrativeStateSystem`](58_BPC_NarrativeStateSystem.md) | Direct | Set flags on line completion |
| [`BPC_DialogueChoiceSystem`](41_BPC_DialogueChoiceSystem.md) | Dispatcher | Hand off at choice points |
| [`BPC_CameraStateLayer`](../02-player/14_BPC_CameraStateLayer.md) | Dispatcher | Cinematic camera mode for dialogue |
| [`BPC_EmbodimentSystem`](../02-player/13_BPC_EmbodimentSystem.md) | Dispatcher | Gesture animation tags |
| [`GI_GameFramework`](../01-core/04_GI_GameFramework.md) | Direct | Set game phase during dialogue |

### Reuse Notes
`DA_DialogueSequence` data assets hold all content — add new sequences per project without touching this system. Voice audio is optional: sequences work without audio (text-only dialogue). Lip-sync data is per-line and can use audio-driven or procedural lip sync.

---

## Manual Implementation Guide

### Class Setup
1. Create Blueprint Class: Parent = `ActorComponent`, Name = `BPC_DialoguePlaybackSystem`
2. Add to Player Character
3. Define struct `S_DialogueLine`: SpeakerTag, LineText (Text), VoiceAudio (SoundBase), Duration (Float), FlagToSetOnComplete (GameplayTag), bIsChoicePoint (Boolean)

### Variable Init (BeginPlay)
```
Event BeginPlay
  ├─ Set bIsPlaying = false, bIsPaused = false
  ├─ Set LineQueue = empty Array<S_DialogueLine>
  └─ Cache: BPC_NarrativeStateSystem, SS_AudioManager (via Get Game Instance)
```

### Function Node-by-Node

#### `PlaySequence(Sequence: DA_DialogueSequence)` → `void`
```
Step 1: If bIsPlaying → QueueSequence (or return error)
Step 2: Validate RequiredFlags: Sequence.RequiredFlags → HasAllFlags → if false, return
Step 3: Set bIsPlaying = true
Step 4: Load LineQueue from Sequence.Lines array (copy all lines)
Step 5: Set CurrentLineIndex = 0
Step 6: Fire OnDialogueStarted(Sequence.SequenceTag)
Step 7: Call PlayNextLine()
```

#### `PlayNextLine()` → `void`
```
Step 1: If CurrentLineIndex >= LineQueue.Length:
  Fire OnSequenceCompleted → Set bIsPlaying=false → Return
Step 2: CurrentLine = LineQueue[CurrentLineIndex]
Step 3: If CurrentLine.bIsChoicePoint:
  Fire OnChoicePointReached → hand to BPC_DialogueChoiceSystem → pause here
  Return (resume when choice returns NextSequenceTag)
Step 4: Fire OnLineStarted(CurrentLine)
Step 5: If CurrentLine.VoiceAudio valid:
  SS_AudioManager.PlayDialogue(CurrentLine.VoiceAudio)
Step 6: Show subtitle: Fire dispatcher → WBP_SubtitleDisplay.Show(CurrentLine.LineText, SpeakerTag)
Step 7: Set Timer (CurrentLine.Duration) → On timer: Call OnLineCompleted()
```

#### `OnLineCompleted()` → `void`
```
Step 1: If CurrentLine.FlagToSetOnComplete valid:
  BPC_NarrativeStateSystem.SetFlag(FlagToSetOnComplete, true)
Step 2: Fire OnLineCompleted(CurrentLine)
Step 3: Increment CurrentLineIndex
Step 4: Call PlayNextLine()
```

#### `SkipCurrentLine()` → `void`
```
Step 1: Clear LineTimer
Step 2: Stop VoiceAudio if playing
Step 3: Fire OnLineCompleted (skip to next line)
```

### Build Checklist
- [ ] Create BPC_DialoguePlaybackSystem, add to Player Character
- [ ] Define S_DialogueLine struct and DA_DialogueSequence Data Asset
- [ ] Implement PlaySequence with flag validation
- [ ] Implement PlayNextLine with line queue + timer + audio + subtitle
- [ ] Implement choice point handoff to DialogueChoiceSystem
- [ ] Implement SkipCurrentLine/SkipSequence
- [ ] Wire subtitles to WBP_SubtitleDisplay via dispatcher
- [ ] Test: trigger dialogue → lines play sequentially → subtitles show → audio plays