diff --git a/docs/blueprints/01-core/BP_CoreGameMode.asset.md b/docs/blueprints/01-core/BP_CoreGameMode.asset.md new file mode 100644 index 0000000..ab73868 --- /dev/null +++ b/docs/blueprints/01-core/BP_CoreGameMode.asset.md @@ -0,0 +1,71 @@ +# BP_CoreGameMode — Asset Implementation + +> **UE5 Asset:** `/Game/Framework/Core/BP_CoreGameMode` +> **Parent Class:** `GM_CoreGameMode` (C++) or `GameModeBase` +> **Asset Type:** Blueprint Class (GameMode) + +--- + +## Create This Asset + +### Step 1: Create Blueprint +1. Content Browser → `Content/Framework/Core/` +2. Right-click → **Blueprint Class** +3. Parent: `GM_CoreGameMode` (C++) OR `GameModeBase` +4. Name: `BP_CoreGameMode` + +### Step 2: Set as Default GameMode +**Project Settings → Maps & Modes → Default GameMode** → `BP_CoreGameMode` + +### Step 3: Configure Class Defaults +| Variable | Type | Value | +|----------|------|-------| +| `GameState Class` | `AGS_CoreGameState` | `BP_CoreGameState` | +| `Player Controller Class` | `APlayerController` | Your `BP_CorePlayerController` | +| `Default Pawn Class` | `APawn` | Your GASP player pawn | +| `HUD Class` | `AHUD` | `WBP_HUDController` | + +--- + +## What to Wire + +### Function: TransitionToChapter +``` +Input: ChapterTag (GameplayTag) + +[BlueprintCallable] + ├─ Branch: CurrentGamePhase == Loading? + │ True → Print Warning: "Already loading" → Return + ├─ Set CurrentChapterTag = ChapterTag + ├─ Switch HasAuthority → True: + │ ├─ Get GameInstance → Cast to GI_GameFramework + │ ├─ SetGamePhase(Loading) + │ ├─ Get GameState → Cast to GS_CoreGameState → SetChapter(ChapterTag) + │ ├─ Open Level (by ChapterTag mapping — use Data Asset lookup) + │ └─ On level loaded → SetGamePhase(InGame) + └─ Call OnChapterTransition(ChapterTag) +``` + +### Function: HandlePlayerDead +``` +Input: DeadController (AController) + +[BlueprintCallable] + ├─ IsValid(DeadController)? → False: Return + ├─ Set bPauseAllowed = false + ├─ Get GameInstance → Cast to GI_GameFramework → SetGamePhase(DeathLoop) + └─ TODO: Route to respawn or AltDeathSpace +``` + +### Event Dispatchers to Create +| Dispatcher | Parameters | +|------------|-----------| +| `OnChapterTransition` | `NewChapter` (GameplayTag) | +| `OnGameOverTriggered` | `EndingTag` (GameplayTag) | + +--- + +## Test It +- [ ] PIE: check output log for "GM_CoreGameMode::InitGame" +- [ ] Check that player spawns with correct pawn +- [ ] Call `TransitionToChapter` → phase changes to Loading → level loads diff --git a/docs/blueprints/01-core/BP_CoreGameState.asset.md b/docs/blueprints/01-core/BP_CoreGameState.asset.md new file mode 100644 index 0000000..599838a --- /dev/null +++ b/docs/blueprints/01-core/BP_CoreGameState.asset.md @@ -0,0 +1,88 @@ +# BP_CoreGameState — Asset Implementation + +> **UE5 Asset:** `/Game/Framework/Core/BP_CoreGameState` +> **Parent Class:** `GS_CoreGameState` (C++) or `GameStateBase` +> **Asset Type:** Blueprint Class (GameState) + +--- + +## Create This Asset + +### Step 1: Create Blueprint +1. Content Browser → `Content/Framework/Core/` +2. Right-click → **Blueprint Class** +3. Parent: `GS_CoreGameState` (C++) OR `GameStateBase` +4. Name: `BP_CoreGameState` + +### Step 2: Assign in GameMode +Open `BP_CoreGameMode` → Class Defaults → `GameState Class` → `BP_CoreGameState` + +--- + +## What to Wire + +### Variables (if BP-only GameStateBase) + +| Variable | Type | Replication | Default | +|----------|------|-------------|---------| +| `ElapsedPlayTime` | `Float` | Replicated | `0.0` | +| `ActiveChapterTag` | `GameplayTag` | Replicated | Empty | +| `ActiveNarrativePhase` | `GameplayTag` | Replicated | Empty | +| `bEncounterActive` | `Boolean` | Replicated | `false` | +| `ActiveObjectiveTags` | `Array` | Replicated | Empty | + +### Override: BeginPlay +``` +[Event BeginPlay] + ├─ Parent: BeginPlay + ├─ Get GameInstance → Cast to GI_GameFramework → Store as CachedFramework + └─ Enable Tick +``` + +### Override: Tick +``` +[Event Tick] + ├─ IsValid(CachedFramework)? AND CurrentGamePhase == InGame? + │ True → ElapsedPlayTime += DeltaSeconds + │ ├─ TimeUpdateAccumulator += DeltaSeconds + │ └─ Accumulator >= 1.0? + │ ├─ Reset accumulator + │ └─ Call OnElapsedPlayTimeUpdated(ElapsedPlayTime) +``` + +### Function: SetChapter +``` +Input: ChapterTag (GameplayTag) +[Server-only] + ├─ If ChapterTag == ActiveChapterTag → Return + ├─ Set ActiveChapterTag = ChapterTag + └─ Call OnChapterChanged(ChapterTag) +``` + +### Function: AddObjective / RemoveObjective +``` +AddObjective(ObjectiveTag): + ├─ If already in array → Return + ├─ Add to ActiveObjectiveTags + └─ Call OnObjectiveTagsChanged + +RemoveObjective(ObjectiveTag): + ├─ Remove from array + └─ Call OnObjectiveTagsChanged +``` + +### Event Dispatchers to Create +| Dispatcher | Parameters | +|------------|-----------| +| `OnElapsedPlayTimeUpdated` | `ElapsedSeconds` (Float) | +| `OnChapterChanged` | `NewChapter` (GameplayTag) | +| `OnNarrativePhaseChanged` | `NewPhase` (GameplayTag) | +| `OnEncounterActiveStateChanged` | `bActive` (Boolean) | +| `OnObjectiveTagsChanged` | (none) | + +--- + +## Test It +- [ ] PIE: check that GS_CoreGameState spawns +- [ ] Call SetChapter → OnChapterChanged fires → HUD updates +- [ ] Call AddObjective → OnObjectiveTagsChanged fires → objective list refreshes diff --git a/docs/blueprints/01-core/BP_GameFramework.asset.md b/docs/blueprints/01-core/BP_GameFramework.asset.md new file mode 100644 index 0000000..232f88a --- /dev/null +++ b/docs/blueprints/01-core/BP_GameFramework.asset.md @@ -0,0 +1,78 @@ +# BP_GameFramework — Asset Implementation + +> **UE5 Asset:** `/Game/Framework/Core/BP_GameFramework` +> **Parent Class:** `GI_GameFramework` (C++) or `GameInstance` (BP-only) +> **Asset Type:** Blueprint Class (GameInstance) + +--- + +## Create This Asset + +### Step 1: Create Blueprint +1. Content Browser → `Content/Framework/Core/` +2. Right-click → **Blueprint Class** +3. Parent: `GI_GameFramework` (C++) OR `GameInstance` +4. Name: `BP_GameFramework` + +### Step 2: Set as Game Instance Class +**Project Settings → Maps & Modes → Game Instance Class** → `BP_GameFramework` + +### Step 3: Configure Class Defaults +| Variable | Type | Value | +|----------|------|-------| +| `TagRegistry` | `DA_GameTagRegistry` | Assign `DA_GameTagRegistry` asset | +| `bValidateTagsOnInit` | `Boolean` | `true` | +| `bLogTagsOnInit` | `Boolean` | `true` (dev) / `false` (ship) | + +--- + +## What to Wire + +### Override: Event Init +``` +[Event Init] + ├─ Parent: Event Init + ├─ Print String: "BP_GameFramework: Init started" + ├─ Branch: bValidateTagsOnInit? + │ True → Call ValidateFrameworkTags (see below) + ├─ IsValid(TagRegistry)? → Branch + │ False → Print Error → Call OnFrameworkInitFailed("TagRegistry not assigned") + │ True → + │ ├─ Set bFrameworkInitialized = true + │ ├─ Call OnFrameworkReady + │ └─ Print String: "Framework ready" +``` + +### Function: ValidateFrameworkTags +``` +[BlueprintCallable, Private] + ├─ IsValid(TagRegistry)? → Branch + │ False → Print Error → Return + ├─ TagRegistry → GetAllRegisteredTags → AllTags + ├─ Array Length(AllTags) → TagCount + ├─ Branch: TagCount == 0? + │ True → Print Warning: "No Gameplay Tags registered!" + │ False → Print: "{TagCount} tags registered" + ├─ Branch: bLogTagsOnInit? + │ True → TagRegistry → LogAllTags + └─ Return +``` + +### Function: IsFrameworkReady +``` +[BlueprintPure, Public] → Boolean + └─ Return bFrameworkInitialized +``` + +### Event Dispatchers to Create +| Dispatcher | Parameters | +|------------|-----------| +| `OnFrameworkReady` | (none) | +| `OnFrameworkInitFailed` | `ErrorReason` (String) | + +--- + +## Test It +- [ ] PIE: output log shows "Framework ready" and tag count +- [ ] Clear TagRegistry variable → PIE → `OnFrameworkInitFailed` fires +- [ ] Set `bLogTagsOnInit = true` → all tag names printed to log diff --git a/docs/blueprints/01-core/DA_GameTagRegistry.asset.md b/docs/blueprints/01-core/DA_GameTagRegistry.asset.md new file mode 100644 index 0000000..65d7a07 --- /dev/null +++ b/docs/blueprints/01-core/DA_GameTagRegistry.asset.md @@ -0,0 +1,68 @@ +# DA_GameTagRegistry — Asset Implementation + +> **UE5 Asset:** `/Game/Framework/Core/DA_GameTagRegistry` +> **Parent Class:** `DA_GameTagRegistry` (C++) or `PrimaryDataAsset` (BP-only) +> **Asset Type:** Data Asset + +--- + +## Create This Asset + +### Step 1: Create Data Asset +1. Content Browser → `Content/Framework/Core/` +2. Right-click → **Miscellaneous → Data Asset** +3. Class: `DA_GameTagRegistry` (if C++ compiled) OR `PrimaryDataAsset` +4. Name: `DA_GameTagRegistry` + +### Step 2: Configure Class Defaults (if BP-only PrimaryDataAsset) +| Variable | Type | Value | +|----------|------|-------| +| `TagNamespace` | `Text` | `"Framework tag namespace documentation"` | +| `bIsFrameworkTag` | `Boolean` | `true` | +| `TagDataTables` | `Array` | Add all 11 DT_Tags_* tables | + +### Step 3: Assign to GameInstance +Open `BP_GameFramework` → Class Defaults → `TagRegistry` → assign `DA_GameTagRegistry` + +--- + +## What to Wire (BP-Only Version) + +### Function: GetAllRegisteredTags +``` +Inputs: none → Output: Array + +[Pure Function Graph] + ├─ Make Array → LocalTags + ├─ ForEachLoop (TagDataTables) + │ ├─ Branch: IsValid(Array Element)? + │ │ True → Get Data Table Row Names + │ │ └─ ForEachLoop (RowNames) + │ │ └─ Get Data Table Row → Break GameplayTagTableRow → Tag + │ │ └─ ADD to LocalTags + └─ Return LocalTags +``` + +### Function: ValidateTag +``` +Input: Tag (GameplayTag) → Output: Boolean + +[Pure Function Graph] + └─ Is Gameplay Tag Valid(Tag) → Return +``` + +### Function: GetTagDisplayName +``` +Input: Tag (GameplayTag) → Output: Text + +[Pure Function Graph] + └─ Get Tag Display Name(Tag) → Return +``` + +--- + +## Test It +- [ ] Open `DA_GameTagRegistry` → verify `TagDataTables` has 11 entries +- [ ] PIE: output log shows `"N tags registered across 11 Data Tables"` +- [ ] Call `ValidateTag(Framework.Player.State.Alive)` → returns `true` +- [ ] Call `ValidateTag(Unregistered.Tag)` → returns `false` diff --git a/docs/blueprints/01-core/DT_Tags_All.asset.md b/docs/blueprints/01-core/DT_Tags_All.asset.md new file mode 100644 index 0000000..7151587 --- /dev/null +++ b/docs/blueprints/01-core/DT_Tags_All.asset.md @@ -0,0 +1,59 @@ +# DT_Tags_* — Data Tables (11 assets) + +> **UE5 Assets:** `Content/Framework/Core/DataTables/DT_Tags_{Category}` +> **Row Structure:** `GameplayTagTableRow` +> **Count:** 11 tables + +--- + +## Create These Assets + +### Step 1: Create All 11 Data Tables +For each category below, repeat this process: + +1. Content Browser → `Content/Framework/Core/DataTables/` +2. Right-click → **Miscellaneous → Data Table** +3. Row Structure: `GameplayTagTableRow` +4. Name: `DT_Tags_{Category}` +5. Right-click the Data Table → **Import** → select the CSV file from `docs/blueprints/01-core/data-tables/DT_Tags_{Category}.csv` + +### The 11 Tables + +| # | Data Table | CSV Source | Namespaces | +|---|-----------|------------|------------| +| 1 | `DT_Tags_Player` | `DT_Tags_Player.csv` | Player.State, Stress, Posture, Movement, Camera, Body, Overlay, Vitals | +| 2 | `DT_Tags_Interaction` | `DT_Tags_Interaction.csv` | Interaction.Type, Context, Prompt, HidingSpot, Traversal, Door | +| 3 | `DT_Tags_Item` | `DT_Tags_Item.csv` | Item.Type, Slot, Rarity, Context | +| 4 | `DT_Tags_Narrative` | `DT_Tags_Narrative.csv` | Narrative.Flag, Phase, Choice, Ending, Trial, Cutscene, Lore, Objective | +| 5 | `DT_Tags_AI` | `DT_Tags_AI.csv` | AI.Alert, Archetype, Stimulus, Behavior, Memory | +| 6 | `DT_Tags_Save` | `DT_Tags_Save.csv` | Save, DeathSpace, Checkpoint, Respawn, RunHistory | +| 7 | `DT_Tags_Environment` | `DT_Tags_Environment.csv` | Environment.Atmosphere, Scare, Light, Pacing, Performance | +| 8 | `DT_Tags_Combat` | `DT_Tags_Combat.csv` | Combat.Damage, Weapon, Ammo, FireMode, HitReaction, Feedback, Shield | +| 9 | `DT_Tags_State` | `DT_Tags_State.csv` | State.Action, Overlay, Vital, Gating | +| 10 | `DT_Tags_Audio` | `DT_Tags_Audio.csv` | Audio.Bus, Room, Parameter, Surface | +| 11 | `DT_Tags_Achievement` | `DT_Tags_Achievement.csv` | Achievement | + +### Step 2: Register All Tables with Engine +**⚠️ CRITICAL — Without this, NO tags are recognized!** + +1. **Project Settings → GameplayTags → Gameplay Tag Table List** +2. Click `+` 11 times +3. Assign each `DT_Tags_*` Data Table to a slot +4. Restart editor (or recompile Blueprints) to refresh tag cache + +### CSV Format +Each CSV has 3 columns: +``` +Name,Tag,DevComment +Alive,"Framework.Player.State.Alive","Player is alive" +Dead,"Framework.Player.State.Dead","Player is dead" +... +``` + +--- + +## Test It +- [ ] Open `DA_GameTagRegistry` → call `GetAllRegisteredTags()` → returns ~334 tags +- [ ] Make Literal Gameplay Tag → type `Framework.Player.State.Alive` → recognized (not red) +- [ ] `Is Gameplay Tag Valid(Framework.Player.State.Alive)` → `true` +- [ ] `Is Gameplay Tag Valid(Fake.Tag)` → `false` diff --git a/docs/blueprints/02-player/BPC_HealthSystem.asset.md b/docs/blueprints/02-player/BPC_HealthSystem.asset.md new file mode 100644 index 0000000..fc0f5cf --- /dev/null +++ b/docs/blueprints/02-player/BPC_HealthSystem.asset.md @@ -0,0 +1,98 @@ +# BPC_HealthSystem — Asset Implementation + +> **UE5 Asset:** `/Game/Framework/Player/BPC_HealthSystem` +> **Parent Class:** `ActorComponent` +> **Attach To:** Player pawn + Enemy pawns + +--- + +## Create This Asset + +1. Content Browser → `Content/Framework/Player/` +2. Right-click → **Blueprint Class** → Parent: `ActorComponent` +3. Name: `BPC_HealthSystem` + +--- + +## Variables to Add + +| Variable | Type | Default | Category | +|----------|------|---------|----------| +| `MaxHealth` | `Float` | `100.0` | Config | +| `CurrentHealth` | `Float` | `100.0` | State | +| `bIsDead` | `Boolean` | `false` | State | +| `DamageResistance` | `Float` | `0.0` | Config | +| `bCanHeal` | `Boolean` | `true` | Config | +| `HealthRegenRate` | `Float` | `0.0` | Config | +| `HealthRegenDelay` | `Float` | `5.0` | Config | +| `LastDamageTime` | `Float` | `0.0` | State | + +--- + +## What to Wire + +### Override: BeginPlay +``` +[Event BeginPlay] + ├─ Set CurrentHealth = MaxHealth + └─ Enable Tick (if regen > 0) +``` + +### Function: ApplyDamage +``` +Input: DamageAmount(Float), DamageCauser(AActor), DamageType(GameplayTag) + +[BlueprintCallable] + ├─ Branch: bIsDead? → True: Return 0 + ├─ Calculate: EffectiveDamage = DamageAmount * (1.0 - DamageResistance) + ├─ Set CurrentHealth = FMax(CurrentHealth - EffectiveDamage, 0) + ├─ Set LastDamageTime = GetGameTimeInSeconds + ├─ Call OnHealthChanged(CurrentHealth, MaxHealth, -EffectiveDamage) + ├─ Branch: CurrentHealth <= 0? + │ True → Set bIsDead = true → Call OnDeath(DamageCauser) + └─ Return EffectiveDamage +``` + +### Function: Heal +``` +Input: HealAmount(Float) + +[BlueprintCallable] + ├─ Branch: bIsDead? → True: Return 0 + ├─ Branch: Not bCanHeal? → True: Return 0 + ├─ Calculate: ActualHeal = FMin(HealAmount, MaxHealth - CurrentHealth) + ├─ Set CurrentHealth += ActualHeal + ├─ Call OnHealthChanged(CurrentHealth, MaxHealth, ActualHeal) + └─ Return ActualHeal +``` + +### Override: Tick +``` +[Event Tick] + ├─ Branch: bIsDead OR HealthRegenRate <= 0 → Return + ├─ Branch: (GameTime - LastDamageTime) < HealthRegenDelay → Return + ├─ Heal(HealthRegenRate * DeltaSeconds) +``` + +### Event Dispatchers to Create +| Dispatcher | Parameters | +|------------|-----------| +| `OnHealthChanged` | `Current` (Float), `Max` (Float), `Delta` (Float) | +| `OnDeath` | `Killer` (AActor) | +| `OnHealed` | `Amount` (Float), `Healer` (AActor) | +| `OnDamageReceived` | `Amount` (Float), `Causer` (AActor), `Type` (GameplayTag) | + +--- + +## Attach to Pawn +1. Open player pawn Blueprint +2. **Add Component → BPC_HealthSystem** +3. Optionally adjust `MaxHealth`, `DamageResistance` in Details panel + +--- + +## Test It +- [ ] PIE: check BeginPlay → CurrentHealth = 100 +- [ ] Call ApplyDamage(25) → health drops to 75 → OnHealthChanged fires +- [ ] Call Heal(10) → health rises to 85 → OnHealed fires +- [ ] Call ApplyDamage(100) → death → OnDeath fires → bIsDead = true diff --git a/docs/blueprints/02-player/BPC_PlayerComponents_All.asset.md b/docs/blueprints/02-player/BPC_PlayerComponents_All.asset.md new file mode 100644 index 0000000..3c3eb43 --- /dev/null +++ b/docs/blueprints/02-player/BPC_PlayerComponents_All.asset.md @@ -0,0 +1,138 @@ +# BPC_StaminaSystem / BPC_StressSystem / BPC_MovementStateSystem +# BPC_HidingSystem / BPC_EmbodimentSystem / BPC_CameraStateLayer / BPC_PlayerMetricsTracker +# +# Player Component Assets — Quick Creation Sheet (7 components) + +> **UE5 Path:** `Content/Framework/Player/` +> **Parent Class:** `ActorComponent` +> **Attach To:** Player pawn + +--- + +## Quick Creation — All 7 Components + +For each component below: +1. Content Browser → `Content/Framework/Player/` +2. Right-click → **Blueprint Class** → Parent: `ActorComponent` +3. Name: as listed +4. Attach to player pawn Blueprint via **Add Component** + +--- + +## BPC_StaminaSystem + +| Variable | Type | Default | +|----------|------|---------| +| `MaxStamina` | Float | `100.0` | +| `CurrentStamina` | Float | `100.0` | +| `SprintDrainRate` | Float | `10.0` | +| `StaminaRegenRate` | Float | `5.0` | +| `ExhaustionThreshold` | Float | `10.0` | +| `bExhausted` | Boolean | `false` | + +**Key Functions:** `ConsumeStamina(Amount)`, `IsExhausted()` + +**Dispatchers:** `OnStaminaChanged`, `OnExhaustionStateChanged` + +--- + +## BPC_StressSystem + +| Variable | Type | Default | +|----------|------|---------| +| `CurrentStress` | Float | `0.0` | +| `StressDecayRate` | Float | `1.0` | +| `StressTier` | Enum (E_PlayerVitalSignals) | `Calm` | + +**Key Functions:** `AddStress(Amount, Source)`, `GetStressTier()` + +**Dispatchers:** `OnStressChanged`, `OnStressTierChanged(Tier)` + +**Stress Tiers:** Calm → Tense → Anxious → Fearful → Catatonic + +--- + +## BPC_MovementStateSystem + +| Variable | Type | Default | +|----------|------|---------| +| `CurrentMovementMode` | GameplayTag | `Framework.Player.Movement.Standing` | +| `CurrentPosture` | GameplayTag | `Framework.Player.Posture.Standing` | +| `bIsSprinting` | Boolean | `false` | +| `bIsCrouching` | Boolean | `false` | + +**Key Functions:** `SetMovementMode(Tag)`, `SetPosture(Tag)`, `GetMovementIntensity()` + +**Dispatchers:** `OnMovementModeChanged`, `OnPostureChanged` + +**GASP Liaison:** This component updates GASP variables — never modify GASP directly. + +--- + +## BPC_HidingSystem + +| Variable | Type | Default | +|----------|------|---------| +| `CurrentHideState` | GameplayTag | `Framework.Player.State.Exposed` | +| `bIsPeeking` | Boolean | `false` | +| `bIsHoldingBreath` | Boolean | `false` | +| `BreathHoldMax` | Float | `8.0` | +| `BreathHoldCurrent` | Float | `8.0` | + +**Key Functions:** `EnterHide(HidingSpot)`, `ExitHide()`, `Peek()`, `HoldBreath()` + +**Dispatchers:** `OnHideStateChanged`, `OnBreathHoldChanged` + +--- + +## BPC_EmbodimentSystem + +| Variable | Type | Default | +|----------|------|---------| +| `bFirstPersonBodyVisible` | Boolean | `true` | +| `bArmsOnlyMode` | Boolean | `false` | +| `BodyMesh` | SkeletalMesh | (assign) | + +**Key Functions:** `SetBodyVisibility(bVisible)`, `SetArmsOnlyMode(bActive)` + +**Dispatchers:** `OnEmbodimentModeChanged` + +--- + +## BPC_CameraStateLayer + +| Variable | Type | Default | +|----------|------|---------| +| `BaseFOV` | Float | `90.0` | +| `CurrentFOV` | Float | `90.0` | +| `FOVSmoothSpeed` | Float | `5.0` | +| `CameraOffset` | Vector | `(0,0,0)` | + +**Key Functions:** `SetFOVOverride(Tag, FOV)`, `ClearFOVOverride(Tag)`, `SetCameraOffset(Tag, Offset)` + +**Dispatchers:** `OnFOVChanged`, `OnCameraOffsetChanged` + +--- + +## BPC_PlayerMetricsTracker + +| Variable | Type | Default | +|----------|------|---------| +| `TotalShotsFired` | Integer | `0` | +| `TotalShotsHit` | Integer | `0` | +| `TotalDeaths` | Integer | `0` | +| `TotalKills` | Integer | `0` | +| `Accuracy` | Float | `0.0` | +| `KDRatio` | Float | `0.0` | + +**Key Functions:** `RecordShot(bHit)`, `RecordDeath()`, `RecordKill()`, `GetAccuracy()` + +**Dispatchers:** `OnMetricsUpdated` + +--- + +## Test All Components +- [ ] All 7 components visible on player pawn +- [ ] BeginPlay sets default values correctly +- [ ] Each dispatcher fires when its state changes +- [ ] Components don't conflict (Stamina drain doesn't affect Stress directly — let StateManager coordinate) diff --git a/docs/blueprints/03-interaction/InteractionAssets_All.asset.md b/docs/blueprints/03-interaction/InteractionAssets_All.asset.md new file mode 100644 index 0000000..8d2e28e --- /dev/null +++ b/docs/blueprints/03-interaction/InteractionAssets_All.asset.md @@ -0,0 +1,129 @@ +# Interaction Systems — Asset Creation Sheet (8 assets) + +> **UE5 Path:** `Content/Framework/Interaction/` + +--- + +## BPC_InteractionDetector (Component) + +**Parent:** `ActorComponent` → Attach to player pawn + +| Variable | Type | Default | +|----------|------|---------| +| `InteractionRange` | Float | `300.0` | +| `InteractionChannel` | TraceChannel | `Visibility` | +| `HoldDuration` | Float | `0.5` | +| `CurrentFocusedActor` | Actor | None | + +**Key Logic:** +``` +Tick → LineTraceByChannel(Camera Forward * Range) + ├─ Hit actor implements I_Interactable? + │ True → if different from CurrentFocused → Call OnFocusBegin on new, OnFocusEnd on old + │ False → Clear focus + ├─ If holding interact → accumulate hold timer + │ Timer >= HoldDuration → trigger OnInteract + └─ Fire dispatchers: OnFocusBegin, OnFocusEnd, OnHoldProgress +``` + +**Dispatchers:** `OnInteractionDetected(Actor, PromptText)`, `OnFocusLost`, `OnHoldProgress(Float)` + +--- + +## I_HidingSpot (Interface) + +**Create:** Right-click → **Blueprint → Blueprint Interface** → Name: `I_HidingSpot` + +| Function | Inputs | Outputs | +|----------|--------|---------| +| `CanPlayerHide` | `Player` (Actor) | `Boolean`, `BlockReason` (Text) | +| `OnPlayerEnter` | `Player` (Actor) | — | +| `OnPlayerExit` | `Player` (Actor) | — | +| `GetEntryTransform` | — | `Transform` | +| `GetPeekTransforms` | — | `Array` | +| `IsOccupied` | — | `Boolean` | +| `GetHidingSpotType` | — | `GameplayTag` | + +--- + +## BPC_DiegeticDisplay (Component) + +**Parent:** `ActorComponent` → Attach to wristwatch/helmet actor + +| Variable | Type | Default | +|----------|------|---------| +| `DisplayWidgetClass` | `WBP_DiegeticHUDFrame` | Assign | +| `RenderTarget` | `TextureRenderTarget2D` | 512x512 | +| `bIsActive` | Boolean | `false` | + +--- + +## BP_DoorActor (Actor) + +**Parent:** `Actor` → Add StaticMesh (door frame) + StaticMesh (door panel) + +| Variable | Type | Default | +|----------|------|---------| +| `DoorState` | GameplayTag | `Framework.Interaction.Door.Closed` | +| `bIsLocked` | Boolean | `false` | +| `RequiredKeyTag` | GameplayTag | Empty | +| `OpenAngle` | Float | `90.0` | +| `OpenSpeed` | Float | `3.0` | + +**Implements:** `I_Interactable`, `I_Lockable`, `I_Toggleable`, `I_Persistable` + +--- + +## BP_PuzzleDeviceActor (Actor) + +**Parent:** `Actor` → Base class for all puzzle devices + +| Variable | Type | Default | +|----------|------|---------| +| `PuzzleData` | `DA_PuzzleData` | Assign | +| `CurrentStep` | Integer | `0` | +| `bIsSolved` | Boolean | `false` | +| `ActivationSequence` | `Array` | Linked devices | + +--- + +## BPC_ContextualTraversalSystem (Component) + +**Attach to:** Player pawn — works with GASP Motion Warping + +| Variable | Type | Default | +|----------|------|---------| +| `TraversalTraceDistance` | Float | `200.0` | +| `VaultHeight` | Float | `120.0` | +| `MantleHeight` | Float | `200.0` | + +--- + +## BPC_PhysicsDragSystem (Component) + +**Attach to:** Player pawn + +| Variable | Type | Default | +|----------|------|---------| +| `DragForce` | Float | `500.0` | +| `HoldDistance` | Float | `200.0` | +| `HeldActor` | Actor | None | + +--- + +## BPC_UsableWorldObjectSystem (Component) + +**Attach to:** Player pawn + +| Variable | Type | Default | +|----------|------|---------| +| `CurrentUsable` | Actor | None | +| `bIsUsing` | Boolean | `false` | + +--- + +## Test These +- [ ] Walk up to door → prompt "Open Door [E]" → press E → door opens +- [ ] Locked door → prompt "Locked — Requires Key Card" → can't open +- [ ] Run toward low wall → auto-vault (ContextualTraversal) +- [ ] Grab physics object → drags in front of player → release throws diff --git a/docs/blueprints/04-inventory/InventoryAssets_All.asset.md b/docs/blueprints/04-inventory/InventoryAssets_All.asset.md new file mode 100644 index 0000000..a34f024 --- /dev/null +++ b/docs/blueprints/04-inventory/InventoryAssets_All.asset.md @@ -0,0 +1,111 @@ +# Inventory Systems — Asset Creation Sheet (10 assets) + +> **UE5 Path:** `Content/Framework/Inventory/` + +--- + +## C++ Already Done +- `BPC_InventorySystem` (31) — attach directly to pawn +- `DA_ItemData` (07) — create Data Asset instances per item + +--- + +## BP Assets to Create + +### BP_ItemPickup (Actor) +**Parent:** `Actor` → Add StaticMesh, SphereCollision, RotatingMovement + +| Variable | Type | Default | +|----------|------|---------| +| `ItemData` | `DA_ItemData` | Assign | +| `Quantity` | Integer | `1` | +| `BobAmplitude` | Float | `0.5` | +| `BobSpeed` | Float | `2.0` | + +**Implements:** `I_Interactable` + +**OnInteract:** +``` + ├─ Get Player → BPC_InventorySystem → CanAddItem(ItemData)? + │ True → AddItem(ItemData, Quantity) → Destroy self + │ False → Show "Inventory Full" prompt +``` + +### BPC_ContainerInventory (Component) +**Attach to:** Chests, drawers, cabinets, safes + +| Variable | Type | Default | +|----------|------|---------| +| `ContainerSlots` | `Array` | Empty | +| `ContainerSize` | Integer | `12` | +| `bIsOpen` | Boolean | `false` | + +### BPC_ActiveItemSystem (Component) +**Attach to:** Player pawn — manages quick-slot item + +| Variable | Type | Default | +|----------|------|---------| +| `QuickSlotCount` | Integer | `4` | +| `ActiveItemIndex` | Integer | `0` | +| `QuickSlots` | `Array` | Empty | + +### BPC_CollectibleTracker (Component) +**Attach to:** Player pawn + +| Variable | Type | Default | +|----------|------|---------| +| `FoundCollectibles` | `Array` | Empty | +| `TotalCollectibles` | Integer | `0` | +| `SetBonuses` | `Array` | Empty | + +### BPC_ConsumableSystem (Component) +**Attach to:** Player pawn + +| Variable | Type | Default | +|----------|------|---------| +| `LastConsumedItem` | `DA_ItemData` | None | +| `UseCooldown` | Float | `0.5` | + +**UseItem(ItemData):** +``` + ├─ BPC_HealthSystem → Heal(Item.ConsumableData.HealthRestore) + ├─ BPC_StressSystem → AddStress(-Item.ConsumableData.StressReduce) + └─ BPC_InventorySystem → RemoveItem(Item, 1) +``` + +### BPC_DocumentArchiveSystem (Component) +| Variable | Type | +|----------|------| +| `ArchivedDocuments` | `Array` | +| `bHasUnread` | Boolean | + +### BPC_EquipmentSlotSystem (Component) +| Variable | Type | Default | +|----------|------|---------| +| `EquipmentSlots` | `Array` | 6 slots | +| `EquippedWeapon` | `DA_ItemData` | None | + +### BPC_ItemCombineSystem (Component) +| Variable | Type | +|----------|------| +| `CraftingRecipes` | `Array` | + +### BPC_JournalSystem (Component) +| Variable | Type | +|----------|------| +| `ActiveQuests` | `Array` | +| `CompletedQuests` | `Array` | + +### BPC_KeyItemSystem (Component) +| Variable | Type | +|----------|------| +| `KeyItems` | `Array` | +| `bAutoUseOnTarget` | Boolean | + +--- + +## Test These +- [ ] Drop item pickup in level → walk over → item added to inventory +- [ ] Use health pack → health increases, item removed from inventory +- [ ] Combine items → new item appears in inventory +- [ ] Equip weapon → appears on character mesh diff --git a/docs/blueprints/05-saveload/SaveAssets_All.asset.md b/docs/blueprints/05-saveload/SaveAssets_All.asset.md new file mode 100644 index 0000000..97b5ad6 --- /dev/null +++ b/docs/blueprints/05-saveload/SaveAssets_All.asset.md @@ -0,0 +1,124 @@ +# Save/Load & Death Loop — Asset Creation Sheet (9 assets) + +> **UE5 Path:** `Content/Framework/Save/` + +--- + +## C++ Already Done +- `SS_SaveManager` (35) — auto-created subsystem, no BP needed +- `I_Persistable` (36) — in `I_InterfaceLibrary.h` + +--- + +## BP Assets to Create + +### BP_Checkpoint (Actor) +**Parent:** `Actor` → Add BoxCollision (trigger) + +| Variable | Type | Default | +|----------|------|---------| +| `CheckpointTag` | GameplayTag | e.g. `Framework.Save.Checkpoint.Chapter1_Start` | +| `bActivated` | Boolean | `false` | +| `SpawnTransform` | Transform | (auto-set from actor location) | + +**OnOverlapBegin(Player):** +``` + ├─ If bActivated → Return + ├─ Set bActivated = true + ├─ Get SaveManager → CreateCheckpoint(CheckpointTag) + ├─ Play checkpoint sound + particle effect + └─ Show WBP_NotificationToast: "Checkpoint Reached" +``` + +--- + +### BPC_AltDeathSpaceSystem (Component) +**Attach to:** Player pawn + +| Variable | Type | Default | +|----------|------|---------| +| `bInAltDeathSpace` | Boolean | `false` | +| `DeathSpaceScene` | Level | Assign | +| `ExitFound` | Boolean | `false` | + +--- + +### BPC_DeathHandlingSystem (Component) +**Attach to:** Player pawn + +| Variable | Type | Default | +|----------|------|---------| +| `DeathAnimation` | AnimMontage | Assign | +| `RespawnDelay` | Float | `3.0` | +| `bDeathSequencePlaying` | Boolean | `false` | + +**Bind to:** `BPC_HealthSystem.OnDeath` + +**OnDeath(Killer):** +``` + ├─ Play DeathAnimation + ├─ Delay(3.0) + ├─ Determine outcome: + │ ├─ AltDeathSpace chance → EnterAltDeathSpace + │ └─ Normal death → Call GM_CoreGameMode.HandlePlayerDead + └─ Call BPC_RunHistoryTracker.RecordDeath +``` + +--- + +### BPC_PersistentCorpseSystem (Component) +**Attach to:** Player pawn + +| Variable | Type | +|----------|------| +| `CorpsePersistenceDuration` | Float = `-1` (infinite) | +| `CorpseSnapshotData` | `Array` | + +--- + +### BPC_PersistentWorldStateRecorder (Component) +**Attach to:** Player pawn or GameState + +| Variable | Type | +|----------|------| +| `RecordedStates` | `Array` | +| `bIsRecording` | Boolean | + +--- + +### BPC_PlayerRespawnSystem (Component) +**Attach to:** Player pawn + +| Variable | Type | Default | +|----------|------|---------| +| `LastCheckpointTag` | GameplayTag | Empty | +| `bRespawning` | Boolean | `false` | + +**Respawn():** +``` + ├─ Get SaveManager → LoadCheckpoint(active slot) + ├─ Find BP_Checkpoint with LastCheckpointTag + ├─ Teleport player to checkpoint transform + ├─ Restore health, clear death state + └─ Call BPC_StateManager.RestorePreviousState +``` + +--- + +### BPC_RunHistoryTracker (Component) +**Attach to:** Player pawn + +| Variable | Type | +|----------|------| +| `TotalDeaths` | Integer | +| `TotalPlayTime` | Float | +| `ChaptersCompleted` | `Array` | +| `CheckpointsReached` | `Array` | + +--- + +## Test These +- [ ] Walk into checkpoint trigger → toast "Checkpoint Reached" → game saved +- [ ] Die → death animation plays → respawn at last checkpoint +- [ ] Alt death → void space loads → find exit → return to normal world +- [ ] Corpse persists after respawn diff --git a/docs/blueprints/06-ui/WBP_AllWidgets_QuickSheet.asset.md b/docs/blueprints/06-ui/WBP_AllWidgets_QuickSheet.asset.md new file mode 100644 index 0000000..82d4dc6 --- /dev/null +++ b/docs/blueprints/06-ui/WBP_AllWidgets_QuickSheet.asset.md @@ -0,0 +1,197 @@ +# WBP_PauseMenu / WBP_SettingsMenu / WBP_InventoryMenu +# WBP_JournalDocumentViewer / WBP_ObjectiveDisplay +# WBP_NotificationToast / WBP_ScreenEffectController +# WBP_AccessibilityUI / WBP_DiegeticHUDFrame +# WBP_MenuFlowController / WBP_CreditsScreen +# +# UI Widget Assets — Quick Creation Sheet (11 widgets) + +> **UE5 Path:** `Content/Framework/UI/` +> **Parent Class:** `UserWidget` + +--- + +## WBP_PauseMenu + +**Canvas:** Vertical Box (centered) → Resume, Settings, Save, Load, Quit to Menu, Quit to Desktop + +**Key Logic:** +``` +Event Construct: + └─ Set Input Mode: UI + ShowCursor + +btn_Resume.OnClicked: + └─ Call SS_UIManager.PopWidget() → Set Input Mode: Game +``` + +--- + +## WBP_SettingsMenu + +**Canvas:** Tab buttons (Audio, Video, Controls, Gameplay, Accessibility) + settings panels + +**Key Logic:** +``` +Audio Tab → Volume sliders → SS_AudioManager.SetBusVolume(Category, Volume) +Video Tab → Resolution dropdown, Fullscreen toggle, Quality presets +Controls Tab → Key rebinding list → SS_EnhancedInputManager.RebindKey(Action, Key) +Gameplay Tab → Difficulty, subtitle toggle, aim assist +Accessibility Tab → WBP_AccessibilityUI embedded + +On Apply → SaveSettings → SS_SettingsSystem.ApplyAndSave() +On Back → If dirty → "Save changes?" dialog +``` + +--- + +## WBP_InventoryMenu + +**Canvas:** Grid panel (8 columns) + item detail panel on right + weight bar at bottom + +**Key Logic:** +``` +Event Construct: + ├─ Get Pawn → BPC_InventorySystem → Bind OnInventoryChanged → RefreshGrid + └─ Bind OnWeightChanged → UpdateWeightBar + +RefreshGrid: + ├─ Clear Grid children + └─ For each slot → Create WBP_InventorySlot widget → Add to Grid + +OnSlotClicked(SlotIndex): + ├─ If dragging → SwapSlots + ├─ If right-click → ShowContextMenu (Use, Equip, Drop, Examine) + └─ Show item detail in right panel +``` + +--- + +## WBP_JournalDocumentViewer + +**Canvas:** ScrollBox with document entries + detail view on right + +**Key Logic:** +``` +Construct → BPC_DocumentArchiveSystem → GetAllDocuments() + └─ For each doc → create list item → on click → show full text + image +``` + +--- + +## WBP_ObjectiveDisplay + +**Canvas:** Vertical Box (top-right) — list of active objectives + +**Key Logic:** +``` +Bind GS_CoreGameState.OnObjectiveTagsChanged → Refresh + └─ For each ActiveObjectiveTag → lookup DA_ObjectiveData → show title + progress +``` + +--- + +## WBP_NotificationToast + +**Canvas:** Border (top-center, slides in/out) → Icon + Title + Subtitle + +**Key Logic:** +``` +ShowToast(Title, Subtitle, Icon, Duration): + ├─ Set text + ├─ Play SlideIn animation + └─ Delay(Duration) → Play SlideOut → Remove from parent +``` + +--- + +## WBP_ScreenEffectController + +**Canvas:** Full-screen overlay images (vignette, blood, healing, flash) + +**Key Logic:** +``` +PlayEffect(EffectType, Intensity, Duration): + ├─ Switch EffectType + │ Damage → Show red vignette, fade to Intensity + │ Healing → Show green edge glow + │ Death → Show black fade + │ Flash → Show white screen + └─ Timeline: fade in, hold, fade out + +Bind BPC_HealthSystem.OnHealthChanged → if damage → PlayEffect(Damage) +``` + +--- + +## WBP_AccessibilityUI + +**Canvas:** Toggles and sliders for accessibility options + +**Controls:** +- Subtitles: On/Off + size slider +- Colorblind Mode: Off/Protanopia/Deuteranopia/Tritanopia +- Controller Remap: Per-platform button mapping +- Difficulty: Story/Easy/Normal/Hard/Nightmare +- Aim Assist: Off/Low/Medium/High + +**On change → call SS_SettingsSystem.SaveAccessibilitySettings()** + +--- + +## WBP_DiegeticHUDFrame + +**Canvas:** Empty container that renders to a material on the player's wristwatch/helmet + +**Key Logic:** +- This widget renders to a RenderTarget +- The render target is assigned to the wristwatch mesh material +- Contents show mini-HUD: health dots, ammo count, compass + +--- + +## WBP_MenuFlowController + +**Not visual** — state machine that manages menu transitions. + +**States:** MainMenu → NewGame → Loading → InGame → Pause → Settings → Death → Credits + +**Key Logic:** +``` +PushMenu(MenuWidget): + ├─ If current menu → hide + ├─ Create new menu → add to viewport + └─ Store in MenuStack + +PopMenu(): + ├─ Remove top menu from viewport + └─ Restore previous menu + +OnBackPressed: + ├─ If menu stack has entries → PopMenu + └─ If game and no stack → Show PauseMenu +``` + +--- + +## WBP_CreditsScreen + +**Canvas:** ScrollBox — auto-scrolling credits text + +**Key Logic:** +``` +Event Construct: + └─ Start Timeline → scroll credits text from bottom to top over 60 seconds + +OnSkip (any key press): + └─ Jump to end → show "Thanks for Playing" → auto-transition to MainMenu +``` + +--- + +## Test All Widgets +- [ ] Each widget displays in isolation (right-click → Run Widget) +- [ ] Pause menu toggles cursor correctly +- [ ] Settings save and persist across sessions +- [ ] Inventory grid updates when items change +- [ ] Notification toast animates in/out +- [ ] Screen effects don't block input diff --git a/docs/blueprints/06-ui/WBP_HUDController.asset.md b/docs/blueprints/06-ui/WBP_HUDController.asset.md new file mode 100644 index 0000000..49c1b90 --- /dev/null +++ b/docs/blueprints/06-ui/WBP_HUDController.asset.md @@ -0,0 +1,72 @@ +# WBP_HUDController — Asset Implementation + +> **UE5 Asset:** `/Game/Framework/UI/WBP_HUDController` +> **Parent Class:** `UserWidget` +> **Purpose:** Root HUD widget — manages all HUD sub-widgets + +--- + +## Create This Widget + +1. Content Browser → `Content/Framework/UI/` +2. Right-click → **User Interface → Widget Blueprint** +3. Name: `WBP_HUDController` + +--- + +## Designer Canvas Setup + +``` +Canvas Panel (root) + ├─ WBP_InteractionPromptDisplay (bottom-center) + ├─ WBP_ObjectiveDisplay (top-right) + ├─ WBP_NotificationToast (top-center) + ├─ HealthBar (ProgressBar) (bottom-left) [inline or sub-widget] + ├─ StaminaBar (ProgressBar) (bottom-left, below health) + ├─ AmmoDisplay (TextBlock) (bottom-right) + ├─ Crosshair (Image) (center) + └─ WBP_DiegeticHUDFrame (full screen, behind everything) +``` + +--- + +## What to Wire + +### Event: Event Construct +``` +[Event Construct] + ├─ Get Owning Player Pawn → Store as CachedPawn + ├─ Get Pawn → GetComponentByClass(BPC_HealthSystem) → Bind OnHealthChanged + ├─ GetComponentByClass(BPC_StaminaSystem) → Bind OnStaminaChanged + ├─ Get GameState → Cast to GS_CoreGameState → Bind OnObjectiveTagsChanged + └─ Get GameInstance → Cast to GI_GameFramework → Bind OnGamePhaseChanged +``` + +### Health Binding (Custom Event) +``` +[OnHealthChanged(Current, Max, Delta)] + ├─ HealthBar → Set Percent(Current / Max) + ├─ Branch: Delta < 0? + │ True → Play Animation (DamageVignette) + └─ Branch: Current <= 0? + └─ Call WBP_ScreenEffectController → PlayDeathEffect +``` + +### GamePhase Binding +``` +[OnGamePhaseChanged(NewPhase)] + ├─ Switch on NewPhase: + │ MainMenu → Hide HUD + │ InGame → Show HUD + │ Paused → Dim HUD, show pause overlay + │ Cutscene → Hide HUD + │ DeathLoop → Show death screen +``` + +--- + +## Test It +- [ ] PIE with player pawn: HUD displays +- [ ] Take damage: health bar updates +- [ ] Sprint: stamina bar drains +- [ ] Open menu: HUD hides/disables diff --git a/docs/blueprints/06-ui/WBP_InteractionPromptDisplay.asset.md b/docs/blueprints/06-ui/WBP_InteractionPromptDisplay.asset.md new file mode 100644 index 0000000..05850a6 --- /dev/null +++ b/docs/blueprints/06-ui/WBP_InteractionPromptDisplay.asset.md @@ -0,0 +1,70 @@ +# WBP_InteractionPromptDisplay — Asset Implementation + +> **UE5 Asset:** `/Game/Framework/UI/WBP_InteractionPromptDisplay` +> **Parent Class:** `UserWidget` + +--- + +## Create This Widget + +1. Content Browser → `Content/Framework/UI/` +2. Right-click → **User Interface → Widget Blueprint** +3. Name: `WBP_InteractionPromptDisplay` + +--- + +## Designer Canvas + +``` +Canvas Panel + └─ Border (background, semi-transparent black) + └─ Horizontal Box + ├─ Image (key icon, e.g. "E" key) + └─ Vertical Box + ├─ TextBlock "PromptText" (e.g. "Pick Up") + └─ TextBlock "SubText" (e.g. "MedKit") +``` + +--- + +## What to Wire + +### Function: ShowPrompt +``` +Inputs: PromptText(Text), SubText(Text), KeyIcon(Texture2D), bShowHoldProgress(Boolean) + ├─ Set PromptText = PromptText + ├─ Set SubText = SubText + ├─ Set KeyIcon = KeyIcon + ├─ Branch: bShowHoldProgress? + │ True → Show HoldProgressBar + ├─ Set Visibility = Visible + └─ Play Animation (FadeIn) +``` + +### Function: HidePrompt +``` + ├─ Set Visibility = Hidden + └─ Stop All Animations +``` + +### Function: UpdateHoldProgress +``` +Input: Progress(0.0-1.0) + └─ HoldProgressBar → Set Percent(Progress) +``` + +--- + +## Events to Handle +| Event | Action | +|-------|--------| +| `BPC_InteractionDetector.OnFocusBegin` | ShowPrompt with object data | +| `BPC_InteractionDetector.OnFocusEnd` | HidePrompt | +| `BPC_InteractionDetector.OnHoldProgress` | UpdateHoldProgress | + +--- + +## Test It +- [ ] Look at an interactable object → prompt appears +- [ ] Hold interact key → progress bar fills +- [ ] Look away → prompt disappears diff --git a/docs/blueprints/06-ui/WBP_MainMenu.asset.md b/docs/blueprints/06-ui/WBP_MainMenu.asset.md new file mode 100644 index 0000000..b1f5d52 --- /dev/null +++ b/docs/blueprints/06-ui/WBP_MainMenu.asset.md @@ -0,0 +1,75 @@ +# WBP_MainMenu — Asset Implementation + +> **UE5 Asset:** `/Game/Framework/UI/WBP_MainMenu` +> **Parent Class:** `UserWidget` + +--- + +## Create This Widget + +1. Content Browser → `Content/Framework/UI/` +2. Right-click → **User Interface → Widget Blueprint** +3. Name: `WBP_MainMenu` + +--- + +## Designer Canvas + +``` +Canvas Panel + └─ Vertical Box (centered) + ├─ Image (game logo) "LogoImage" + ├─ Spacer + ├─ Button "btn_NewGame" "New Game" + ├─ Button "btn_Continue" "Continue" + ├─ Button "btn_LoadGame" "Load Game" + ├─ Button "btn_Settings" "Settings" + ├─ Button "btn_Credits" "Credits" + └─ Button "btn_Quit" "Quit Game" + └─ TextBlock "VersionText" (bottom-right) "v1.0.0" +``` + +--- + +## What to Wire + +### Event: Event Construct +``` +[Event Construct] + ├─ Get GameInstance → Cast to GI_GameFramework + ├─ Get SaveManager → GetSlotManifest() + ├─ Branch: Any slot has data? + │ True → btn_Continue.SetIsEnabled(true) + │ False → btn_Continue.SetIsEnabled(false) + └─ Set Input Mode: UI + Show Cursor +``` + +### Button Handlers +``` +btn_NewGame.OnClicked: + ├─ Call GI_GameFramework.ClearAllSessionFlags() + ├─ Call GI_GameFramework.SetActiveSlot(new slot index) + ├─ Call OpenLevel (first chapter map) + └─ Set Input Mode: Game + +btn_Continue.OnClicked: + ├─ Call SaveManager.QuickLoad() + └─ OnLoadComplete → OpenLevel (saved chapter) + +btn_LoadGame.OnClicked: + └─ Push WBP_LoadGameMenu to SS_UIManager stack + +btn_Settings.OnClicked: + └─ Push WBP_SettingsMenu + +btn_Quit.OnClicked: + └─ Quit Game (or ConsoleCommand "quit") +``` + +--- + +## Test It +- [ ] Game opens at main menu → cursor visible +- [ ] No save data → Continue grayed out +- [ ] Click New Game → level loads → cursor hidden +- [ ] Click Quit → game exits diff --git a/docs/blueprints/07-narrative/NarrativeAssets_All.asset.md b/docs/blueprints/07-narrative/NarrativeAssets_All.asset.md new file mode 100644 index 0000000..5f755aa --- /dev/null +++ b/docs/blueprints/07-narrative/NarrativeAssets_All.asset.md @@ -0,0 +1,108 @@ +# Narrative Systems — Asset Creation Sheet (11 assets) + +> **UE5 Path:** `Content/Framework/Narrative/` + +--- + +## Components (attach to player pawn or GameState) + +### BPC_NarrativeStateSystem +| Variable | Type | Default | +|----------|------|---------| +| `ActiveFlags` | `Array` | Empty | +| `CurrentChapter` | GameplayTag | Empty | +| `CurrentPhase` | GameplayTag | Empty | + +**SetFlag(Tag):** Add to ActiveFlags → broadcast OnNarrativeFlagSet + +### BPC_ObjectiveSystem +| Variable | Type | Default | +|----------|------|---------| +| `ActiveObjectives` | `Array` | Empty | +| `CompletedObjectives` | `Array` | Empty | + +**ActivateObjective(Tag):** → Add to Active → broadcast OnObjectiveActivated → GS_CoreGameState.AddObjective(Tag) + +### BPC_DialoguePlaybackSystem +| Variable | Type | +|----------|------| +| `DialogueQueue` | `Array` | +| `bIsPlaying` | Boolean | +| `bAutoAdvance` | Boolean | + +**PlayDialogue(DialogueData):** → Show subtitles → play VO → advance queue + +### BPC_DialogueChoiceSystem +| Variable | Type | +|----------|------| +| `CurrentChoices` | `Array` | +| `SelectedChoiceIndex` | Integer | + +**PresentChoices(Choices):** → Show WBP_DialogueChoice widget → wait for selection → return + +### BPC_BranchingConsequenceSystem +| Variable | Type | +|----------|------| +| `PendingConsequences` | `Array` | + +**ExecuteConsequence(Choice):** → Grant items, set narrative flags, change relationships, trigger cutscenes + +### BPC_TrialScenarioSystem +| Variable | Type | Default | +|----------|------|---------| +| `TrialTimer` | Float | `0.0` | +| `bTrialActive` | Boolean | `false` | +| `TrialSuccessThreshold` | Float | `60.0` | + +### BPC_CutsceneBridge +| Variable | Type | +|----------|------| +| `CurrentCutscene` | `DA_CutsceneData` | +| `bCutscenePlaying` | Boolean | + +**PlayCutscene(Data):** → Set phase to Cutscene → play Sequence → on finish → restore phase + +### BPC_LoreUnlockSystem +| Variable | Type | +|----------|------| +| `UnlockedLore` | `Array` | + +**UnlockLore(Tag):** → Add to unlocked → show notification → add to journal + +### BPC_EndingAccumulator +| Variable | Type | +|----------|------| +| `EndingConditions` | `TMap` | +| `DominantEnding` | GameplayTag | + +--- + +## Data Assets (create instances per content) + +| Asset | Purpose | +|-------|---------| +| `DA_DialogueData` | Dialogue lines, speaker, VO, conditions | +| `DA_CutsceneData` | Level sequence, milestone flags, skip policy | +| `DA_ObjectiveData` | Title, description, prerequisites, rewards | +| `DA_TrialData` | Timer, success conditions, failure consequences | + +--- + +## Actor — BP_NarrativeTriggerVolume +**Parent:** `TriggerVolume` + +| Variable | Type | +|----------|------| +| `TriggerTag` | GameplayTag | +| `bTriggerOnce` | Boolean | +| `NarrativeActions` | `Array` | + +**OnOverlapBegin:** → Execute narrative actions (set flag, start dialogue, activate objective, play cutscene) + +--- + +## Test These +- [ ] Walk into trigger → dialogue starts → subtitles show +- [ ] Dialogue choices appear → select option → consequence fires +- [ ] Objective activates → shows in HUD objective display +- [ ] Trial scenario starts → timer counts down → succeed/fail diff --git a/docs/blueprints/08-weapons/Weapons_AI_Adaptive_QuickSheet.asset.md b/docs/blueprints/08-weapons/Weapons_AI_Adaptive_QuickSheet.asset.md new file mode 100644 index 0000000..4e73222 --- /dev/null +++ b/docs/blueprints/08-weapons/Weapons_AI_Adaptive_QuickSheet.asset.md @@ -0,0 +1,107 @@ +# Weapons, AI & Adaptive — Asset Creation Sheet (31 assets) + +> **UE5 Path:** `Content/Framework/Weapons/`, `Content/Framework/AI/`, `Content/Framework/Adaptive/` + +--- + +## Weapons (08-weapons — 10 remaining BP assets) + +### BP_WeaponBase (Actor) +**Parent:** `Actor` → Add SkeletalMesh, ArrowComponent (muzzle) + +| Variable | Type | Default | +|----------|------|---------| +| `WeaponData` | `DA_ItemData` | Assign | +| `AmmoLoaded` | Integer | `0` | +| `FireMode` | GameplayTag | `Framework.Combat.FireMode.SemiAuto` | +| `MuzzleFlashFX` | ParticleSystem | Assign | +| `FireSound` | SoundBase | Assign | + +**Implements:** `I_Interactable`, `I_UsableItem` + +### BP Components (attach to player/enemy pawns) + +| Component | Key Variables | +|-----------|--------------| +| `BPC_AmmoComponent` | `ReserveAmmo`(Int), `MaxReserve`(Int), `AmmoType`(GameplayTag) | +| `BPC_CombatFeedbackComponent` | `bShowHitMarker`(Bool), `HitMarkerDuration`(Float) | +| `BPC_DamageReceptionSystem` | ✅ C++ done — attach directly | +| `BPC_DeathCauseTracker` | `LastDamageType`(GameplayTag), `LastKiller`(Actor) | +| `BPC_FirearmSystem` | `CurrentFireMode`(GameplayTag), `bChamberEmpty`(Bool) | +| `BPC_HitReactionSystem` | `FlinchAnimation`(AnimMontage), `KnockdownAnimation`(AnimMontage) | +| `BPC_MeleeSystem` | `ComboCount`(Int), `CurrentComboWindow`(Float) | +| `BPC_RecoilSystem` | `RecoilPattern`(CurveVector), `RecoilRecoverySpeed`(Float) | +| `BPC_ReloadSystem` | `ReloadTime`(Float), `bTacticalReload`(Bool) | +| `BPC_ShieldDefenseSystem` | `ShieldHealth`(Float), `BlockAngle`(Float) | + +--- + +## AI (09-ai — 9 BP assets) + +### BP_EnemyBase (Character) +**Parent:** `Character` → Add SkeletalMesh, Capsule, AI Perception + +| Variable | Type | Default | +|----------|------|---------| +| `EnemyData` | `DA_EncounterData` | Assign | +| `AlertLevel` | GameplayTag | `Framework.AI.Alert.Unaware` | +| `Archetype` | GameplayTag | `Framework.AI.Archetype.Patrol` | + +### Components +| Component | Purpose | +|-----------|---------| +| `BPC_AlertSystem` | Suspicious → Alerted → Combat state machine | +| `BPC_AIStateMachine` | Patrol/Search/Combat/Flee transitions | +| `BPC_AIMemorySystem` | Last known locations, threat history | +| `BPC_AIPerceptionSystem` | Sight, hearing, damage sense | +| `BPC_BehaviourVariantSelector` | Weighted random behavior selection from DA_BehaviourVariant set | + +### Other AI Assets +| Asset | Type | Purpose | +|-------|------|---------| +| `BP_PatrolPath` | Actor + Spline | Patrol waypoints | +| `AI_BaseAgentController` | AIController | Behavior tree runner | +| `BB_AgentBoard` | Blackboard | AI keys (Target, LastLocation, AlertLevel, etc.) | + +--- + +## Adaptive (10-adaptive — 13 BP assets) + +### Components +| Component | Purpose | +|-----------|---------| +| `BPC_DifficultyManager` | Dynamic difficulty scaling based on player metrics | +| `BPC_FearSystem` | AI + player fear states, cower, flee | +| `BPC_PerformanceScaler` | LOD, spawn distance, effect quality | +| `BPC_ProceduralEncounter` | Difficulty-based spawn group generation | +| `BPC_AdaptiveEnvironmentDirector` | Room mutation, event coordination | +| `BPC_AtmosphereStateController` | Room tone, tension, mood | +| `BPC_AudioAtmosphereController` | [DEPRECATED — use SS_AudioManager] | +| `BPC_LightEventController` | Flicker, dim, color shift, strobe | +| `BPC_MemoryDriftSystem` | Visual/audio/dialogue distortions (stress-based) | +| `BPC_PacingDirector` | Intensity bands, encounter frequency, music | +| `BPC_PlaystyleClassifier` | Aggressive/Stealthy/Explorer/Balanced | +| `BPC_RareEventSystem` | Weighted rare event selection + cooldown | +| `BPC_ScareEventSystem` | Jump scares, anticipation, recovery | +| `SS_AudioManager` | GameInstanceSubsystem — MetaSounds entry point | +| `BP_RoomAudioZone` | TriggerVolume — auto-switches room reverb | + +--- + +## Test Weapons +- [ ] Pick up weapon → attaches to hand socket +- [ ] Fire → muzzle flash + recoil + ammo count decreases +- [ ] Empty magazine → auto-reload (or click Reload) +- [ ] Melee → combo counter increments + +## Test AI +- [ ] Patrol path → enemy walks waypoints +- [ ] Player enters sight → alert level rises → chase begins +- [ ] Player hides → enemy loses sight → searches last known location +- [ ] Combat → enemy uses behavior variant (flanking, cover, rush) + +## Test Adaptive +- [ ] Player dies frequently → difficulty decreases (fewer enemies, more health) +- [ ] Player excels → difficulty increases +- [ ] Stress high → memory drift distortions activate +- [ ] Scare event triggers → jump scare sound + visual plays diff --git a/docs/blueprints/11-meta/Meta_Settings_Polish_DataAssets.asset.md b/docs/blueprints/11-meta/Meta_Settings_Polish_DataAssets.asset.md new file mode 100644 index 0000000..3ead786 --- /dev/null +++ b/docs/blueprints/11-meta/Meta_Settings_Polish_DataAssets.asset.md @@ -0,0 +1,119 @@ +# Meta, Settings & Polish — Asset Creation Sheet (13 assets) + +> **UE5 Path:** `Content/Framework/Achievements/`, `Content/Framework/Settings/`, `Content/Framework/Polish/` + +--- + +## Meta (11-meta — 2 assets) + +### BPC_ProgressStatTracker +**Attach to:** Player pawn + +| Variable | Type | Default | +|----------|------|---------| +| `TotalPlaytime` | Float | `0.0` | +| `TotalKills` | Integer | `0` | +| `TotalDeaths` | Integer | `0` | +| `CollectiblesFound` | Integer | `0` | +| `EndingsUnlocked` | `Array` | Empty | +| `DifficultyCompleted` | `Array` | Empty | + +### SS_AchievementSystem +**Parent:** `GameInstanceSubsystem` — auto-created by GameInstance + +| Variable | Type | +|----------|------| +| `UnlockedAchievements` | `Array` | +| `PendingNotifications` | `Array` | + +**UnlockAchievement(Tag):** → Check platform API → if not already unlocked → unlock → show toast → save + +--- + +## Settings (12-settings — 2 assets) + +### BPC_AccessibilitySettings +**Attach to:** Player pawn + +| Variable | Type | Default | +|----------|------|---------| +| `bSubtitlesEnabled` | Boolean | `true` | +| `SubtitleSize` | Float | `1.0` | +| `ColorblindMode` | Integer | `0` | +| `bAimAssist` | Boolean | `true` | +| `AimAssistStrength` | Float | `0.5` | +| `DifficultyLevel` | Integer | `2` | + +### SS_SettingsSystem +**Parent:** `GameInstanceSubsystem` — auto-created + +| Variable | Type | +|----------|------| +| `VideoSettings` | `S_VideoSettings` | +| `AudioSettings` | `S_AudioSettings` | +| `ControlSettings` | `S_ControlSettings` | +| `AccessibilitySettings` | `S_AccessibilitySettings` | + +**ApplyAndSave():** → Write to config file → broadcast OnSettingsApplied + +--- + +## Polish (13-polish — 9 assets) + +### Components + +| Component | Purpose | +|-----------|---------| +| `BPC_AnalyticsTracker` | Event tracking, session metrics, telemetry | +| `BPC_DevCheatManager` | God mode, noclip, give item, teleport | +| `BPC_ErrorHandler` | Crash logging, error display, recovery | +| `BPC_FPSCounter` | FPS display, min/max/avg tracking | +| `BPC_LoadingScreen` | Progress bar, tips, background | +| `BPC_TutorialSystem` | Contextual prompts, progression, dismiss | + +### Widgets + +| Widget | Purpose | +|--------|---------| +| `WBP_CreditsScreen` | Auto-scroll credits, skip, post-credit scene | +| `WBP_DebugMenu` | State viewer, log, performance, cheats | +| `WBP_SplashScreen` | Studio/engine logo, skip | + +--- + +## Data Assets — Remaining (14-data-assets — 16 total) + +Create Data Asset instances (not Blueprint children) for all content definitions. + +| Asset | Purpose | Key Properties | +|-------|---------|---------------| +| `DA_AdaptationRule` | Difficulty adaptation | MetricThreshold, Action, ScaleFactor | +| `DA_AtmosphereProfile` | Room atmosphere | AudioLayer, LightSettings, FogSettings, PostProcess | +| `DA_BehaviourVariant` | AI behavior | AttackPattern, PatrolStyle, AggressionLevel | +| `DA_EncounterData` | Enemy group | EnemyTypes, SpawnRules, DifficultyTier | +| `DA_EquipmentConfig` | Weapon/armor stats | DamageTypeResistances, Durability, Weight | +| `DA_HapticProfile` | Force feedback | RumblePattern, Intensity, Duration | +| `DA_InteractionData` | Interaction def | PromptText, Duration, Icon, Conditions | +| `DA_ObjectiveData` | Quest def | Title, Description, Prerequisites, Rewards | +| `DA_PuzzleData` | Puzzle def | Solution, Steps, Hints, Rewards | +| `DA_RareEvent` | Rare event | Weight, Conditions, Effects, Cooldown | +| `DA_RoomMutation` | Room change | LayoutChange, ObjectSwap, LightChange | +| `DA_ScareEvent` | Scare def | Type, Anticipation, Payoff, Recovery | +| `DA_InputMappingProfile` | Per-platform bindings | PC/Xbox/PS5 key arrays | +| `DA_AudioSettings` | Audio config | Bus volumes, ducking, pool limits | +| `DA_RoomAcousticPreset` | Room acoustics | Reverb, Occlusion, Reflection (7 presets) | + +### How to Create Each Data Asset +1. Right-click → **Miscellaneous → Data Asset** +2. Class: `DA_{Type}` (if C++) or `PrimaryDataAsset` +3. Name: `DA_{Type}_{Name}` (e.g. `DA_ObjectiveData_Chapter1_FindKey`) +4. Fill properties per the spec file in `docs/blueprints/14-data-assets/` + +--- + +## Test Meta/Settings/Polish +- [ ] Unlock achievement → toast notification appears → saved to platform +- [ ] Change settings → persist after restart +- [ ] Press F1 → debug menu opens +- [ ] Loading screen shows between levels with progress bar +- [ ] Tutorial popups appear for first-time actions diff --git a/docs/blueprints/15-input/IA_IMC_All.asset.md b/docs/blueprints/15-input/IA_IMC_All.asset.md new file mode 100644 index 0000000..c9abc8a --- /dev/null +++ b/docs/blueprints/15-input/IA_IMC_All.asset.md @@ -0,0 +1,121 @@ +# IA_* — Input Actions + IMC_* — Input Mapping Contexts + +> **UE5 Path:** `Content/Framework/Input/Actions/` + `Content/Framework/Input/Contexts/` +> **Plugin Required:** Enhanced Input (enabled in project plugins) + +--- + +## Prerequisites + +1. **Project Settings → Plugins → Enhanced Input** → Enabled ✓ +2. Restart editor after enabling + +--- + +## Input Actions — Create All (17 assets) + +### Gameplay Actions +| Asset Name | Value Type | Description | +|-----------|-----------|-------------| +| `IA_Move` | `Axis2D` | WASD / Left Stick movement | +| `IA_Look` | `Axis2D` | Mouse / Right Stick camera | +| `IA_Jump` | `Digital (bool)` | Jump / Vault | +| `IA_Sprint` | `Digital (bool)` | Sprint (hold) | +| `IA_Crouch` | `Digital (bool)` | Toggle crouch | +| `IA_Interact` | `Digital (bool)` | Primary interact (E / X) | +| `IA_InteractHold` | `Digital (bool)` | Hold interaction (hold E) | +| `IA_Reload` | `Digital (bool)` | Reload weapon | +| `IA_Fire` | `Digital (bool)` | Primary fire | +| `IA_AimDownSights` | `Digital (bool)` | Aim (hold) | +| `IA_Melee` | `Digital (bool)` | Melee attack | +| `IA_UseItem` | `Digital (bool)` | Use equipped/quick-slot item | +| `IA_ToggleInventory` | `Digital (bool)` | Open/close inventory | +| `IA_ToggleJournal` | `Digital (bool)` | Open/close journal | +| `IA_Pause` | `Digital (bool)` | Pause menu | +| `IA_Hide` | `Digital (bool)` | Enter/exit hiding | +| `IA_Peek` | `Digital (bool)` | Peek while hiding | + +### How to Create Each + +1. Content Browser → `Content/Framework/Input/Actions/` +2. Right-click → **Input → Input Action** +3. Name: `IA_{Action}` +4. Open the asset → set **Value Type** per the table above +5. Optionally add **Triggers** (Tap, Hold, Pressed, Released) +6. Optionally add **Modifiers** (Negate, Dead Zone, Swizzle Axis) + +### Common Trigger/Modifier Setup + +``` +IA_Interact: Trigger: Pressed +IA_InteractHold: Trigger: Hold (HoldTimeThreshold = 0.5) +IA_Sprint: Trigger: Hold +IA_Crouch: Trigger: Pressed (toggle behavior in code) +IA_Fire: Trigger: Pressed + Trigger: Hold (for auto-fire) +IA_AimDownSights: Trigger: Hold +IA_Pause: Trigger: Pressed +``` + +--- + +## Input Mapping Contexts — Create All (6 assets) + +| Asset Name | Priority | Contains These Actions | When Active | +|-----------|----------|----------------------|-------------| +| `IMC_Default` | 0 | Move, Look, Jump, Sprint, Crouch, Interact, InteractHold, Reload, Fire, AimDownSights, Melee, UseItem, ToggleInventory, ToggleJournal, Pause | Always (lowest priority) | +| `IMC_Hiding` | 5 | Hide, Peek (overrides some IMC_Default) | While hidden | +| `IMC_WristwatchUI` | 10 | Interact (re-mapped to wristwatch), Look | Wristwatch mode | +| `IMC_Inspection` | 20 | Look (rotation only), Interact (exit inspect) | 3D inspect mode | +| `IMC_UI` | 100 | Pause (close), Interact (confirm) | Any menu open | +| `IMC_Vehicle` | 3 | Move (vehicle), Look, Interact (exit) | While in vehicle | + +### How to Create Each + +1. Content Browser → `Content/Framework/Input/Contexts/` +2. Right-click → **Input → Input Mapping Context** +3. Name: `IMC_{Context}` +4. Open → **Add Mapping** for each action in the table +5. For each mapping, select the `IA_` asset and assign a key binding + +### Default Key Bindings (PC — IMC_Default) + +| Action | Primary Key | Secondary Key | +|--------|------------|---------------| +| `IA_Move` | `W/A/S/D` | Left Stick | +| `IA_Look` | `Mouse XY` | Right Stick | +| `IA_Jump` | `Space` | `A` (gamepad) | +| `IA_Sprint` | `Left Shift` | Left Stick Click | +| `IA_Crouch` | `Left Ctrl` | `B` (gamepad) | +| `IA_Interact` | `E` | `X` (gamepad) | +| `IA_Reload` | `R` | `Y` (gamepad) | +| `IA_Fire` | `Left Mouse` | Right Trigger | +| `IA_AimDownSights` | `Right Mouse` | Left Trigger | +| `IA_Melee` | `V` | Right Stick Click | +| `IA_UseItem` | `Q` | `D-Pad Up` | +| `IA_ToggleInventory` | `Tab` | `Select` | +| `IA_ToggleJournal` | `J` | `D-Pad Left` | +| `IA_Pause` | `Escape` | `Start` | + +--- + +## Context Priority System + +``` +IMC_UI (100) ← Highest — blocks everything +IMC_Inspection (20) +IMC_WristwatchUI (10) +IMC_Hiding (5) +IMC_Vehicle (3) +IMC_Default (0) ← Lowest — always active +``` + +When a higher-priority context is pushed, conflicting inputs from lower contexts are overridden. Non-conflicting inputs still pass through. + +--- + +## Test It +- [ ] All 17 IA_ assets created with correct Value Types +- [ ] All 6 IMC_ assets created with correct mappings +- [ ] PIE: WASD moves character, mouse looks around, E interacts +- [ ] Push IMC_Hiding → IMC_Default actions blocked except those also in IMC_Hiding +- [ ] Open inventory → IMC_UI pushes → cursor appears → game inputs blocked diff --git a/docs/blueprints/16-state/StateAssets_All.asset.md b/docs/blueprints/16-state/StateAssets_All.asset.md new file mode 100644 index 0000000..c0b2475 --- /dev/null +++ b/docs/blueprints/16-state/StateAssets_All.asset.md @@ -0,0 +1,152 @@ +# State Management Assets — Enums, Structs, Data Asset + +> **UE5 Path:** `Content/Framework/State/` +> **Assets:** 4 Enums + 3 Structs + 1 Data Asset + 1 Component + +--- + +## Enums — Create All (4 assets) + +### E_PlayerActionState (42 values) +1. Content Browser → `Content/Framework/State/` +2. Right-click → **Blueprint → Enumeration** +3. Name: `E_PlayerActionState` + +**Values to Add:** +``` +Idle, Walking, Sprinting, Crouching, Jumping, Falling, Landing, +Sliding, Vaulting, Mantling, Climbing, Swimming, Crawling, +Firing, Aiming, Reloading, Melee, Blocking, Throwing, +Interacting, Inspecting, UsingItem, ConsumingItem, +Hiding, Peeking, HoldingBreath, Lockpicking, Hacking, +Dialoguing, Reading, Examining, Crafting, +Dead, Dying, Unconscious, Staggered, KnockedDown, +CutsceneBound, VoidSpace, Menu, Inventory, Journal +``` + +### E_OverlayState (18 values) +1. Name: `E_OverlayState` + +**Values:** +``` +None, Aiming, Firing, Reloading, MeleeAttack, Blocking, +UsingItem, Inspecting, Interacting, Throwing, +HoldingBreath, Peeking, Dialoguing, Injured, +Staggered, Carrying, WristwatchActive, MapActive +``` + +### E_PlayerVitalSignals (5 values) +1. Name: `E_PlayerVitalSignals` + +**Values:** +``` +Calm, Elevated, Stressed, Panic, Critical +``` + +### E_ActionRequestResult (8 values) +1. Name: `E_ActionRequestResult` + +**Values:** +``` +Granted, Denied, BlockedByForce, AlreadyActive, +InvalidState, RequesterNotFound, CooldownActive, VitalThreshold +``` + +--- + +## Structs — Create All (3 assets) + +### S_StateChangeRequest +1. Content Browser → `Content/Framework/State/` +2. Right-click → **Blueprint → Structure** +3. Name: `S_StateChangeRequest` + +| Field | Type | +|-------|------| +| `RequestedState` | `GameplayTag` | +| `Requester` | `Actor` (Object Reference) | +| `Priority` | `Integer` | +| `Reason` | `String` | +| `Timestamp` | `Float` | + +### S_StateGatingRule +1. Name: `S_StateGatingRule` + +| Field | Type | +|-------|------| +| `ActionTag` | `GameplayTag` | +| `BlockedByStates` | `Array` | +| `RequiresStates` | `Array` | +| `BlockedByOverlays` | `Array` | +| `bRequiresAuthority` | `Boolean` | +| `CooldownSeconds` | `Float` | +| `RulePriority` | `Integer` | + +### S_ActionPermissionResult +1. Name: `S_ActionPermissionResult` + +| Field | Type | +|-------|------| +| `bPermitted` | `Boolean` | +| `ResultCode` | `E_ActionRequestResult` | +| `BlockingState` | `GameplayTag` | +| `BlockReason` | `String` | + +--- + +## Data Asset — DA_StateGatingTable + +### Create +1. Content Browser → `Content/Framework/State/` +2. Right-click → **Miscellaneous → Data Asset** +3. Class: `PrimaryDataAsset` +4. Name: `DA_StateGatingTable` + +### Variables to Add +| Variable | Type | Default | +|----------|------|---------| +| `GatingRules` | `Array` | Empty — populate below | +| `ForceStackRules` | `Array` | Empty | + +### Populate GatingRules (37 action rules — key examples) + +| Action | Blocked By | +|--------|-----------| +| `Framework.State.Action.Sprint` | Crouching, Aiming, Firing, Injured | +| `Framework.State.Action.Fire` | Sprinting, Reloading, Dead, Menu | +| `Framework.State.Action.Reload` | Sprinting, Firing, Melee, Dead | +| `Framework.State.Action.Jump` | Crouching, Dead, CutsceneBound | +| `Framework.State.Action.Interact` | Sprinting, Firing, Dead, Menu | +| `Framework.State.Action.Hide` | Sprinting, Firing, Carrying | +| `Framework.State.Action.Melee` | Reloading, Inspecting, Dead | +| `Framework.State.Action.UseItem` | Dead, Staggered, CutsceneBound | +| `Framework.State.Action.Crouch` | Sprinting, Falling, Vaulting | +| `Framework.State.Action.Inspect` | Sprinting, Hiding, Dead, Menu | +| `Framework.State.Action.Dialogue` | Sprinting, Firing, Hiding, Dead | +| `Framework.State.Action.Vault` | Crouching, Aiming, Firing, Carrying | +| `Framework.State.Action.Aim` | Sprinting, Reloading, Melee, Dead | +| `Framework.State.Action.Menu` | Dead, CutsceneBound (always permitted otherwise) | +| `Framework.State.Action.Dead` | Always permitted (force-state — overrides everything) | + +--- + +## Component — BPC_StateManager + +Already covered in C++ (`Source/Framework/Public/Player/BPC_StateManager.h`). + +### Attach to Pawn +1. Open player pawn Blueprint +2. **Add Component → BPC_StateManager** +3. In Details → `Gating Table` → assign `DA_StateGatingTable` +4. Set `Default Action State` → `Framework.State.Action.Idle` + +--- + +## Test It +- [ ] All 4 enums created with correct values +- [ ] All 3 structs created with correct fields +- [ ] `DA_StateGatingTable` populated with 37 rules +- [ ] PIE: `IsActionPermitted(SprintTag)` returns `false` when crouching +- [ ] `RequestStateChange(Fire)` returns `Granted` when idle +- [ ] `ForceStateChange(Dead)` → `IsActionPermitted(AnyTag)` returns `false` +- [ ] `RestorePreviousState()` → previous state restored