# 39 — BPC_ObjectiveSystem ## Blueprint Spec — UE 5.5–5.7 --- ### Parent Class `ActorComponent` ### Dependencies - Gameplay Tag System - [`BPC_NarrativeStateSystem`](58_BPC_NarrativeStateSystem.md) - [`WBP_ObjectiveDisplay`](../06-ui/35_WBP_InteractionUI.md) (via dispatcher) - [`BPC_JournalSystem`](41_BPC_JournalSystem.md) ### Purpose Tracks active, completed, and failed objectives. Supports main objectives, sub-objectives, hidden objectives, and optional objectives. Acts as the query layer for UI and journal. ### Responsibilities - Activate objectives by tag - Complete / fail objectives by tag or narrative flag trigger - Track objective dependency chains (must complete A before B activates) - Notify UI and journal on changes - Support objectives hidden until discovery condition met - Persist objective state via [`I_Persistable`](../01-core/29_I_Persistable.md) ### Does NOT Handle - What completing an objective does in the world (that is story content) - UI display of objectives (that is `WBP_ObjectiveDisplay`) - Ending condition evaluation ### Variables | Name | Type | Description | |------|------|-------------| | `AllObjectives` | Map (GameplayTag → S_ObjectiveState) | Full objective register | | `ActiveObjectiveTags` | Array of GameplayTag | Currently active objectives | | `CompletedObjectiveTags` | Array of GameplayTag | Completed objectives | | `FailedObjectiveTags` | Array of GameplayTag | Failed objectives | | `ObjectiveOrderPriority` | Array of GameplayTag | Display sort order for UI | ### Enums | Enum | Values | Description | |------|--------|-------------| | `E_ObjectiveStatus` | Inactive, Active, Complete, Failed, Hidden | Objective lifecycle | ### Structs | Struct | Fields | Description | |--------|--------|-------------| | `S_ObjectiveState` | ObjectiveTag: GameplayTag, Status: E_ObjectiveStatus, DisplayText: FText, Description: FText, SubObjectives: Array of S_ObjectiveState, Dependencies: Array of GameplayTag, bIsHidden: Bool, bIsOptional: Bool | Runtime objective state | | `S_ObjectiveDisplayData` | ObjectiveTag: GameplayTag, DisplayText: FText, bIsComplete: Bool, bIsOptional: Bool | Lightweight UI snapshot | ### Functions / Events | Name | Inputs | Outputs | Description | |------|--------|---------|-------------| | `ActivateObjective` | ObjectiveTag: GameplayTag | — | Sets objective Active, checks dependencies | | `CompleteObjective` | ObjectiveTag: GameplayTag | — | Marks complete, broadcasts, unlocks dependents | | `FailObjective` | ObjectiveTag: GameplayTag | — | Marks failed | | `GetActiveObjectives` | — | Array of S_ObjectiveDisplayData | For UI consumption | | `GetCompletedObjectives` | — | Array of GameplayTag | Status check | | `GetFailedObjectives` | — | Array of GameplayTag | Status check | | `IsObjectiveComplete` | ObjectiveTag: GameplayTag | Bool | Single check | | `IsObjectiveActive` | ObjectiveTag: GameplayTag | Bool | Single check | | `RevealHiddenObjective` | ObjectiveTag: GameplayTag | — | Shows previously hidden objective | | `RegisterObjectiveFromDataAsset` | ObjectiveTag: GameplayTag, DataAsset | — | Registers an objective definition from a DA_ObjectiveData | | `CheckDependenciesMet` | ObjectiveTag: GameplayTag | Bool | Returns true if all dependency objectives are complete | | `CollectState` (I_Persistable) | — | S_WorldObjectState | Serializes objective state | | `RestoreState` (I_Persistable) | Data: S_WorldObjectState | — | Deserializes objective state | ### Event Dispatchers | Name | Parameters | Fired When | |------|-----------|-----------| | `OnObjectiveActivated` | ObjectiveTag: GameplayTag, Data: S_ObjectiveDisplayData | New objective added to active list | | `OnObjectiveCompleted` | ObjectiveTag: GameplayTag | Objective marked complete | | `OnObjectiveFailed` | ObjectiveTag: GameplayTag | Objective marked failed | | `OnObjectiveRevealed` | ObjectiveTag: GameplayTag | Hidden objective revealed | | `OnAllObjectivesComplete` | — | All active objectives complete (chapter milestone) | ### Blueprint Flow ``` [ActivateObjective called] └─► Look up objective in AllObjectives map └─► Check Dependencies: │ └─► DependenciesMet? → Set status = Active │ └─► Not met? → Set status = Inactive, wait for dependency completion └─► If Hidden → bIsHidden check └─► Add to ActiveObjectiveTags └─► Broadcast OnObjectiveActivated └─► Notify UI and JournalSystem [CompleteObjective called] └─► Validate objective is currently Active └─► Set status = Complete └─► Move from ActiveObjectiveTags to CompletedObjectiveTags └─► Broadcast OnObjectiveCompleted └─► Check dependent objectives for activation └─► Check if AllObjectivesComplete → broadcast milestone └─► Set narrative flag via BPC_NarrativeStateSystem ``` ### Communications With | Target System | Method | Why | |---------------|--------|-----| | [`BPC_NarrativeStateSystem`](58_BPC_NarrativeStateSystem.md) | Direct + Dispatcher | Flag-driven objective activation / completion | | [`WBP_ObjectiveDisplay`](../06-ui/35_WBP_InteractionUI.md) | Dispatcher | UI updates | | [`WBP_HUDController`](../06-ui/33_WBP_HUD.md) | Dispatcher | Objective display visibility | | [`BPC_JournalSystem`](41_BPC_JournalSystem.md) | Direct | Journal entries on objective events | | [`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. --- ## 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) ### Variable Init (BeginPlay) ``` Event BeginPlay ├─ Set AllObjectives = empty Map ├─ 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` ``` 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