# State Gating Examples — Game-Specific State Rules **Game:** Project Void | **Build Phase:** 14 (Data Asset configuration) **Framework Systems:** 130_BPC_StateManager, 131_DA_StateGatingTable --- ## Purpose Defines game-specific state gating rules added to `DA_StateGatingTable` (131). These rules determine what actions are permitted in each game state. Designers can modify these without touching any Blueprint code. --- ## How State Gating Works (Quick Refresher) ``` Any system that wants to perform an action: Actor → BPC_StateManager.IsActionPermitted(ActionTag) │ ├─ StateManager checks DA_StateGatingTable for rule matching ActionTag ├─ Rule specifies which states BLOCK this action ├─ If current state matches blocked state: │ └─ Return { bPermitted = false, BlockReason = "Cannot [Action] — [Reason]" } └─ If current state doesn't match: └─ Return { bPermitted = true } Result struct: S_ActionPermissionResult ├─ bPermitted: Boolean ├─ BlockReason: FText (shown to player via InteractionPromptDisplay) └─ BlockingState: GameplayTag (for debug/logging) ``` --- ## Framework Default Rules (from DA_StateGatingTable, 37 rules) These come from the framework and apply to **all** games: | Action | Blocked By | |--------|-----------| | `Move` | Death, Cutscene, Loading, Exhausted | | `Look` | Cutscene, Loading | | `Interact` | Death, Cutscene, Loading, Hiding, Reloading | | `Fire` | Death, Cutscene, Loading, Hiding, Reloading, Exhausted, Sprinting | | `Reload` | Death, Cutscene, Loading, Hiding, Exhausted | | `Sprint` | Death, Cutscene, Loading, Crouching, Exhausted | | `Crouch` | Death, Cutscene, Loading, Sprinting | | `Jump` | Death, Cutscene, Loading, Crouching | | `Equip` | Death, Cutscene, Loading, Hiding, Reloading | | `UseItem` | Death, Cutscene, Loading, Hiding | | `Hide` | Death, Cutscene, Loading, Sprinting, Exhausted, InCombat | | `Pause` | Death, Cutscene, Loading, AltDeathSpace | | ... | (30+ more rules — see 131_DA_StateGatingTable.md) | --- ## Game-Specific Rules (Project Void) These are added on top of the framework defaults. They represent horror-game-specific restrictions. ### 1. Combat Rules | Action Tag | Blocked By | Block Reason | Notes | |-----------|-----------|-------------|-------| | `Fire` | `State.InVoidSpace` | "Your weapon has no power here." | Weapons don't work in void space | | `Fire` | `State.Catatonic` | "Your hands shake too much to aim." | Stress 100 = can't shoot | | `Reload` | `State.InVoidSpace` | "Ammunition is meaningless in the void." | Void space blocks reload | | `Melee` | `State.InVoidSpace` | "You swing at shadows." | Melee also useless in void | ### 2. Void Space Rules | Action Tag | Blocked By | Block Reason | Notes | |-----------|-----------|-------------|-------| | `Interact` | `State.VoidShiftActive` | "Reality is unstable. Nothing responds correctly." | During void shift events, interaction is unreliable (50% chance success) | | `Move` | `State.VoidParalyzed` | "The void holds you still." | Scripted moments where player is frozen | | `Pause` | `State.AltDeathSpace` | "There is no escape from the void." | No pause menu in void space | | `OpenInventory` | `State.AltDeathSpace` | "Your belongings feel distant here." | No inventory in void space | | `UseItem` | `State.AltDeathSpace` | "Items from your world have no effect." | Can't use consumables in void space | ### 3. Horror-Specific Rules | Action Tag | Blocked By | Block Reason | Notes | |-----------|-----------|-------------|-------| | `Sprint` | `State.Exhausted` | "You're too exhausted to run." | After stamina depleted for 3+ seconds | | `Sprint` | `State.Catatonic` | "Your body won't obey." | Stress 100 = no sprint | | `Interact` | `State.InCombat` | "Too dangerous! Find cover first." | Can't search drawers while enemy is attacking | | `Hide` | `State.InCombat` | "Hide quickly before they see you!" | Transition period of 2s after combat starts, then allowed | | `Hide` | `State.Catatonic` | "You can't think clearly enough to hide." | Stress 100 = can't hide | | `Flashlight` | `State.Exhausted` | "Your arm is too weak to hold the light." | Exhausted state dims flashlight to 25% instead of blocking | | `OpenWatch` | `State.Hiding` | — | **ALLOWED** (override framework block) — can check inventory while hiding | ### 4. Narrative/Dialogue Rules | Action Tag | Blocked By | Block Reason | Notes | |-----------|-----------|-------------|-------| | `All` (wildcard) | `State.InDialogueChoice` | "Make your choice." | ALL actions blocked during dialogue choice | | `Move` | `State.InDialogueChoice` | "You stand before the entity, frozen." | Can't walk away mid-choice | | `Equip` | `State.InCutscene` | — | Framework default already blocks | | `Pause` | `State.InEndingSequence` | "This moment cannot be paused." | Ending cutscene blocks pause | ### 5. Death State Rules | Action Tag | Blocked By | Block Reason | Notes | |-----------|-----------|-------------|-------| | `All` (wildcard) | `State.Dead` | "You are dead." | ALL actions blocked | | `Pause` | `State.Dead` | "Press Continue to respawn." | Pause menu blocked on death screen (death screen is the menu) | | `Look` | `State.Dead` | — | **ALLOWED** (override) — camera still follows ragdoll briefly | --- ## DA_StateGatingTable Game-Specific Configuration ### How to Add These Rules in UE5 1. Open `DA_StateGatingTable` (Content/Framework/State/) 2. **Duplicate** it → `DA_StateGatingTable_Horror` (Content/Game/DataAssets/) 3. The framework `DA_StateGatingTable` has 37 base rules. The game-specific table **inherits** them. 4. Add new entries for game-specific rules. **Rule: NEVER modify `DA_StateGatingTable` in Framework/. Use your game copy.** ### Rule Entry Structure ``` S_StateGatingRule (struct): ├─ ActionTag: GameplayTag (e.g., Framework.Action.Fire) ├─ BlockedStateTags: Array (e.g., State.InVoidSpace) ├─ BlockReason: FText (shown to player) ├─ Priority: Int32 (higher = overrides lower priority rules) └─ bOverrideFramework: Boolean (true = replaces framework rule for this action) ``` ### Example Entry: Block Fire in Void Space ``` ActionTag: Framework.Action.Fire BlockedStates: [State.InVoidSpace, State.AltDeathSpace] BlockReason: "Your weapon has no power here." Priority: 100 OverrideFramework: false (ADD to framework blocks, not REPLACE) ``` ### Example Entry: ALLOW Interact During Hiding (Override) ``` ActionTag: Framework.Action.OpenWatch BlockedStates: [] (empty = no blocks = ALWAYS permitted) BlockReason: "" Priority: 200 (HIGHER than framework default) OverrideFramework: true (REPLACE framework rule — framework blocks OpenWatch during Hiding) ``` --- ## Runtime State Management (BPC_StateManager Integration) ### Force Push States (Scripted Moments) ``` States that are force-pushed by game systems: BPC_CutsceneBridge → ForcePushState(InCutscene) └─ Blocks: All actions except SkipCutscene BPC_DeathHandlingSystem → ForcePushState(Dead) └─ Blocks: All actions BPC_VoidShiftSystem → ForcePushState(VoidShiftActive) └─ Blocks: Fire, Reload, Melee, Interact(50%) BPC_DialogueChoiceSystem → ForcePushState(InDialogueChoice) └─ Blocks: All actions except dialogue input BPC_StressSystem (at Catatonic) → ForcePushState(Catatonic) └─ Blocks: Fire, Sprint, Hide ``` ### Overlay States (Simultaneous) ``` States that layer on top of base state: BPC_HidingSystem → SetOverlayState(Hiding) └─ Blocks: Fire, Reload, Sprint, Jump └─ Allows: Look, Interact (exit hide), Crouch BPC_EquipmentSlotSystem → SetOverlayState(Aiming) └─ Blocks: Sprint, Jump └─ Allows: Fire (with ADS bonus), Reload, Crouch BPC_StaminaSystem → SetOverlayState(Exhausted) └─ Blocks: Sprint, Jump └─ Allows: Move (walk only), Interact, Fire ``` ### Vital Signals (BPC_StateManager tracks) ``` BPC_StateManager.UpdateVitalSignals() is called every 0.5s: E_PlayerVitalSignals: ├─ Normal → Health > 50 AND Stress < 50 AND Stamina > 30 ├─ Wounded → Health < 50 ├─ Stressed → Stress > 50 ├─ Exhausted → Stamina < 20 └─ Critical → Health < 25 OR Stress > 90 Systems read vital signals to modify behavior: ├─ WBP_DiegeticHUDFrame → changes health bar color per signal ├─ SS_AudioManager → modifies heartbeat audio parameter ├─ BPC_CameraStateLayer → adjusts FOV and blur per signal └─ BPC_MemoryDriftSystem → increases hallucination intensity ``` --- ## GASP Liaison (Movement ↔ State) ### Movement State → Action State Mapping ``` BPC_MovementStateSystem reports movement mode to BPC_StateManager: MovingMode.Walking → State.Walking MovingMode.Sprinting → State.Sprinting MovingMode.Crouching → State.Crouching MovingMode.Falling → State.Falling (no jump/equip actions) MovingMode.Swimming → State.Swimming (if water areas added) MovingMode.Ladder → State.Climbing (no fire/equip actions) BPC_StateManager enforces: ├─ Can't Sprint → if State.Is(Exhausted) OR State.Is(Catatonic) ├─ Can't Crouch → if State.Is(Sprinting) └─ Can't Jump → if State.Is(Crouching) OR State.Is(Exhausted) ``` --- ## Debugging State Gating ### In WBP_DebugMenu → State Viewer tab: ``` Display: ├─ Current Action State: "Walking" ├─ Current Overlay States: ["Hiding"] ├─ Vital Signal: "Wounded" ├─ Force Stack Depth: 2 │ ├─ [0] InCutscene (pushed by BPC_CutsceneBridge) │ └─ [1] Dead (pushed by BPC_DeathHandlingSystem) │ ├─ Action Test: │ ├─ [Fire] → BLOCKED: "Cannot Fire — you are in Hiding" │ ├─ [Interact] → BLOCKED: "Cannot Interact — cutscene playing" │ └─ [Look] → PERMITTED │ └─ Gating Table Source: DA_StateGatingTable_Horror (Game/DataAssets/) ``` --- ## Blueprint Wiring Checklist - [ ] Duplicate `DA_StateGatingTable` → `DA_StateGatingTable_Horror` in `Game/DataAssets/` - [ ] Add all 15+ game-specific gating rules - [ ] Configure `BP_HorrorPlayerCharacter` → BPC_StateManager → set `GatingTable = DA_StateGatingTable_Horror` - [ ] Wire all force-push states (cutscene, death, void shift, dialogue choice, catatonic) - [ ] Wire all overlay states (hiding, aiming, exhausted) - [ ] Wire GASP liaison: MovementState → BPC_StateManager movement update - [ ] Test every blocked action shows correct `BlockReason` in HUD - [ ] Verify `WBP_InteractionPromptDisplay` reads `OnActionDenied` dispatcher --- ## Notes for Expansion - New states can be added by creating a new **GameplayTag** in `DT_Tags_State.csv` - Designers can add gating rules to `DA_StateGatingTable_Horror` without touching any Blueprint - Priority system allows game rules to override framework rules cleanly - Consider adding **"semi-permitted"** actions: permitted but with penalty (e.g., flashlight dims when exhausted) - Add **per-state camera layers**: each state automatically configures FOV, offset, blur - Multiplayer: state gating is server-authoritative; client requests are validated server-side --- *State Gating Examples for Project Void. See [GAMEINDEX.md](GAMEINDEX.md) for full game structure. See [bpc-statemanager.md](../architecture/bpc-statemanager.md) for full State Manager architecture. See [130_BPC_StateManager.md](../blueprints/16-state/130_BPC_StateManager.md) for State Manager spec.*