Enhance narrative systems with detailed implementation guides and data-driven structures

- Updated BPC_NarrativeStateSystem with a comprehensive manual implementation guide, including class setup, variable initialization, and function breakdowns.
- Expanded BPC_ObjectiveSystem documentation to include a manual implementation guide and detailed function descriptions.
- Added a manual implementation guide for BPC_DialoguePlaybackSystem, outlining class setup and function nodes.
- Introduced a manual implementation guide for BPC_DialogueChoiceSystem, detailing choice presentation and selection processes.
- Enhanced BPC_BranchingConsequenceSystem documentation with a manual implementation guide for consequence evaluation.
- Updated BPC_TrialScenarioSystem with a manual implementation guide for scenario management.
- Expanded BPC_LoreUnlockSystem documentation to include a manual implementation guide for lore entry management.
- Added a manual implementation guide for BP_NarrativeTriggerVolume, detailing trigger volume setup and action execution.
- Enhanced BPC_EndingAccumulator documentation with a manual implementation guide for ending evaluation.
- Updated BPC_HitReactionSystem with a manual implementation guide for hit reaction management.
- Added a manual implementation guide for BPC_RecoilSystem, detailing recoil application and recovery processes.
- Introduced DT_ProjectTags.csv to define gameplay tags for various systems, enhancing data-driven design capabilities.
This commit is contained in:
Lefteris Notas
2026-05-19 18:48:37 +03:00
parent eeb1bf82c9
commit bec6cb715e
12 changed files with 745 additions and 11 deletions

View File

@@ -111,4 +111,80 @@ None required. Flat Tag maps suffice.
| [`SS_SaveManager`](../05-save/28_SS_SaveManager.md) | [`I_Persistable`](../01-core/29_I_Persistable.md) | Flag persistence across sessions |
### Reuse Notes
The entire system is tag-driven and fully generic. The `Narrative.Flag.*` and `Narrative.Phase.*` namespaces are empty by default — fill them per project with game-specific flags. Add new numeric value types (reputation, corruption, etc.) by simply calling `SetValue` with the appropriate tag. No code/blueprint changes needed.
The entire system is tag-driven and fully generic. The `Narrative.Flag.*` and `Narrative.Phase.*` namespaces are empty by default — fill them per project with game-specific flags. Add new numeric value types (reputation, corruption, etc.) by simply calling `SetValue` with the appropriate tag. No code/blueprint changes needed.
---
## Manual Implementation Guide
### Class Setup
1. Create Blueprint Class: Parent = `ActorComponent`, Name = `BPC_NarrativeStateSystem`
2. Add to Player Character or GameState (if shared)
3. Implement Interface: `I_Persistable`
### Variable Init (BeginPlay)
```
Event BeginPlay
├─ Set NarrativeFlags = empty Map<GameplayTag, Boolean>
├─ Set NarrativeValues = empty Map<GameplayTag, Float>
├─ Set NarrativeHistory = empty Array<GameplayTag>
├─ Set MaxHistorySize = 500
└─ If implementing I_Persistable: register with SS_SaveManager
```
### Function Node-by-Node
#### `SetFlag(Tag: GameplayTag, Value: Boolean)` → `void`
```
Step 1: OldValue = NarrativeFlags.Find(Tag) or false
Step 2: NarrativeFlags.Add(Tag, Value) ← Map Add (overwrites if exists)
Step 3: If Value == true AND OldValue == false:
NarrativeHistory.Add(Tag)
If NarrativeHistory.Length > MaxHistorySize: Remove oldest entry
Step 4: Fire OnFlagChanged(Tag, Value)
Step 5: Notify I_Persistable: Mark dirty for save
```
**Nodes:** `Map Find`, `Map Add`, `Array Add`, `Array Length`, `Remove Index 0`
#### `SetValue(Tag, Value: Float)` → `void`
```
Step 1: NarrativeValues.Add(Tag, Value)
Step 2: Fire OnValueChanged(Tag, Value)
```
#### `GetFlag(Tag)` → `Boolean` *(Pure)*
```
NarrativeFlags.Find(Tag) → if found: return value, else: return false
```
#### `HasAllFlags(Tags: Array<GameplayTag>)` → `Boolean`
```
ForEach Tags:
If GetFlag(ArrayElement) == false → Return false
Return true
```
#### `CollectState()` → `S_WorldObjectState` *(I_Persistable)*
```
Step 1: Create S_WorldObjectState
Step 2: Serialize NarrativeFlags: ForEach → store (Tag, Value) as string pairs in CustomData
Step 3: Serialize NarrativeValues similarly
Step 4: Return struct
```
#### `RestoreState(Data: S_WorldObjectState)` *(I_Persistable)*
```
Step 1: Clear NarrativeFlags, NarrativeValues, NarrativeHistory
Step 2: Parse CustomData → ForEach entry → NarrativeFlags.Add(Tag, BoolValue)
Step 3: Parse values → NarrativeValues.Add(Tag, FloatValue)
```
### Build Checklist
- [ ] Create BPC_NarrativeStateSystem, add to Player Character
- [ ] Define variables: NarrativeFlags (Map), NarrativeValues (Map), NarrativeHistory (Array), MaxHistorySize
- [ ] Implement SetFlag/GetFlag with map operations
- [ ] Implement SetValue/GetValue for numeric values
- [ ] Implement HasAllFlags/HasAnyFlags for batch queries
- [ ] Implement CollectState/RestoreState for I_Persistable
- [ ] Create OnFlagChanged/OnValueChanged event dispatchers
- [ ] Test: call SetFlag → verify OnFlagChanged fires → other systems react

View File

@@ -114,4 +114,75 @@ Tracks active, completed, and failed objectives. Supports main objectives, sub-o
| [`SS_SaveManager`](../05-save/28_SS_SaveManager.md) | [`I_Persistable`](../01-core/29_I_Persistable.md) | Objective state persistence |
### Reuse Notes
Define objectives via `DA_ObjectiveData` data assets (one per objective) that specify display text, dependencies, associated narrative flag, and optional/hidden flags. The objective system reads from these assets at level start. Adding a new objective type (like timed objectives) requires adding an `S_TimedObjective` struct extension and a timer function — no system redesign needed.
Define objectives via `DA_ObjectiveData` data assets (one per objective) that specify display text, dependencies, associated narrative flag, and optional/hidden flags. The objective system reads from these assets at level start. Adding a new objective type (like timed objectives) requires adding an `S_TimedObjective` struct extension and a timer function — no system redesign needed.
---
## Manual Implementation Guide
### Class Setup
1. Create Blueprint Class: Parent = `ActorComponent`, Name = `BPC_ObjectiveSystem`
2. Add to Player Character
3. Define struct `S_ObjectiveState`: ObjectiveTag, Status (E_ObjectiveStatus), DisplayText (Text), Description (Text), bIsHidden (Boolean), bIsOptional (Boolean), Dependencies (Array<GameplayTag>)
### Variable Init (BeginPlay)
```
Event BeginPlay
├─ Set AllObjectives = empty Map<GameplayTag, S_ObjectiveState>
├─ Set ActiveObjectiveTags, CompletedObjectiveTags, FailedObjectiveTags = empty arrays
└─ Get Owner → Cache BPC_NarrativeStateSystem
```
### Function Node-by-Node
#### `RegisterObjectiveFromDataAsset(ObjTag, DataAsset)` → `void`
```
Step 1: Read DA_ObjectiveData fields
Step 2: Create S_ObjectiveState struct:
ObjectiveTag = ObjTag, Status = Inactive
DisplayText = DataAsset.ObjectiveText
Dependencies = DataAsset.PrerequisiteFlags
bIsHidden = (DataAsset.ObjectiveCategory == Hidden)
bIsOptional = DataAsset.bIsOptional
Step 3: AllObjectives.Add(ObjTag, newState)
```
#### `ActivateObjective(ObjTag)` → `void`
```
Step 1: State = AllObjectives.Find(ObjTag) — if not found, return
Step 2: If State.bIsHidden: return (hidden until revealed)
Step 3: Call CheckDependenciesMet(ObjTag) → if not met: set Status=Inactive, return
Step 4: State.Status = Active
Step 5: ActiveObjectiveTags.Add Unique(ObjTag)
Step 6: Fire OnObjectiveActivated(ObjTag, DisplayData)
Step 7: Update GS_CoreGameState.ActiveObjectiveTags
```
#### `CompleteObjective(ObjTag)` → `void`
```
Step 1: Validate Status == Active → if not, return
Step 2: State.Status = Complete
Step 3: Move: ActiveObjectiveTags.Remove(ObjTag) → CompletedObjectiveTags.Add(ObjTag)
Step 4: Fire OnObjectiveCompleted(ObjTag)
Step 5: Set narrative flag: BPC_NarrativeStateSystem.SetFlag(ObjTag, true)
Step 6: Check dependent objectives: ForEach AllObjectives → if Deps include ObjTag → ActivateObjective
```
#### `GetActiveObjectives()` → `Array<S_ObjectiveDisplayData>`
```
Create results array → ForEach ActiveObjectiveTags:
State = AllObjectives.Find(tag)
Create S_ObjectiveDisplayData(Tag, State.DisplayText, false, State.bIsOptional)
Add to results
Return results
```
### Build Checklist
- [ ] Create BPC_ObjectiveSystem, add to Player Character
- [ ] Define E_ObjectiveStatus enum and S_ObjectiveState struct
- [ ] Implement RegisterObjectiveFromDataAsset
- [ ] Implement ActivateObjective with dependency check
- [ ] Implement CompleteObjective with cascading activation
- [ ] Implement GetActiveObjectives for UI binding
- [ ] Sync to GS_CoreGameState.ActiveObjectiveTags
- [ ] Test: register objective → activate → complete → dependent activates

View File

@@ -119,4 +119,75 @@ Manages the playback of dialogue sequences: line queuing, timing, subtitle routi
| [`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.
`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

View File

@@ -104,4 +104,77 @@ Presents branching dialogue choices to the player and routes the selected respon
| [`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.
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

View File

@@ -124,4 +124,55 @@ Evaluates narrative consequences when flags change. Listens for flag changes acr
| [`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.
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

View File

@@ -128,4 +128,61 @@ Manages trial-based gameplay scenarios: combat gauntlets, escape sequences, inve
| Phase 8 AI | Indirect | Spawn/despawn enemy actors by tag |
### Reuse Notes
Scenarios are fully data-driven via `DA_ScenarioData`. Designers configure spawn tags, objective tags, time limits, and cleanup actions without blueprint modifications. Supports mixed scenarios: combat + investigation, timed + untimed, survival + objective.
Scenarios are fully data-driven via `DA_ScenarioData`. Designers configure spawn tags, objective tags, time limits, and cleanup actions without blueprint modifications. Supports mixed scenarios: combat + investigation, timed + untimed, survival + objective.
---
## Manual Implementation Guide
### Class Setup
1. Create Blueprint Class: Parent = `ActorComponent`, Name = `BPC_TrialScenarioSystem`
2. Add to Player Character or GameMode
### Variable Init (BeginPlay)
```
Event BeginPlay
├─ Set ScenarioState = Inactive
└─ Cache: BPC_NarrativeStateSystem, BPC_ObjectiveSystem
```
### Function Node-by-Node
#### `StartScenario(ScenarioData: DA_ScenarioData)` → `void`
```
Step 1: If ScenarioState != Inactive → Return (already running)
Step 2: Set ActiveScenario = ScenarioData, ScenarioState = SetupRunning
Step 3: Create checkpoint via SS_SaveManager (auto-save before trial)
Step 4: Spawn enemies: ForEach ScenarioData.SpawnTags → Spawn Actor from Class at SpawnPoints
Step 5: Lock doors/block exits: ForEach ScenarioData.BlockActor → Set enabled=false
Step 6: If ScenarioData.bShowObjective: ActivateObjective(ScenarioData.ObjectiveTag)
Step 7: Set ScenarioStartTime = Get Game Time
Step 8: ScenarioState = ActiveRunning
Step 9: Fire OnScenarioStarted
```
#### `EvaluateScenario()` → `void` *(Called on Tick or timer)*
```
Step 1: If ScenarioState != ActiveRunning → Return
Step 2: Check success conditions:
If ScenarioData.SuccessFlags: HasAllFlags? → Call OnScenarioSuccess()
If ScenarioData.SuccessKillCount: enemies killed >= count? → Success
Step 3: Check failure conditions:
If ScenarioData.TimeLimit > 0 AND (Now - StartTime) >= TimeLimit → OnScenarioFailure("Time expired")
If player death detected → OnScenarioFailure("Player died")
```
#### `OnScenarioSuccess()` → `void`
```
Step 1: ScenarioState = Success
Step 2: ForEach ScenarioData.SuccessFlags → BPC_NarrativeStateSystem.SetFlag(flag, true)
Step 3: If Objective active: CompleteObjective(ObjectiveTag)
Step 4: Fire OnScenarioCompleted(true)
Step 5: Call CleanupScenario()
```
### Build Checklist
- [ ] Create component with DA_ScenarioData reference
- [ ] Implement StartScenario: setup → spawn → lock → objective → active
- [ ] Implement EvaluateScenario: check win/loss conditions per tick
- [ ] Implement OnScenarioSuccess/Failure with flag setting
- [ ] Implement CleanupScenario: despawn enemies, unlock doors

View File

@@ -135,4 +135,61 @@ Manages the discovery, unlocking, and tracking of lore entries (documents, notes
| [Save System](../04-save/32_SS_SaveManager.md) | Direct (via I_Persistable) | Save unlocked/read state |
### Reuse Notes
Pure data-driven: all lore content is defined in `DA_LoreEntryData` assets. The system requires zero blueprint changes to add new lore entries. Supports any mix of discovery methods (pickup, narrative flag, location trigger, consequence). Lore categories are defined by gameplay tags, allowing flexible grouping without code changes.
Pure data-driven: all lore content is defined in `DA_LoreEntryData` assets. The system requires zero blueprint changes to add new lore entries. Supports any mix of discovery methods (pickup, narrative flag, location trigger, consequence). Lore categories are defined by gameplay tags, allowing flexible grouping without code changes.
---
## Manual Implementation Guide
### Class Setup
1. Create Blueprint Class: Parent = `ActorComponent`, Name = `BPC_LoreUnlockSystem`
2. Add to Player Character
### Variable Init (BeginPlay)
```
Event BeginPlay
├─ Set AllLoreEntries = loaded DA_LoreEntryData array
├─ Set UnlockedLoreTags = empty Set<GameplayTag>
├─ Set ReadLoreTags = empty Set<GameplayTag>
├─ Set TotalLoreCount = AllLoreEntries.Length
└─ Bind to BPC_NarrativeStateSystem.OnFlagChanged → check for lore unlock triggers
```
### Function Node-by-Node
#### `UnlockLoreByTag(LoreTag: GameplayTag)` → `void`
```
Step 1: If UnlockedLoreTags.Contains(LoreTag) → Return (already unlocked)
Step 2: UnlockedLoreTags.Add(LoreTag)
Step 3: Find entry in AllLoreEntries by LoreTag
Step 4: Add to NewLoreQueue for notification
Step 5: Increment TotalUnlockedCount
Step 6: Fire OnLoreUnlocked(LoreTag, EntryData)
Step 7: Show notification: "New lore discovered: {Entry.Title}"
```
#### `MarkLoreAsRead(LoreTag: GameplayTag)` → `void`
```
Step 1: If NOT UnlockedLoreTags.Contains(LoreTag) → Return
Step 2: If NOT ReadLoreTags.Contains(LoreTag):
ReadLoreTags.Add(LoreTag)
Decrement UnreadCount
Fire OnLoreRead(LoreTag)
```
#### `GetLoreByCategory(CategoryTag: GameplayTag)` → `Array<DA_LoreEntryData>` *(Pure)*
```
ForEach AllLoreEntries:
If Entry.CategoryTag == CategoryTag AND UnlockedLoreTags.Contains(Entry.LoreTag):
Add to results
Return results
```
### Build Checklist
- [ ] Create BPC_LoreUnlockSystem, add to Player Character
- [ ] Define DA_LoreEntryData Data Asset (Title, Body, Category, RequiredFlag, LoreTag)
- [ ] Implement UnlockLoreByTag with dedup check
- [ ] Implement MarkLoreAsRead with unread counter
- [ ] Implement category-based filtering for UI
- [ ] Bind to NarrativeStateSystem for flag-triggered unlocks
- [ ] Test: pick up lore item → notification appears → journal entry unlocks

View File

@@ -156,4 +156,45 @@ A level-placed trigger volume that detects player overlap and fires narrative ac
### Reuse Notes
This is the primary level-design tool for narrative gating. Designers place volumes, configure action lists, and set prerequisite flags — no blueprint editing required. Supports all narrative action types. The `CustomEvent` action type allows designers to bind custom level blueprint logic when no predefined action fits.
- Renamed from `47_BPC_NarrativeTriggerVolume` to `BP_NarrativeTriggerVolume` per Master naming convention.
- Renamed from `47_BPC_NarrativeTriggerVolume` to `BP_NarrativeTriggerVolume` per Master naming convention.
---
## Manual Implementation Guide
### Class Setup
1. Create Blueprint Class: Parent = `Actor`, Name = `BP_NarrativeTriggerVolume`
2. Add `BoxComponent` as Root (name: `CollisionBox`)
3. Set Collision Preset = `OverlapOnlyPawn`
### Function Node-by-Node
#### `Event ActorBeginOverlap(OtherActor)` → `void`
```
Step 1: If NOT bIsEnabled → Return
Step 2: Cast OtherActor to Player Character → if fail, Return
Step 3: Check RequiredFlags → if any missing, Return
Step 4: Check ExclusiveFlags → if any set, Return
Step 5: TriggerType == Once AND bHasTriggered? → Return
Step 6: Cooldown active? → Return
Step 7: Call ExecuteActions(TriggerActions)
Step 8: Set bHasTriggered = true, LastTriggerTime = Now
```
#### `ExecuteActions(Actions: Array<FTriggerActionEntry>)` → `void`
```
ForEach Actions → Switch on ActionType:
SetFlag → NarrativeState.SetFlag(Tag, true)
PlayDialogue → DialoguePlayback.PlaySequence(Asset)
PlayCutscene → CutsceneBridge.PlayCutscene(Asset)
ActivateObjective → ObjectiveSystem.ActivateObjective(Tag)
StartTrial → TrialScenario.StartScenario(Asset)
UnlockLore → LoreUnlock.UnlockLoreByTag(Tag)
GrantItem → Inventory.AddItem(Asset, 1)
```
### Build Checklist
- [ ] Create BP_NarrativeTriggerVolume with BoxComponent
- [ ] Define ETriggerActionType enum and FTriggerActionEntry struct
- [ ] Bind ActorBeginOverlap → check conditions → ExecuteActions
- [ ] Test: walk into volume → dialogue plays → flag sets → one-shot prevents re-fire

View File

@@ -133,4 +133,66 @@ Evaluates all narrative flags accumulated throughout gameplay and determines whi
Completely data-driven. Designers create DA_EndingData assets with required flags, exclusive flags, score thresholds, and score entries. The priority system ensures specific endings (e.g., "True Ending") override general ones. The system supports both linear and score-based ending evaluation simultaneously.
- Renamed from `45_BPC_EndingAccumulatorSystem` to `BPC_EndingAccumulator` per Master naming convention.
- Cross-references updated: `BPC_CheckpointSystem``BP_Checkpoint`.
- Cross-references updated: `BPC_CheckpointSystem``BP_Checkpoint`.
---
## Manual Implementation Guide
### Class Setup
1. Create Blueprint Class: Parent = `ActorComponent`, Name = `BPC_EndingAccumulator`
2. Add to Player Character or GameState
### Variable Init (BeginPlay)
```
Event BeginPlay
├─ Set EndingScores = empty Map<GameplayTag, Float>
├─ Load all DA_EndingData assets into EndingDefinitions array
└─ Bind to BPC_NarrativeStateSystem.OnFlagChanged
```
### Function Node-by-Node
#### `OnNarrativeFlagChanged(Flag: GameplayTag, NewValue: Boolean)` → `void`
```
Step 1: If NewValue == false → Return (only accumulate on true flags)
Step 2: ForEach EndingDefinitions:
ForEach Entry in Ending.ScoreEntries:
If Entry.FlagTag == Flag:
EndingScores[Ending.EndingTag] += Entry.Weight
Break inner loop
Step 3: Fire OnEndingScoresUpdated(EndingScores)
```
#### `EvaluateEndings()` → `DA_EndingData`
```
Step 1: QualifiedList = empty array
Step 2: ForEach EndingDefinitions:
If EndingScores[Ending.EndingTag] >= Ending.RequiredScore:
Check Ending.RequiredFlags: all set? → Add to QualifiedList
Check Ending.ExclusiveFlags: any set? → Skip
Step 3: Sort QualifiedList by Priority (descending)
Step 4: Return QualifiedList[0] (highest priority qualified ending)
```
#### `GetQualifiedEndings()` → `Array<DA_EndingData>` *(Pure)*
```
Same logic as EvaluateEndings but returns all qualified, not just best
```
#### `TriggerGameEnding(OverrideTag: GameplayTag)` → `void`
```
Step 1: If OverrideTag valid → SelectedEnding = Find(OverrideTag)
Else: SelectedEnding = EvaluateEndings()
Step 2: Fire OnGameEndingTriggered(SelectedEnding)
Step 3: GM_CoreGameMode.TriggerEnding(SelectedEnding.EndingTag)
→ initiates cutscene, game-over screen, credits
```
### Build Checklist
- [ ] Create BPC_EndingAccumulator
- [ ] Define DA_EndingData with ScoreEntries, RequiredFlags, ExclusiveFlags, RequiredScore, Priority
- [ ] Bind to NarrativeStateSystem.OnFlagChanged → accumulate scores
- [ ] Implement EvaluateEndings with qualification gating
- [ ] Wire to GM_CoreGameMode.TriggerEnding
- [ ] Test: make choices throughout game → check ending scores → trigger end → correct ending plays