Files
UE5-Modular-Game-Framework/docs/game/state-gating-examples.md
Lefteris Notas 040db37720 Add UI Overrides and Weapons Index documentation for Project Void
- Created ui-overrides.md detailing game-specific Widget Blueprint overrides, including purpose, widget index, visual styling, and accessibility requirements.
- Established weapons-index.md outlining all held weapon actors, including their components, logic, and comparisons for gameplay mechanics.
2026-05-21 22:27:57 +03:00

288 lines
11 KiB
Markdown

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