# 41 — BPC_DialogueChoiceSystem

## Blueprint Spec — UE 5.5–5.7

---

### Parent Class
`ActorComponent`

### Dependencies
- [`BPC_NarrativeStateSystem`](58_BPC_NarrativeStateSystem.md)
- [`BPC_DialoguePlaybackSystem`](40_BPC_DialoguePlaybackSystem.md)
- [`WBP_DialogueChoiceDisplay`](../06-ui/46_WBP_DialogueChoiceDisplay.md)
- [`DA_DialogueSequence`](48_DA_NarrativeDataAssets.md)

### Purpose
Presents branching dialogue choices to the player and routes the selected response back to the narrative system. Manages choice availability based on narrative flags and time limits.

### Responsibilities
- Receive choice set from dialogue flow (via dispatcher from `BPC_DialoguePlaybackSystem`)
- Filter choices by required flags (only show choices player qualifies for)
- Display choices via `WBP_DialogueChoiceDisplay`
- Apply time limit if configured (auto-select default on expiry)
- Route selected choice tag to `BPC_NarrativeStateSystem`
- Trigger consequence dialogue branches by returning next sequence tag

### Does NOT Handle
- Playing dialogue lines (that is `BPC_DialoguePlaybackSystem`)
- Evaluating narrative consequences beyond setting choice flag (that is `BPC_BranchingConsequenceSystem`)
- UI visual styling (that is `WBP_DialogueChoiceDisplay`)

### Variables

| Name | Type | Description |
|------|------|-------------|
| `CurrentChoices` | Array of S_DialogueChoice | Available options for active choice |
| `DefaultChoiceIndex` | Integer | Auto-selected if timer expires |
| `ChoiceTimeLimit` | Float | Seconds before auto-select (0 = no limit) |
| `ChoiceTimer` | TimerHandle | Countdown timer |
| `bChoiceActive` | Bool | Player is currently choosing |
| `TimeRemaining` | Float | Remaining time for UI display |

### Structs

| Struct | Fields | Description |
|--------|--------|-------------|
| `S_DialogueChoice` | ChoiceText: FText, ResultFlagTag: GameplayTag, NextSequenceTag: GameplayTag, RequiredFlagTag: GameplayTag, bIsHidden: Bool, Priority: Integer, FlavorText: FText (tooltip/thought) | One choice option |

### Functions / Events

| Name | Inputs | Outputs | Description |
|------|--------|---------|-------------|
| `PresentChoices` | Choices: Array of S_DialogueChoice, TimeLimit: Float | — | Opens choice UI and starts timer |
| `SelectChoice` | ChoiceIndex: Integer | — | Player or system selects a choice |
| `GetValidChoices` | Choices: Array of S_DialogueChoice | Array of S_DialogueChoice | Filters choices by RequiredFlagTag against narrative state |
| `HasValidChoices` | Choices: Array | Bool | At least one choice available? |
| `OnChoiceTimedOut` | — | — | Default choice auto-selected |
| `CancelChoice` | — | — | Exits choice without selecting |
| `ProcessSelectedChoice` | Choice: S_DialogueChoice | GameplayTag (NextSequenceTag) | Sets narrative flag and returns next sequence |
| `IsChoiceActive` | — | Bool | Query |

### Event Dispatchers

| Name | Parameters | Fired When |
|------|-----------|-----------|
| `OnChoicesPresented` | Choices: Array of S_DialogueChoice | Choice UI opens |
| `OnChoiceSelected` | SelectedChoice: S_DialogueChoice, ChoiceIndex: Integer | Player makes selection |
| `OnChoiceTimedOut` | DefaultChoiceIndex: Integer | Timer expired |
| `OnChoiceCancelled` | — | Choice dismissed without selection |
| `OnChoiceCompleted` | NextSequenceTag: GameplayTag | Choice processed, ready for next dialogue |

### Blueprint Flow

```
[PresentChoices called]
  └─► Call GetValidChoices (filter by narrative flags)
  └─► If no valid choices → skip (choose default or cancel)
  └─► Set CurrentChoices to valid set
  └─► Set bChoiceActive = true
  └─► Broadcast OnChoicesPresented to WBP_DialogueChoiceDisplay
  └─► If TimeLimit > 0 → start ChoiceTimer

[SelectChoice called]
  └─► Validate ChoiceIndex is in range
  └─► Get selected S_DialogueChoice
  └─► Clear ChoiceTimer
  └─► Broadcast OnChoiceSelected
  └─► Call ProcessSelectedChoice

[ProcessSelectedChoice]
  └─► If ResultFlagTag is valid → BPC_NarrativeStateSystem.SetFlag(ResultFlagTag)
  └─► Set bChoiceActive = false
  └─► Broadcast OnChoiceCompleted with NextSequenceTag
  └─► Hand NextSequenceTag back to BPC_DialoguePlaybackSystem
```

### Communications With

| Target System | Method | Why |
|---------------|--------|-----|
| [`BPC_NarrativeStateSystem`](58_BPC_NarrativeStateSystem.md) | Direct | Set choice flag, check required flags |
| [`BPC_DialoguePlaybackSystem`](40_BPC_DialoguePlaybackSystem.md) | Dispatcher (receives) + Direct (returns) | Receives choice points, returns next sequence |
| [`WBP_DialogueChoiceDisplay`](../06-ui/46_WBP_DialogueChoiceDisplay.md) | Dispatcher | Opens/closes choice UI |
| [`BPC_BranchingConsequenceSystem`](42_BPC_BranchingConsequenceSystem.md) | Dispatcher | Choice flag changes trigger consequence evaluation |

### Reuse Notes
Choice filtering by RequiredFlagTag allows context-sensitive dialogue without branching logic in the system. Choices can be hidden (e.g., secret dialogue options only appear if player has a specific lore unlock). The system handles all choice patterns: timed, untimed, locked, hidden, and priority-sorted.

---

## Manual Implementation Guide

### Class Setup
1. Create Blueprint Class: Parent = `ActorComponent`, Name = `BPC_DialogueChoiceSystem`
2. Add to Player Character
3. Define struct `S_DialogueChoice`: ChoiceText (Text), ResultFlagTag (GameplayTag), NextSequenceTag (GameplayTag), RequiredFlagTag (GameplayTag), Priority (Integer)

### Variable Init (BeginPlay)
```
Event BeginPlay
  ├─ Set CurrentChoices = empty array
  ├─ Set bChoiceActive = false
  ├─ Set ChoiceTimeLimit = 0.0
  └─ Cache: BPC_NarrativeStateSystem, BPC_DialoguePlaybackSystem
```

### Function Node-by-Node

#### `PresentChoices(Choices: Array<S_DialogueChoice>, TimeLimit: Float)` → `void`
```
Step 1: Filtered = GetValidChoices(Choices)  ← filter by narrative flags
Step 2: If Filtered.Length == 0: auto-cancel (or select hidden default)
Step 3: Sort Filtered by Priority (descending)
Step 4: Set CurrentChoices = Filtered
Step 5: Set bChoiceActive = true
Step 6: Fire OnChoicesPresented(CurrentChoices) → WBP_DialogueChoiceDisplay shows UI
Step 7: If TimeLimit > 0:
  Set ChoiceTimeLimit = TimeLimit, TimeRemaining = TimeLimit
  Start looping timer (0.1s):
    TimeRemaining -= 0.1 → update UI
    If TimeRemaining <= 0 → Call OnChoiceTimedOut
```

#### `GetValidChoices(Choices)` → `Array<S_DialogueChoice>`
```
ForEach Choices:
  If Choice.RequiredFlagTag valid:
    Call BPC_NarrativeStateSystem.GetFlag(Choice.RequiredFlagTag)
    If flag is true → Add to results
  Else: Add to results (no requirement)
Return results
```

#### `SelectChoice(ChoiceIndex: Integer)` → `void`
```
Step 1: Validate ChoiceIndex < CurrentChoices.Length
Step 2: Selected = CurrentChoices[ChoiceIndex]
Step 3: Clear ChoiceTimer
Step 4: Fire OnChoiceSelected(Selected, ChoiceIndex)
Step 5: Call ProcessSelectedChoice(Selected)
```

#### `ProcessSelectedChoice(Choice)` → `GameplayTag` (NextSequenceTag)
```
Step 1: If Choice.ResultFlagTag valid:
  BPC_NarrativeStateSystem.SetFlag(Choice.ResultFlagTag, true)
Step 2: Set bChoiceActive = false
Step 3: Fire OnChoiceCompleted(Choice.NextSequenceTag)
Step 4: Return Choice.NextSequenceTag  ← caller (DialoguePlayback) plays this sequence
```

### Build Checklist
- [ ] Create BPC_DialogueChoiceSystem, add to Player Character
- [ ] Define S_DialogueChoice struct
- [ ] Implement PresentChoices with flag filtering + timer
- [ ] Implement GetValidChoices with RequiredFlagTag check
- [ ] Implement SelectChoice with timer clear
- [ ] Implement ProcessSelectedChoice: set flag → return next sequence
- [ ] Wire to WBP_DialogueChoiceDisplay via dispatcher
- [ ] Test: dialogue choice appears → player selects → flag set → next dialogue plays