Files
UE5-Modular-Game-Framework/docs/architecture/bpc-statemanager.md
Lefteris Notas fee12b115f Refactor GameplayTag documentation and implementation
- Updated references from GI_GameTagRegistry to DA_GameTagRegistry in architecture overview and implementation patterns documentation.
- Added new Blueprint specification for GI_StarterGameInstance, detailing its purpose, configuration, and integration pattern.
- Introduced DA_GameTagRegistry Blueprint specification, centralizing GameplayTag management and providing functions for tag validation and logging.
- Created documentation for the Starter GameInstance, outlining its role in the project setup and how other systems can integrate with it.
2026-05-20 14:31:52 +03:00

53 KiB
Raw Blame History

BPC_StateManager — Central Nervous System for the Modular Game Framework

Architecture Document | UE 5.55.7 | GASP Compatible


1. Problem Statement

The framework has 129 systems, each maintaining its own state machine with 36+ state-gated actions. Without a central authority, systems must hardcode knowledge of every other system's state to know whether an action is permitted. This creates tight coupling and makes adding new states (e.g., a new traversal type or weapon mode) a cascade-change across dozens of files. BPC_StateManager solves this by being the single source of truth for "what can the player do right now?"


2. Proposed Solution

flowchart TD
    A[Any System: Request Action] --> B[BPC_StateManager.RequestStateChange]
    B --> C{Check Gating Rules}
    C -->|Permitted| D[Set NewState + Fire OnStateChanged]
    D --> E[Notify: ABP_GASP via SetOverlayState]
    D --> F[Notify: BPC_MovementStateSystem]
    D --> G[Notify: SS_EnhancedInputManager - context switch]
    D --> H[Notify: All bound listeners]
    C -->|Blocked| I[Return false + Reason]
    I --> J[Requester handles rejection - show prompt, play denied sound]

BPC_StateManager sits on the Player Character. It does NOT control GASP's Motion Matching, Camera Manager, or AnimBP. It communicates with GASP exclusively through overlay states and animation notify events. Every other system queries IsActionPermitted(Tag) before executing.


3. File Structure

Content/Framework/Player/
  BPC_StateManager.uasset          # NEW — Central state authority

Content/Framework/Core/
  E_PlayerActionState.uasset       # NEW — Exclusive action state enum  
  E_OverlayState.uasset            # NEW — Upper-body overlay state enum
  E_ActionRequestResult.uasset     # NEW — Result enum for RequestStateChange
  S_StateChangeRequest.uasset      # NEW — Struct for state change request
  S_StateGatingRule.uasset         # NEW — Struct for gating rule
  DA_StateGatingTable.uasset       # NEW — Data Asset: all gating rules

4. Enums

4.1 E_PlayerActionState — Exclusive Action States

Enum Name: E_PlayerActionState
(DisplayName = "Player Action State")

Values:
  Idle = 0                    // Standing, not performing any action
  Walking = 1                 // Moving at walk speed
  Jogging = 2                 // Moving at jog speed
  Sprinting = 3               // Moving at sprint speed (stamina draining)
  Crouching = 4               // Crouched posture, possibly moving
  Crawling = 5                // Prone, crawling
  Sitting = 6                 // Sitting on surface — immobile, can look around
  Vaulting = 7                // Transient — vaulting over obstacle
  Climbing = 8                // Ledge or ladder climbing
  Sliding = 9                 // Transient — sliding under or down
  Interacting = 10            // Performing a hold/press interaction
  Inspecting = 11             // Inspecting an item in close-up view
  InInventory = 12            // Inventory menu is open
  InJournal = 13              // Journal/document viewer is open
  InPauseMenu = 14            // Pause menu is open
  InDialogue = 15             // In dialogue with an NPC
  InCutscene = 16             // Pre-authored cutscene playing
  SwingMelee = 17             // Performing a melee attack
  AimingFirearm = 18          // Aiming a firearm
  FiringFirearm = 19          // Firing a firearm (transient)
  Reloading = 20              // Reloading a firearm
  DeployingShield = 21        // Raising a shield
  Hiding = 22                 // Inside a hiding spot (enclosed/behind/under/shadow)
  Peeking = 23                // Peeking from behind cover
  GrabbingObject = 24         // Holding a physics object
  UsingObject = 25            // Using a world object (lever, panel, etc.)
  Dead = 26                   // Dead — death animation playing or death loop active
  InVoidSpace = 27            // In alt death / void space
  InPuzzle = 28               // Using a puzzle device
  InTrialScenario = 29        // In a timed trial scenario
  InMainMenu = 30             // At main menu (no gameplay)
  Loading = 31                // Loading screen active
  DraggingCorpse = 32         // Dragging a physics body
  HoldingBreath = 33          // Holding breath while hiding
  Injured = 34                // Health ≤ threshold — reduced speed, limp anim, restricted actions
  Staggered = 35              // Transient — hit reaction / stagger
  KnockedDown = 36            // Knocked to ground
  Exhausted = 37              // Stamina fully depleted — panting/immobile
  Panicked = 38               // Stress at catatonic tier — stumble/freeze
  PushingObject = 39          // Pushing a movable object
  AimingThrowable = 40        // Aiming a throwable item
  ThrowingItem = 41           // Throwing an item (transient)
  UsingConsumable = 42        // Using a consumable (heal, inject, etc.)
  InPhotoMode = 43            // Photo mode active — free cam, no gameplay input
  CustomAction = 44           // Reserved for mod/expansion actions

4.2 E_PlayerVitalSignals — Vital Signal Enum for HeartRate / Breathing

Enum Name: E_PlayerVitalSignals
(DisplayName = "Player Vital Signals")

Values:
  Normal = 0                  // Heart rate 60-80 BPM — resting/exploring
  Elevated = 1                // Heart rate 80-110 BPM — sprinting, light combat
  High = 2                    // Heart rate 110-150 BPM — heavy combat, chased
  Critical = 3                // Heart rate 150+ BPM — near death, terrified
  Erratic = 4                 // Irregular rhythm — panic state, hallucinating

4.3 E_OverlayState — Upper-Body Overlay for GASP AnimBP

Enum Name: E_OverlayState
(DisplayName = "Upper Body Overlay State")

Values:
  Empty = 0                   // No overlay — default locomotion
  Flashlight = 1              // Holding flashlight
  Melee_OneHanded = 2         // One-handed melee weapon (knife, baton)
  Melee_TwoHanded = 3         // Two-handed melee weapon (axe, pipe)
  Pistol = 4                  // Pistol / handgun
  Shotgun = 5                 // Shotgun
  Rifle = 6                   // Rifle / carbine
  Shield = 7                  // Shield only
  Shield_And_Melee = 8        // Shield + one-handed melee
  Shield_And_Pistol = 9       // Shield + pistol
  DualWield = 10              // Dual-wielding one-handed weapons
  Inspect = 11                // Inspecting an object
  DualHand_Flashlight_Melee = 12  // Flashlight + melee
  Injured = 13                // Injured arm (lowered, favoring)
  Throwable = 14              // Holding a throwable (grenade, bottle)
  Consumable = 15             // Using consumable (syringe, bandage)
  TwoHanded_Heavy = 16        // Heavy two-handed (sledgehammer, chainsaw)
  EmptyHands_Raised = 17      // Empty hands raised (surrender, blocking bare)

4.4 E_ActionRequestResult

Enum Name: E_ActionRequestResult

Values:
  Permitted = 0               // State change approved
  Blocked_CurrentState = 1    // Blocked because player is in an incompatible state
  Blocked_GamePhase = 2       // Blocked by game phase (menu, cutscene, loading)
  Blocked_Dead = 3            // Player is dead
  Blocked_Stamina = 4         // Insufficient stamina
  Blocked_Equipment = 5       // Missing required equipment
  Blocked_Cooldown = 6        // Action on cooldown
  Blocked_Custom = 7          // Blocked by a custom gating rule

5. Structs

5.1 S_StateChangeRequest

Field Type Description
RequestedState E_PlayerActionState The state the requester wants to enter
RequesterTag GameplayTag Identifies which system is requesting
Priority Integer 0=Normal, 50=High, 100=Force (bypasses all gating)
OverrideReason Text Human-readable reason for override/force

5.2 S_StateGatingRule

Field Type Description
ActionTag GameplayTag The action being gated
BlockedStates Array<E_PlayerActionState> States that block this action
BlockedGamePhases Array<E_GamePhase> Game phases that block this
RequiredTags GameplayTagContainer Tags the player must have
BlockedTags GameplayTagContainer Tags the player must NOT have
BlockReason Text Reason shown to player when blocked
Priority Integer Rule evaluation order (lower = checked first)

5.3 S_ActionPermissionResult

Field Type Description
bPermitted Boolean Whether the action is allowed
BlockReason Text Why it was blocked (if not permitted)
ResultCode E_ActionRequestResult Machine-readable result code

6. Variables

Configuration (Instance Editable, Expose On Spawn)

Variable Type Default Category Description
GatingRules Array<S_StateGatingRule> DefaultRules State Config All gating rules defined in blueprint
DefaultState E_PlayerActionState Idle State Config State to initialize on BeginPlay
bLogStateTransitions Boolean false Debug Log all state transitions to console
StateTransitionDelay Float 0.0 State Config Minimum time between state changes (anti-spam)
DefaultOverlay E_OverlayState Empty State Config Default overlay state
InjuryHealthThreshold Float 0.30 State Config Health ratio (0-1) below which player becomes Injured
HeartRateBase Float 70.0 State Config Base heart rate in BPM when calm
HeartRateMax Float 180.0 State Config Maximum heart rate in BPM

Internal (Private / Protected)

Variable Type Default Category Description
CurrentState E_PlayerActionState Idle State Current exclusive action state
PreviousState E_PlayerActionState Idle State Previous state for transitions
CurrentOverlay E_OverlayState Empty State Current upper-body overlay state
LastStateChangeTime Float 0.0 State Game time of last state change
StateHistory Array<E_PlayerActionState> Empty State History of last N states for debugging
ForceStack Array<E_PlayerActionState> Empty State Stack of forced states for nested overrides
bIsTransitioning Boolean false State True during a state transition
PendingRequests Array<S_StateChangeRequest> Empty State Queued requests during transition
CachedABPRef ABP_GASP (soft ref) None State Cached reference to GASP AnimBP
CurrentActionFlags Map<GameplayTag, Float> Empty State Active action tags with duration/timestamp
CurrentHeartRate Float 70.0 Vital Signs Current heart rate in BPM (recalculated each tick)
CurrentVitalSignal E_PlayerVitalSignals Normal Vital Signs Current vital signal category
bIsInjured Boolean false Vital Signs True when health ≤ InjuryHealthThreshold
InjurySpeedMultiplier Float 0.65 Vital Signs Walk speed multiplier when injured

7. Functions / Custom Events

7.1 RequestStateChange

RequestStateChange(NewState: E_PlayerActionState, RequesterTag: GameplayTag, Priority: Integer = 0) → E_ActionRequestResult

Description: The primary entry point. Any system requests to transition the player to a new exclusive action state. State Manager checks all gating rules and returns the result.

Flow:

  1. If Priority == 100 (Force): bypass gating, go directly to step 6
  2. If bIsTransitioning: queue the request on PendingRequests, return Blocked_CurrentState
  3. Check time since LastStateChangeTime — if < StateTransitionDelay: return Blocked_Cooldown
  4. If CurrentState == Dead and NewState != Idle (respawn): return Blocked_Dead
  5. Iterate GatingRules matching RequesterTag:
    • If NewState is in BlockedStates for any rule: return Blocked_CurrentState with BlockReason
    • If CurrentGamePhase is in BlockedGamePhases: return Blocked_GamePhase
    • If required tags missing or blocked tags present: return appropriate result
  6. Execute state transition (see 7.7)
  7. Return Permitted

7.2 ForceStateChange

ForceStateChange(NewState: E_PlayerActionState, Reason: Text) → void

Description: Bypasses ALL gating. Used by death system, cutscene bridge, void space entry, and developer cheats. Pushes current state onto ForceStack.

Flow:

  1. If ForceStack already has NewState at top: return (prevents double-force)
  2. Push CurrentState onto ForceStack
  3. Execute state transition with NewState
  4. Log reason to console if bLogStateTransitions

7.3 RestorePreviousState

RestorePreviousState() → void

Description: Pops the force stack. Used when exiting cutscenes, void space, or force-override states.

Flow:

  1. If ForceStack is empty:
    • Set to Idle or previously known normal state
    • Return
  2. Pop top of ForceStack
  3. Execute state transition to popped state

7.4 GetCurrentState

GetCurrentState() → E_PlayerActionState

Pure getter — returns CurrentState.

7.5 GetPreviousState

GetPreviousState() → E_PlayerActionState

Pure getter — returns PreviousState.

7.6 IsActionPermitted

IsActionPermitted(ActionTag: GameplayTag) → S_ActionPermissionResult

Description: Non-mutating query. Does NOT change state. Any system can ask "can I do this right now?"

Flow:

  1. Find all GatingRules where ActionTag matches
  2. Check CurrentState against BlockedStates
  3. Check GI_GameFramework.CurrentGamePhase against BlockedGamePhases
  4. Check RequiredTags and BlockedTags
  5. Return S_ActionPermissionResult with bPermitted, BlockReason, ResultCode

7.7 SetOverlayState

SetOverlayState(Overlay: E_OverlayState) → void

Description: Tells GASP AnimBP which upper-body overlay to use. Does not change E_PlayerActionState. Called by equipment system, weapon system, and inspection.

Flow:

  1. If Overlay == CurrentOverlay: return
  2. Set CurrentOverlay = Overlay
  3. If CachedABPRef is valid: set ABP_GASP.OverlayState = Overlay (via I_AnimNotifyInterface or direct variable set)
  4. Fire OnOverlayStateChanged
  5. Update visible first-person arm mesh if applicable (via BPC_EmbodimentSystem)

7.8 CanTransitionTo

CanTransitionTo(TargetState: E_PlayerActionState) → S_ActionPermissionResult

Description: Pre-flight check without executing. Used by UI to enable/disable buttons.

7.9 UpdateHeartRate (Tick-Driven)

UpdateHeartRate() → void

Description: Recalculates heart rate each tick based on current state, stress, stamina, and health. Evaluates E_PlayerVitalSignals thresholds. Called automatically from Tick.

Flow:

  1. Calculate base rate:
    • Idle/Walking/Sitting → HeartRateBase (60-80)
    • Jogging → Base + 15
    • Sprinting → Base + 30
    • Combat (any weapon state) → Base + 40
    • Hiding/Peeking → Base + 5 (suppressed by stealth)
    • Panicked → Base + 50
    • Dead → 0
  2. Apply health modifier: (1.0 - HealthRatio) * 20 added
  3. Apply stress modifier: StressRatio * 30 added
  4. Apply stamina modifier: if Exhausted → +25
  5. Clamp to HeartRateMax
  6. Smooth interpolation: CurrentHeartRate = FMath::FInterpTo(CurrentHeartRate, Target, DeltaTime, 3.0)
  7. Evaluate E_PlayerVitalSignals from CurrentHeartRate:
    • ≤ 80 → Normal
    • ≤ 110 → Elevated
    • ≤ 150 → High
    • ≤ 180 → Critical
    • If Panicked state OR FearSystem active → Erratic (overrides BPM threshold)
  8. If CurrentVitalSignal changed, fire OnVitalSignalChanged
  9. Write CurrentHeartRate to ABP_GASP.HeartRate for breathing animation blend

7.10 EvaluateInjuryState

EvaluateInjuryState() → void

Description: Called when health changes. Sets bIsInjured flag and auto-transitions to/from Injured state if health crosses threshold.

Flow:

  1. Get HealthRatio from BPC_HealthSystem.CurrentHealth / MaxHealth
  2. If HealthRatio <= InjuryHealthThreshold AND !bIsInjured:
    • Set bIsInjured = true
    • If CurrentState is Idle/Walking/Jogging/Sprinting/Crouching: RequestStateChange(Injured, Tag.Health)
    • Apply InjurySpeedMultiplier to movement
  3. If HealthRatio > InjuryHealthThreshold AND bIsInjured:
    • Set bIsInjured = false
    • If CurrentState == Injured: RequestStateChange(Idle, Tag.Health)
    • Restore movement speed

7.11 IsInCombat

IsInCombat() → Boolean

Description: Convenience — returns true if CurrentState is SwingMelee, AimingFirearm, FiringFirearm, Reloading, or DeployingShield.

7.12 IsMovementBlocked

IsMovementBlocked() → Boolean

Description: Convenience — returns true if player cannot move. True when CurrentState is Dead, InCutscene, InDialogue, InInventory, InJournal, InPauseMenu, InMainMenu, UsingObject, Sitting, KnockedDown, Panicked, Staggered, Exhausted, Loading, InPhotoMode.

7.13 IsMovementRestricted

IsMovementRestricted() → Boolean

Description: Convenience — returns true if movement is partially restricted (slowed/impaired but not fully blocked). True when CurrentState is Injured, Crouching, Crawling, HoldingBreath, AimingFirearm, DeployingShield, Hiding, Peeking, GrabbingObject, PushingObject, UsingConsumable.

7.14 GetHeartRate

GetHeartRate() → Float

Description: Returns CurrentHeartRate in BPM. Used by audio system for heartbeat SFX tempo, by UI for vitals display, by haptic system for controller pulse rate.

7.15 GetVitalSignal

GetVitalSignal() → E_PlayerVitalSignals

Description: Returns CurrentVitalSignal. Used by atmosphere system (audio tension layers), camera (breathing sway), and narrative system (dialogue conditionals).

7.16 CanEquipWeapon

CanEquipWeapon() → Boolean

Description: Checks if weapon equip is permitted in current state.

7.17 RegisterActionFlag / UnregisterActionFlag / HasActionFlag

RegisterActionFlag(Tag: GameplayTag, Duration: Float = -1.0) → void
UnregisterActionFlag(Tag: GameplayTag) → void
HasActionFlag(Tag: GameplayTag) → Boolean

Description: Lightweight flag system for transient action permissions. Duration of -1 = permanent until unregistered. Used by systems to mark "I am currently in cooldown" or "I am currently active."

7.18 Initialize (BeginPlay override)

Flow:

  1. Get owner as Character
  2. Cache reference to ABP_GASP from character's skeletal mesh
  3. Set CurrentState = DefaultState, CurrentOverlay = DefaultOverlay
  4. Populate default GatingRules from DA_StateGatingTable if assigned
  5. Bind to GI_GameFramework.OnGamePhaseChanged (for game-phase-gated rules)
  6. Bind to BPC_HealthSystem.OnDeath (auto-call ForceStateChange(Dead))
  7. Register with DA_GameTagRegistry for tag-based queries
  8. Bind to BPC_HealthSystem.OnHealthChanged → call EvaluateInjuryState()
  9. Bind to BPC_StressSystem.OnStressTierChanged → recalculate heart rate
  10. Bind to BPC_StaminaSystem.OnExhaustionStateChanged → recalculate heart rate
  11. Enable component tick (required for heart rate smoothing)

8. Event Dispatchers

Dispatcher Parameters Bind Access Description
OnStateChanged OldState: E_PlayerActionState, NewState: E_PlayerActionState Public Fired on any state transition
OnStateChangeRequested Request: S_StateChangeRequest Public Fired when request is made (before evaluation)
OnStateChangeDenied Request: S_StateChangeRequest, Result: E_ActionRequestResult, Reason: Text Public Fired when a request is denied
OnOverlayStateChanged OldOverlay: E_OverlayState, NewOverlay: E_OverlayState Public Fired on overlay change
OnActionFlagRegistered Tag: GameplayTag, Duration: Float Public Fired when a flag is registered
OnActionFlagExpired Tag: GameplayTag Public Fired when a timed flag expires
OnForceOverridePushed ForcedState: E_PlayerActionState, PoppedState: E_PlayerActionState Public Fired when force stack is pushed
OnForceOverridePopped RestoredState: E_PlayerActionState Public Fired when force stack is popped
OnVitalSignalChanged OldSignal: E_PlayerVitalSignals, NewSignal: E_PlayerVitalSignals Public Fired when vital signal tier changes
OnHeartRateChanged NewBPM: Float Public Fired when heart rate changes significantly (±5 BPM)
OnInjuryStateChanged bIsInjured: Boolean, HealthRatio: Float Public Fired when injury state toggles

9. State Gating Function Table

Complete Action → Blocking State Matrix

Requested Action (Tag) Blocked If CurrentState Is Reason
Action.Move.Walk Dead, InCutscene, InDialogue, KnockedDown, Panicked, Exhausted, Sitting, InInventory, InJournal, InPauseMenu, UsingObject, GrabbingObject, InPhotoMode Movement disabled
Action.Move.Sprint Dead, InCutscene, InDialogue, Crouching, Crawling, Hiding, Peeking, Sitting, KnockedDown, Exhausted, Panicked, Reloading, UsingConsumable, Injured Sprint requires standing + uninjured
Action.Move.Crouch Dead, Vaulting, Climbing, Sliding, InCutscene, InDialogue, Sitting, KnockedDown, Exhausted, Panicked Cannot crouch during traversal
Action.Move.Crawl Dead, Standing required states, Vaulting, Climbing, InCutscene, Sitting, KnockedDown Must be prone first
Action.Move.Jump Dead, Hiding, Peeking, Crouching (maybe), Crawling, InCutscene, InDialogue, Sitting, KnockedDown, Panicked, Exhausted, UsingObject, InInventory, InPauseMenu Jump blocked
Action.Move.Sit Dead, Vaulting, Climbing, Hiding, SwingMelee, FiringFirearm, Reloading, KnockedDown, Panicked, InInventory, InCutscene, InDialogue Sit requires neutral standing state
Action.Move.StandUp Must be Sitting state Must be sitting first
Action.Traversal.Vault Dead, Hiding, Peeking, InCutscene, InDialogue, Reloading, SwingMelee, FiringFirearm, KnockedDown, Panicked Traversal requires free hands
Action.Traversal.Climb Dead, InCutscene, InDialogue, Reloading, SwingMelee, KnockedDown, Panicked Climbing requires free hands
Action.Traversal.Slide Dead, InCutscene, InDialogue, Reloading, SwingMelee, KnockedDown, Panicked Slide requires two hands
Action.Hide.Enter Dead, InCutscene, InDialogue, SwingMelee, FiringFirearm, Reloading, Vaulting, Climbing, KnockedDown, Panicked, Exhausted, GrabbingObject Hide requires exposed state
Action.Hide.Peek Dead, SwingMelee, FiringFirearm, Reloading Peek only from hidden
Action.Hide.Exit InCutscene, Dead (if not force-exit) Forced exit allowed
Action.Interact.Hold Dead, InCutscene, SwingMelee, FiringFirearm, Reloading, Hiding, Peeking, Vaulting, Climbing, KnockedDown, Panicked, InInventory, InPauseMenu, InDialogue, UsingObject Interaction requires free state
Action.Interact.Instant Dead, InCutscene, KnockedDown, Panicked Instant interaction only blocked by critical
Action.Inventory.Open Dead, InCutscene, Vaulting, Climbing, SwingMelee, FiringFirearm, Reloading, KnockedDown, Panicked, Hiding, GrabbingObject, InDialogue, InPuzzle, InTrialScenario Inventory blocked during actions
Action.Inventory.Close (always permitted — but may not open if blocked) Close always works
Action.Inventory.Equip Dead, InCutscene, Vaulting, Climbing, KnockedDown, Panicked Equip requires stability
Action.Inventory.UseItem Dead, InCutscene, Vaulting, Climbing, KnockedDown, Panicked, Hiding Use requires stable state
Action.Weapon.Fire Dead, Hiding, Peeking, Reloading, Vaulting, Climbing, InCutscene, InDialogue, KnockedDown, Panicked, InInventory, InPauseMenu, UsingConsumable, GrabbingObject Cannot fire in these states
Action.Weapon.Aim Dead, Hiding, Peeking, Vaulting, Climbing, InCutscene, InDialogue, KnockedDown, Panicked, InInventory, InPauseMenu, GrabbingObject Cannot aim
Action.Weapon.Reload Dead, Hiding, Peeking, Vaulting, Climbing, SwingMelee, InCutscene, InDialogue, KnockedDown, Panicked, InPauseMenu, GrabbingObject Cannot reload
Action.Weapon.Melee Dead, Hiding, Peeking, Reloading, Vaulting, Climbing, InCutscene, InDialogue, KnockedDown, Panicked, InInventory, InPauseMenu, GrabbingObject, UsingConsumable Cannot melee
Action.Weapon.Block Dead, Reloading, Vaulting, Climbing, InCutscene, KnockedDown, Panicked, Hiding, InInventory, InPauseMenu Cannot block
Action.Dialogue.Start Dead, InCutscene, Vaulting, Climbing, SwingMelee, FiringFirearm, Hiding, InInventory, InPauseMenu, Reloading, KnockedDown, Panicked Dialogue requires neutral state
Action.Dialogue.Choose Must be InDialogue state Must be in dialogue
Action.Cutscene.Play (handled by GI_GameFramework game phase, not action state) Cutscene overrides via Force
Action.Cutscene.Skip Must be InCutscene, bCanSkip Must be in cutscene
Action.HoldBreath Hiding state only, not Peeking Breath hold only while hidden
Action.Grab.PhysicsObject Dead, InCutscene, Hiding, Vaulting, Climbing, Reloading, SwingMelee, FiringFirearm, KnockedDown, Panicked, InInventory, InPauseMenu Grab requires free hands
Action.Puzzle.Use Dead, InCutscene, InDialogue, Vaulting, Climbing, Hiding, SwingMelee, FiringFirearm, Reloading, KnockedDown, Panicked Puzzle requires focus
Action.Consumable.Use Dead, InCutscene, Vaulting, Climbing, Hiding, SwingMelee, FiringFirearm, Reloading, KnockedDown, Panicked, InInventory Consumable requires free hands
Action.Pause.Open InCutscene, Dead, InMainMenu, Loading Cannot pause in cutscene/death
Action.Pause.Close (always permitted) Close always works
Action.Journal.Open Dead, InCutscene, InDialogue, Vaulting, Climbing, Hiding, SwingMelee, FiringFirearm, Reloading, KnockedDown, Panicked, InInventory, InPuzzle, InTrialScenario Journal requires neutral state
Action.Settings.Open InCutscene, Loading Settings limited during cutscene
Action.MainMenu.Return (always permitted) Return to menu always works
Action.QuestLog.Open Same as Journal Same blocking states
Action.Map.Open Dead, InCutscene, Vaulting, Climbing, Hiding, InInventory, InPauseMenu Map in neutral/explore states
Action.Throwable.Aim Dead, Hiding, Peeking, Vaulting, Climbing, InCutscene, InDialogue, Reloading, KnockedDown, Panicked, InInventory, InPauseMenu Throw requires free hands
Action.Throwable.Throw Same as Aim + must be in AimingThrowable state Must be aiming first
Action.PhotoMode.Enter Dead, InCutscene, InDialogue, Vaulting, Climbing, Hiding, SwingMelee, FiringFirearm, KnockedDown, Panicked Photo mode requires neutral state
Action.PhotoMode.Exit Must be InPhotoMode Must be in photo mode

Restricted Movement States (Enclosed Spaces / Injured)

The following states impose movement restrictions beyond simply blocked/unblocked:

State Walk Allowed Sprint Allowed Jump Allowed Crouch Allowed Camera Freelook Notes
Sitting No No No No Yes (head only) Must StandUp to move. Enter via world interaction point (bench, chair, floor)
Injured Slowed (×0.65) No No Yes Yes Limp animation. Heals above threshold. Sprint/jump blocked
Hiding (Locker/Under) No No No No No (fixed cam) Fully enclosed — zero movement
Hiding (BehindCover) No No No N/A (already crouched) Limited (peek) Can peek but cannot leave cover position
Hiding (InShadow) Yes (slow) No No Yes Yes Standing in shadow — can move but sprint blocked
Hiding (TallGrass) Yes (crouch-walk) No No Yes Yes Crouch-moving through vegetation
Staggered No No No No Locked Forced animation — no input
KnockedDown No No No No Locked (ground view) Must GetUp animation first
Exhausted No No No No Yes Heavy breathing — must wait for stamina regen
Panicked Stumble No No No Random jerks Camera shakes, movement impaired
HoldingBreath No No No No Yes Must release breath before moving
InPhotoMode No (free cam only) No No No Full (free cam) Gameplay input disabled, camera only

10. GASP Integration Notes

10.1 What the State Manager READS from GASP

GASP Variable / Event How Used
ABP_GASP.bStrafing Read to detect if GASP is in strafing mode — informs combat state eligibility
ABP_GASP.bSprinting Read to confirm sprint state when BPC_MovementStateSystem reports sprint
ABP_GASP.MovementMode Read to cross-validate BPC_MovementStateSystem.CurrentMovementMode
ABP_GASP.GroundState Read to know if airborne (blocks certain actions)
AnimNotify_StateEnter Any GASP notify received via I_AnimNotifyInterface is forwarded to listeners

10.2 What the State Manager WRITES to GASP

GASP Variable / Event How Written
ABP_GASP.OverlayState Set via SetOverlayState(E_OverlayState) — direct enum value set on cached AnimBP reference
ABP_GASP.bIsInAction Set to true when CurrentState is any action state (not Idle/Walking/Jogging/Sprinting/Crouching)
ABP_GASP.ActionIntensity Float 0.01.0 set based on action type: 0.0=Idle, 0.3=Interacting, 0.7=SwingMelee, 1.0=FiringFirearm
AnimNotify_OverlayChanged Fired when overlay changes — GASP blends to new upper-body pose

10.3 What the State Manager NEVER Touches

  • Motion Matching Database — GASP's motion matching is sacred, never modified
  • Camera Manager — Camera blends, FOV, and offsets belong to BPC_CameraStateLayer
  • GASP's Internal State Machine — Ground/air transitions, rotation mode, strafing logic
  • Animation Blueprint Graph Logic — Only sets variables, never modifies graph nodes
  • GASP's Root Motion — Root motion extraction is GASP's domain

10.4 Overlay State Pipeline

sequenceDiagram
    participant ES as EquipmentSystem
    participant SM as BPC_StateManager
    participant GASP as ABP_GASP
    participant AP as AnimPose

    ES->>SM: SetOverlayState(Pistol)
    SM->>SM: CurrentOverlay = Pistol
    SM->>GASP: ABP_GASP.OverlayState = Pistol
    GASP->>GASP: Blend upper body to Pistol pose
    GASP->>AP: Apply overlay pose
    SM->>SM: Fire OnOverlayStateChanged
    SM->>ES: Confirm overlay set

11. Blueprint Flow Diagram — RequestStateChange

flowchart TD
    A[System calls RequestStateChange] --> B{Priority == 100?}
    B -->|Yes Force| C[ExecuteStateTransition]
    B -->|No| D{bIsTransitioning?}
    D -->|Yes| E[Queue on PendingRequests - return Blocked_CurrentState]
    D -->|No| F{Within StateTransitionDelay?}
    F -->|Yes| G[Return Blocked_Cooldown]
    F -->|No| H{CurrentState == Dead?}
    H -->|Yes and NewState != Idle| I[Return Blocked_Dead]
    H -->|No| J[Fire OnStateChangeRequested]
    J --> K[Evaluate GatingRules for RequesterTag]
    K --> L{NewState in BlockedStates?}
    L -->|Yes| M[Fire OnStateChangeDenied - return Blocked_CurrentState]
    L -->|No| N{GamePhase blocks?}
    N -->|Yes| O[Fire OnStateChangeDenied - return Blocked_GamePhase]
    N -->|No| P{Required tags missing?}
    P -->|Yes| Q[Fire OnStateChangeDenied - return reason]
    P -->|No| R{Blocked tags present?}
    R -->|Yes| Q
    R -->|No| C
    C --> S[PreviousState = CurrentState]
    S --> T[CurrentState = NewState]
    T --> U[Update bIsInAction on GASP]
    U --> V[Update ActionIntensity on GASP]
    V --> W[Fire OnStateChanged - OldState, NewState]
    W --> X[Notify SS_EnhancedInputManager - context change]
    X --> Y[Return Permitted]

12. Communication Matrix

Who Talks How What Is Sent
Any System RequestStateChange() E_PlayerActionState, RequesterTag: GameplayTag, Priority: Int
Any System IsActionPermitted() GameplayTagS_ActionPermissionResult
BPC_StateManager ABP_GASP (Direct variable set) OverlayState, bIsInAction, ActionIntensity
BPC_StateManager Dispatcher: OnStateChanged OldState, NewState to all bound listeners
BPC_StateManager Dispatcher: OnOverlayStateChanged OldOverlay, NewOverlay to BPC_EmbodimentSystem, WBP_HUDController
BPC_StateManager Dispatcher: OnStateChangeDenied Request, Result, Reason to WBP_InteractionPromptDisplay, WBP_NotificationToast
BPC_StateManager SS_EnhancedInputManager (Direct) Context change notification when state changes
BPC_StateManager BPC_MovementStateSystem (Direct) Receives OnMovementModeChanged to track walking/sprinting
BPC_StateManager BPC_HealthSystem (Listener on OnDeath) Auto-transitions to Dead state
GI_GameFramework Dispatcher: OnGamePhaseChanged Notifies StateManager of phase changes for gating
BPC_CameraStateLayer Dispatcher: OnStateChanged Adjusts camera based on state (e.g., combat FOV)
BPC_StressSystem Direct: IsActionPermitted Checks if stress effects are currently permitted
WBP_InteractionPromptDisplay Listener on OnStateChanged Shows/hides interaction prompts based on state

13. Testing Checklist

  • RequestStateChange with valid state returns Permitted and fires OnStateChanged
  • RequestStateChange while Dead (except to Idle) returns Blocked_Dead
  • RequestStateChange during transition queues and returns Blocked_CurrentState
  • ForceStateChange bypasses all gating and pushes to ForceStack
  • RestorePreviousState pops ForceStack and restores correct state
  • IsActionPermitted returns correct S_ActionPermissionResult for all 35+ actions
  • SetOverlayState correctly writes to ABP_GASP.OverlayState
  • Overlay change fires OnOverlayStateChanged dispatcher
  • Game phase change (MainMenu → InGame → Cutscene) correctly gates actions
  • Death auto-transitions to Dead state via BPC_HealthSystem.OnDeath binding
  • Respawn restores previous state from ForceStack
  • Rapid state change requests are throttled by StateTransitionDelay
  • IsInCombat() returns true for SwingMelee, AimingFirearm, FiringFirearm, Reloading, DeployingShield
  • IsMovementBlocked() returns true for all blocking states
  • Edge case: ForceStateChange called twice with same state — second call is no-op
  • Edge case: RestorePreviousState with empty ForceStack defaults to Idle
  • Edge case: State Manager handles owner destruction gracefully (null checks on cached ABP ref)

14. Reuse Notes

  • BPC_StateManager replaces the need for every system to check every other system's state. Systems call IsActionPermitted(Tag) instead of IsPlayerInState(X) && !IsPlayerInState(Y) && ...
  • New states can be added to E_PlayerActionState and DA_StateGatingTable without modifying the State Manager blueprint logic.
  • The DA_StateGatingTable Data Asset allows designers to tune gating rules without opening blueprints.
  • Force stack pattern supports nested force overrides (e.g., Death → Cutscene flashback → Respawn).
  • GASP variables bIsInAction and ActionIntensity allow AnimBP to blend differently during action vs exploration without the AnimBP knowing about game logic.

Part B — Chooser Table Candidate Audit

Complete Chooser Table Candidate Catalog (32 identified)

# Chooser Table Name Input Columns (Name + Type) Output Type Row Logic Summary Used By
1 Damage Resistance Lookup E_DamageType (enum), bIsStackable (bool) Float (multiplier) Map DamageType → resistance multiplier; accumulate if stackable BPC_HealthSystem (08)
2 Exhaustion Tier CurrentStamina/MaxStamina (float ratio) E_ExhaustionState ≤ ExhaustedThreshold → Exhausted; ≤ LowThreshold → Low; else Normal BPC_StaminaSystem (09)
3 Stress Tier CurrentStress (float) E_StressTier Descending threshold check: highest exceeded → assign tier BPC_StressSystem (10)
4 Movement Settings E_MovementMode (enum) S_MovementSettings Map[Mode] → speed/accel/friction/stamina drain BPC_MovementStateSystem (11)
5 Footstep Profile EPhysicalSurface (enum), CurrentSpeed (float vs threshold) S_FootstepProfile (SoundSoft/SoundHard) Trace surface → lookup profile → compare velocity to threshold BPC_MovementStateSystem (11)
6 Stance Transition E_StanceTransition (enum) Float (blend time) Instant→0s, Smooth→TransitionBlendTime, Forced→0s + impulse BPC_MovementStateSystem (11)
7 Hide Detectability E_HideType (enum), Distance (float), LOS trace result Boolean (detectable) Not hidden→true; trace hits cover first→false; hits player→true BPC_HidingSystem (12)
8 Hide Spot Quality E_HideSpotQuality (enum) DetectionRangeModifier, DetectionSpeedModifier (floats 0-1) Better quality → lower detection modifiers I_HidingSpot / BP_HidingSpotBase (17)
9 Door Interaction Outcome EDoorState (enum), ELockState (enum), bHasKey (bool) E_DoorActionResult Locked→check key; Closed→open; Open→close BP_DoorActor (19)
10 Traversal Type ObstacleHeight (float) vs thresholds (Low/Medium/High) E_TraversalType ≤Low→step; ≤Medium→vault; ≤High→mantle; >High→climb BPC_ContextualTraversalSystem (21)
11 Container Fill Method E_ContainerFillMethod (enum) LootTable or FixedList or Empty Switch on FillMethod → generate appropriate loot BPC_ContainerInventory (24)
12 Weighted Loot Selection Weight (float per entry), bGuaranteed (bool) DA_ItemData + quantity Roll random vs weight sum; guaranteed items always spawn BPC_ContainerInventory (24)
13 Pickup Visual State Distance/Overlap (enum state) E_PickupState Far→Idle; Near→Highlighted; Interact→BeingPickedUp; Timer→Respawning BP_ItemPickup (25)
14 Equip Result SlotOccupied (bool), Category (tag), StateBlocked (bool) E_EquipResult Cascading validation: slot→category→state→Success BPC_EquipmentSlotSystem (30)
15 Equip Animation E_EquipAnimationType (enum) UAnimMontage Instant→none; Holster→holster; Equip→equip; Unequip→reverse equip BPC_EquipmentSlotSystem (30)
16 Inventory Sort Mode E_SortMode (enum) Reordered Array<S_InventorySlot> Switch: ByName, ByCategory, ByRarity, ByWeight, ByQuantity, ByRecent BPC_InventorySystem (31)
17 Add Item Outcome HasSpace (bool), HasStack (bool), WeightCapacity (float) E_AddItemResult Find stack→increment; else find slot→new; else→Full/Overweight BPC_InventorySystem (31)
18 Alt Death Space GameplayTag (context) TSoftObjectPtr<UWorld> Map lookup by context tag → level reference BPC_AltDeathSpaceSystem (38)
19 Death Outcome S_DeathOutcomeRules (struct), S_DeathContext (struct) E_DeathOutcome Check: max deaths→GameOver; has alt space→AltDeathSpace; else→StandardRespawn BPC_DeathHandlingSystem (39)
20 Document Font E_DocumentFontStyle (enum) UFont + color Handwritten/Typewritten/Digital/BloodScrawled → font asset + color tint WBP_JournalDocumentViewer (50)
21 Narrative Flag Query Array<GameplayTag>, bUseAndLogic (bool) Boolean AND query: all must be true; OR query: any must be true BPC_NarrativeStateSystem (58)
22 Dialogue Choice Filter RequiredFlagTag (GameplayTag) per choice Filtered Array<FDialogueChoice> If RequiredFlagTag set AND not in narrative state → hide choice BPC_DialogueChoiceSystem (61)
23 Consequence Action EConsequenceActionType (enum) System call Switch: PlayDialogue, UpdateObjective, SetWorldState, TriggerCutscene, GiveItem, etc. BPC_BranchingConsequenceSystem (62)
24 Scenario Outcome bAllObjectivesComplete (bool), bFailureConditionMet (bool) EScenarioOutcome All complete→Success; failure→Failure; else→InProgress BPC_TrialScenarioSystem (63)
25 Fire Mode E_FireMode (enum) FireRate, AmmoPerShot Single→1 shot, long delay; Burst→3 shots, medium; Auto→continuous, short BPC_FirearmSystem (74)
26 Reload Type CurrentAmmo (int) == 0 vs > 0 EReloadType Ammo=0→EmptyReload montage; else→TacticalReload montage BPC_ReloadSystem (78)
27 AI State Transition PerceptionStatus (enum), AlertLevel (float), HealthRatio (float) E_AIState HasTarget+HighAlert→Combat; LostTarget→Search; LowHealth→Flee; else→Patrol BPC_AIStateMachine (83)
28 Behaviour Variant DA_BehaviourVariant (Data Asset entries with weights) S_BehaviourVariant Weighted random selection from variant set BPC_BehaviourVariantSelector (88)
29 Difficulty Scaling PlayerMetrics (struct) vs thresholds DamageMultiplier, SpawnRate, ResourceAmount Metrics-to-difficulty mapping: Easy/Normal/Hard/Adaptive BPC_DifficultyManager (89)
30 Memory Drift StressTier (enum), RandomRoll (float) E_DriftEffectType Random selection weighted by stress tier → Visual/Audio/Dialogue BPC_MemoryDriftSystem (97)
31 Pacing Intensity Stress (float), CombatTime (float), ExploreTime (float) E_IntensityBand + Music/Spawn settings Composite score → Low/Medium/High/VeryHigh BPC_PacingDirector (98)
32 Rare Event DA_RareEvent weight table DA_RareEvent entry Weighted random selection from configured events BPC_RareEventSystem (100)

Top 5 Most Impactful Chooser Tables — Full Specs


TOP 1 — Death Outcome Chooser

Table Name: CT_DeathOutcome

Blueprint: BPC_DeathHandlingSystem

Input Columns:

Column Type Value Range Source
StandardDeathsUsed Integer 0MaxStandardDeaths BPC_RunHistoryTracker.GetDeathCount()
MaxStandardDeaths Integer 199 S_DeathOutcomeRules.MaxStandardDeaths
AltSpaceEntrancesUsed Integer 0MaxAltDeathSpaceEntrances BPC_RunHistoryTracker.GetAltSpaceEntranceCount()
MaxAltDeathSpaceEntrances Integer 099 S_DeathOutcomeRules.MaxAltDeathSpaceEntrances
bHasAltDeathSpace Boolean true/false S_DeathContext.bHasAltDeathSpace
bEnableAltDeathSpace Boolean true/false S_DeathOutcomeRules.bEnableAltDeathSpace
bIsBossDeath Boolean true/false S_DeathContext.KillerTag matches boss tag
bGameOverOnBossDeath Boolean true/false S_DeathOutcomeRules.bGameOverOnBossDeath
bIsNarrativeClimax Boolean true/false BPC_NarrativeStateSystem.HasFlag(ClimaxFlag)
bGameOverInNarrativeClimax Boolean true/false S_DeathOutcomeRules.bGameOverInNarrativeClimax

Output Column: E_DeathOutcome (StandardRespawn / GameOver / AltDeathSpace)

All Rows:

Row Conditions Outcome
1 bIsBossDeath == true AND bGameOverOnBossDeath == true GameOver
2 bIsNarrativeClimax == true AND bGameOverInNarrativeClimax == true GameOver
3 StandardDeathsUsed >= MaxStandardDeaths GameOver
4 AltSpaceEntrancesUsed >= MaxAltDeathSpaceEntrances AND !bHasAltDeathSpace GameOver
5 bEnableAltDeathSpace == true AND bHasAltDeathSpace == true AND AltSpaceEntrancesUsed < MaxAltDeathSpaceEntrances AltDeathSpace
6 (default — none of above) StandardRespawn

Reuse Notes: Rules are externalized to S_DeathOutcomeRules, configurable per level/chapter. The chooser evaluates rows in priority order (1→6). First match wins.


TOP 2 — Traversal Type Chooser

Table Name: CT_TraversalType

Blueprint: BPC_ContextualTraversalSystem

Input Columns:

Column Type Value Range Source
ObstacleHeight Float 0400 cm Line trace from player location upward
ObstacleDepth Float 0200 cm Line trace from player location forward
ClearanceAbove Float 0300 cm Ceiling check trace above obstacle
bIsGrounded Boolean true/false BPC_MovementStateSystem.bIsOnGround
CurrentSpeed Float 0SprintSpeed BPC_MovementStateSystem.CurrentSpeed

Output Column: E_TraversalType (Step / Vault / Mantle / Slide / Squeeze / Climb / Blocked)

All Rows:

Row Conditions Outcome
1 !bIsGrounded Blocked (cannot traverse in air)
2 ObstacleHeight <= 15 Step
3 ObstacleHeight <= 60 AND CurrentSpeed >= JogSpeed Vault
4 ObstacleHeight <= 150 AND ClearanceAbove >= 180 Mantle
5 ObstacleHeight <= 80 AND ClearanceAbove <= 90 AND ClearanceAbove > 40 Slide
6 ObstacleDepth >= 60 AND ClearanceAbove <= 80 AND ClearanceAbove >= 30 Squeeze
7 ObstacleHeight > 150 AND ClearanceAbove >= 200 Climb
8 (default) Blocked

Reuse Notes: Thresholds should be in a DA_TraversalConfig Data Asset for easy tuning. Root motion montages selected by traversal type from a map: Map<E_TraversalType, UAnimMontage>. Motion Warping targets set from obstacle edge location.


TOP 3 — AI State Transition Chooser

Table Name: CT_AIState

Blueprint: BPC_AIStateMachine

Input Columns:

Column Type Value Range Source
CurrentState E_AIState Patrol/Search/Combat/Flee/Idle Self
bHasTarget Boolean true/false BPC_AIPerceptionSystem.HasCurrentTarget()
bTargetVisible Boolean true/false BPC_AIPerceptionSystem.IsTargetVisible()
AlertLevel Float 0.01.0 BPC_AlertSystem.AlertLevel
HealthRatio Float 0.01.0 BPC_HealthSystem (enemy).CurrentHealth/MaxHealth
bFearActive Boolean true/false BPC_FearSystem.IsFeared()
LastKnownTargetLocation Vector world position BPC_AIMemorySystem.LastKnownLocation
DistanceToTarget Float 0MaxPerceptionRange Distance calc
TimeSinceLastSighting Float 0∞ seconds BPC_AIMemorySystem.TimeSinceLastSighting

Output Column: E_AIState (new target state)

All Rows:

Row Conditions Outcome
1 bFearActive == true AND HealthRatio <= 0.3 Flee
2 CurrentState == Combat AND HealthRatio <= 0.15 Flee
3 bHasTarget == true AND bTargetVisible == true AND AlertLevel >= 0.7 Combat
4 bHasTarget == true AND bTargetVisible == true AND AlertLevel < 0.7 AND AlertLevel >= 0.3 Search (advance to last known)
5 bHasTarget == false AND AlertLevel >= 0.5 AND TimeSinceLastSighting <= 15 Search
6 AlertLevel < 0.3 AND TimeSinceLastSighting > 30 Patrol
7 (default — same as current) CurrentState

Reuse Notes: Transition animations (alert→combat raise weapon, combat→search lower weapon) triggered by state change. BlendSpace selection per state: Patrol uses slow walk, Search uses jog, Combat uses strafing blendspace, Flee uses sprint.


TOP 4 — Dialogue Choice Filter Chooser

Table Name: CT_DialogueChoices

Blueprint: BPC_DialogueChoiceSystem

Input Columns:

Column Type Value Range Source
Choice.RequiredFlagTag GameplayTag any valid narrative tag DA_DialogueData.ChoiceDefinitions[i].RequiredFlag
Choice.BlockedFlagTag GameplayTag any valid narrative tag DA_DialogueData.ChoiceDefinitions[i].BlockedFlag
Choice.RequiredItemTag GameplayTag any valid item tag DA_DialogueData.ChoiceDefinitions[i].RequiredItem
Choice.MinStressTier E_StressTier CalmCatatonic DA_DialogueData.ChoiceDefinitions[i].MinStressTier
CurrentNarrativeFlags GameplayTagContainer accumulated flags BPC_NarrativeStateSystem.GetActiveFlags()
CurrentInventoryTags GameplayTagContainer possessed item tags BPC_InventorySystem.GetAllItemTags()
CurrentStressTier E_StressTier CalmCatatonic BPC_StressSystem.CurrentTier

Output Column: Filtered Array<S_DialogueChoice> (visible choices)

All Rows (per choice):

Row Conditions Action
1 RequiredFlagTag.IsValid() AND !CurrentNarrativeFlags.HasTag(RequiredFlagTag) HIDE choice
2 BlockedFlagTag.IsValid() AND CurrentNarrativeFlags.HasTag(BlockedFlagTag) HIDE choice
3 RequiredItemTag.IsValid() AND !CurrentInventoryTags.HasTag(RequiredItemTag) HIDE choice
4 MinStressTier > CurrentStressTier HIDE choice
5 (all conditions pass) SHOW choice

Reuse Notes: Maximum 6 visible choices at once. If more than 6 pass, prioritize by Priority field in choice definition. Hidden choices still count for narrative branching — they were "considered" but not presented.


TOP 5 — Difficulty Scaling Chooser

Table Name: CT_DifficultyScaling

Blueprint: BPC_DifficultyManager

Input Columns:

Column Type Value Range Source
PlayerDeathCount Integer 0 BPC_PlayerMetricsTracker.DeathCount
PlayerAccuracy Float 0.01.0 BPC_PlayerMetricsTracker.HitAccuracy
AverageCombatTime Float 0∞ seconds BPC_PlayerMetricsTracker.AvgCombatDuration
HealthItemUsageRate Float 0∞ per hour BPC_PlayerMetricsTracker.ConsumableUsageRate
PlaystyleArchetype E_PlaystyleArchetype Aggressive/Stealthy/Explorer/Balanced BPC_PlaystyleClassifier.CurrentArchetype
bIsBossCombat Boolean true/false BPC_AlertSystem.IsBossCombat()
CurrentDifficulty E_DifficultyLevel Easy/Normal/Hard/Nightmare Self (current state)
bAdaptiveEnabled Boolean true/false Config setting

Output Column Parameters:

Output Type Range
EnemyDamageMultiplier Float 0.53.0
EnemyHealthMultiplier Float 0.53.0
SpawnGroupSize Integer 18
ResourceScarcity Float 0.22.0 (ammo/health items)
EnemyPerceptionSpeed Float 0.52.0
EnemyReactionTime Float 0.22.0 seconds

All Rows (simplified — full table uses continuous interpolation):

Row Conditions Difficulty Band Multipliers
1 bIsBossCombat == true Fixed (no adaptive) Damage=1.2, Health=1.5, Resources=1.0
2 PlayerDeathCount >= 5 AND bAdaptiveEnabled Easier Damage=0.7, Health=0.8, Resources=1.5, Perception=0.7
3 PlayerDeathCount <= 1 AND PlayerAccuracy >= 0.7 AND bAdaptiveEnabled Harder Damage=1.5, Health=1.3, Resources=0.7, Perception=1.3
4 PlaystyleArchetype == Stealthy Stealth-tuned Perception=0.8, SpawnGroups=-2, ReactionTime=1.5
5 PlaystyleArchetype == Aggressive Combat-tuned SpawnGroups=+2, Resources=1.3, Perception=1.0
6 (default — Normal metrics) Normal All multipliers = 1.0

Reuse Notes: Continuous interpolation between rows rather than hard switches — avoids jarring difficulty changes. All thresholds and multipliers in DA_DifficultyProfile Data Asset. PlaystyleArchetype is a rolling average, not instant — prevents oscillation.


15. Gating Rules Data Asset Specification

DA_StateGatingTable

Class: UPrimaryDataAsset
Asset Path: Content/Framework/Core/DA_StateGatingTable

Variables:
  GatingRules: Array<S_StateGatingRule>
    - ActionTag: GameplayTag          // e.g., "Action.Weapon.Fire"
    - BlockedStates: Array<E_PlayerActionState>  // e.g., [Dead, Hiding, Reloading, ...]
    - BlockedGamePhases: Array<E_GamePhase>      // e.g., [MainMenu, Cutscene, Loading]
    - RequiredTags: GameplayTagContainer         // e.g., [State.CanFire, Status.Armed]
    - BlockedTags: GameplayTagContainer          // e.g., [Status.Disarmed, Status.Cuffed]
    - BlockReason: Text                          // e.g., "Cannot fire while reloading"
    - Priority: Integer                          // 0 = checked first

This Data Asset allows designers to add, remove, or modify gating rules without touching the State Manager blueprint. The blueprint reads the array and evaluates rules in priority order.


Architecture Document: BPC_StateManager. Conforms to the Modular Game Framework conventions. GASP is sacred. Ready for Code agent implementation.