# 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 └─ 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