# 42 — BPC_BranchingConsequenceSystem ## Blueprint Spec — UE 5.5–5.7 --- ### Parent Class `ActorComponent` ### Dependencies - [`BPC_NarrativeStateSystem`](58_BPC_NarrativeStateSystem.md) - [`DA_ConsequenceRule`](48_DA_NarrativeDataAssets.md) - [`BPC_ObjectiveSystem`](39_BPC_ObjectiveSystem.md) - [`BPC_DialoguePlaybackSystem`](40_BPC_DialoguePlaybackSystem.md) ### Purpose Evaluates narrative consequences when flags change. Listens for flag changes across the narrative state and fires off deferred or immediate consequences: new dialogue, objective updates, world-state changes, or scene transitions. ### Responsibilities - Watch for flag changes (via dispatcher from `BPC_NarrativeStateSystem`) - Match changed flags against `DA_ConsequenceRule` entries - Execute matched consequence actions (play dialogue, update objective, modify world, trigger cutscene) - Handle priority and stacking for multiple consequences firing simultaneously - Separate immediate vs. delayed consequences (allow narrative beat to breathe) ### Does NOT Handle - Setting flags (that is `BPC_NarrativeStateSystem`) - Playing dialogue lines (that is `BPC_DialoguePlaybackSystem`) - Evaluating choices (that is `BPC_DialogueChoiceSystem`) - Triggering cutscene play (that is `BPC_CutsceneBridge`) ### Variables | Name | Type | Description | |------|------|-------------| | `ConsequenceRules` | Array of DA_ConsequenceRule | Loaded rules from content registry | | `PendingConsequences` | Array of FConsequencePayload | Queue of delayed consequences | | `ActiveConsequenceCount` | Integer | Prevent stacking beyond max | | `MaxConcurrentConsequences` | Integer | Max simultaneous actions (default 3) | ### Structs | Struct | Fields | Description | |--------|--------|-------------| | `FConsequencePayload` | RuleRef: DA_ConsequenceRule, TriggerFlag: GameplayTag, FireTime: Float (world time for delayed), bIsImmediate: Bool | Holds a consequence awaiting execution | ### Enums | Enum | Values | Description | |------|--------|-------------| | `EConsequenceActionType` | PlayDialogue, UpdateObjective, SetWorldState, TriggerCutscene, UnlockLore, ModifyStat, SpawnActor, DestroyActor | Types of actions a consequence can perform | ### Functions / Events | Name | Inputs | Outputs | Description | |------|--------|---------|-------------| | `RegisterConsequenceRule` | Rule: DA_ConsequenceRule | — | Add a rule to active set | | `OnFlagChanged` | FlagTag: GameplayTag, bIsSet: Bool | — | Dispatcher callback from narrative state | | `EvaluateRulesForFlag` | FlagTag: GameplayTag | Array of DA_ConsequenceRule | Find matching rules | | `ExecuteConsequence` | Rule: DA_ConsequenceRule | — | Fire immediate or queue delayed | | `ExecuteImmediateAction` | Action: FConsequenceData | — | Internal: performs single action | | `ProcessDelayedConsequences` | — | — | Called every tick or on timer for delayed queue | | `ClearPendingConsequences` | — | — | Clear all pending (e.g., on scene transition) | | `GetActiveRuleCount` | — | Integer | | ### Data: FConsequenceData (Inline in DA_ConsequenceRule) | Field | Type | Description | |-------|------|-------------| | ActionType | Enum(EConsequenceActionType) | What to do | | TargetTag | GameplayTag | Dialogue sequence, objective, or world flag to apply | | FloatValue | Float | Numeric modifier (e.g., stat change) | | DelaySeconds | Float | 0 = immediate, >0 = delayed | | bBlocking | Bool | If true, wait for this to complete before next | | Priority | Integer | Higher = execute first | ### Event Dispatchers | Name | Parameters | Fired When | |------|-----------|-----------| | `OnConsequenceTriggered` | Rule: DA_ConsequenceRule, ActionType: EConsequenceActionType | Consequence begins execution | | `OnConsequenceCompleted` | Rule: DA_ConsequenceRule | Consequence finished | | `OnConsequenceQueueChanged` | PendingCount: Integer | Delayed queue size changed | ### Blueprint Flow ``` [BPC_NarrativeStateSystem dispatches OnFlagChanged] └─► BPC_BranchingConsequenceSystem.OnFlagChanged(FlagTag, bIsSet) └─► EvaluateRulesForFlag(FlagTag) └─► For each matching DA_ConsequenceRule: └─► Check rule's required flag state matches current state └─► If match → ExecuteConsequence(Rule) [ExecuteConsequence - immediate] └─► Broadcast OnConsequenceTriggered └─► ExecuteImmediateAction(Action) └─► Switch on ActionType: PlayDialogue → request BPC_DialoguePlaybackSystem.PlaySequence(TargetTag) UpdateObjective → request BPC_ObjectiveSystem.AddOrUpdateObjective(...) SetWorldState → BPC_NarrativeStateSystem.SetStateFlag(TargetTag, true) TriggerCutscene → request BPC_CutsceneBridge.BeginCutscene(TargetTag) UnlockLore → BPC_NarrativeStateSystem.UnlockLoreEntry(TargetTag) ModifyStat → through player's stat component SpawnActor → spawn from registry DestroyActor → destroy by tag lookup └─► Broadcast OnConsequenceCompleted [ExecuteConsequence - delayed] └─► Create FConsequencePayload with FireTime = WorldTime + DelaySeconds └─► Add to PendingConsequences array └─► Sort by FireTime └─► Broadcast OnConsequenceQueueChanged ``` ### Communications With | Target System | Method | Why | |---------------|--------|-----| | [`BPC_NarrativeStateSystem`](58_BPC_NarrativeStateSystem.md) | Dispatcher (receives) + Direct (sets world state) | Listens for flag changes, may set additional flags | | [`BPC_DialoguePlaybackSystem`](40_BPC_DialoguePlaybackSystem.md) | Direct | Trigger dialogue sequences as consequences | | [`BPC_ObjectiveSystem`](39_BPC_ObjectiveSystem.md) | Direct | Update/add objectives as consequences | | [`BPC_CutsceneBridge`](44_BPC_CutsceneBridge.md) | Direct | Trigger cutscenes as consequences | | [`BPC_LoreUnlockSystem`](46_BPC_LoreUnlockSystem.md) | Direct | Unlock lore entries | ### Reuse Notes Consequence rules are data-driven via `DA_ConsequenceRule`, enabling designers to author branch logic without blueprint edits. The system supports both immediate and delayed consequences, allowing dramatic pacing. Priority sorting ensures critical consequences fire first. Blocking flag prevents race conditions between sequential narrative beats. --- ## Manual Implementation Guide ### Class Setup 1. Create Blueprint Class: Parent = `ActorComponent`, Name = `BPC_BranchingConsequenceSystem` 2. Add to Player Character ### Variable Init (BeginPlay) ``` Event BeginPlay ├─ Set ConsequenceRules = empty array (loaded from DA_ConsequenceRule registry) ├─ Set PendingConsequences = empty array ├─ Set MaxConcurrentConsequences = 3 └─ Cache: BPC_NarrativeStateSystem, BPC_DialoguePlaybackSystem, BPC_ObjectiveSystem, BPC_CutsceneBridge, BPC_LoreUnlockSystem ``` ### Function Node-by-Node #### `OnFlagChanged(Fage: GameplayTag, NewValue: Boolean)` → `void` *(Bind to NarrativeStateSystem.OnFlagChanged)* ``` Step 1: If NewValue == false → Return (only react to true flags) Step 2: ForEach ConsequenceRules: If Rule.TriggerFlag == Flag: Create FConsequencePayload(RuleRef=Rule, TriggerFlag=Flag, bIsImmediate=Rule.bIsImmediate, FireTime=Now+Delay) If bIsImmediate: Add to pending, call ProcessPendingConsequences Else: Add to PendingConsequences queue with timer ``` #### `ProcessPendingConsequences()` → `void` ``` Step 1: Sort PendingConsequences by Rule.Priority (descending) Step 2: ForEach PendingConsequences (up to MaxConcurrentConsequences): Switch on Rule.ActionType: PlayDialogue → BPC_DialoguePlaybackSystem.PlaySequence(Rule.DialogueSequence) SetObjective → BPC_ObjectiveSystem.ActivateObjective(Rule.ObjectiveTag) UnlockLore → BPC_LoreUnlockSystem.UnlockEntry(Rule.LoreTag) TriggerCutscene → BPC_CutsceneBridge.PlayCutscene(Rule.CutsceneData) SetFlag → BPC_NarrativeStateSystem.SetFlag(Rule.FlagTag, true) GrantItem → BPC_InventorySystem.AddItem(Rule.ItemAsset, 1) Step 3: Remove processed from queue ``` ### Build Checklist - [ ] Create component, add to Player Character - [ ] Bind to BPC_NarrativeStateSystem.OnFlagChanged - [ ] Load DA_ConsequenceRule assets into ConsequenceRules array - [ ] Implement OnFlagChanged: match trigger flag → create payload - [ ] Implement ProcessPendingConsequences with action switch - [ ] Create DA_ConsequenceRule Data Asset type with action enum and fields