# 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<GameplayTag> (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.*
