# Game Core — PC_HorrorController, PS_HorrorPlayerState, GS_HorrorGameState **Game:** Project Void | **Build Phase:** 1 --- This document covers the 3 remaining Core class children: | Asset | Parent | Purpose | |-------|--------|---------| | `PC_HorrorController` | `PC_CoreController` (or `PlayerController`) | Horror-specific input routing, camera, UI injection | | `PS_HorrorPlayerState` | `PS_CorePlayerState` (or `PlayerState`) | Horror player data: fear history, deaths, sanity | | `GS_HorrorGameState` | `GS_CoreGameState` (or `GameStateBase`) | Shared session data: global flags, void state, timer | --- ## PC_HorrorController — Player Controller **Asset Path:** `Content/Game/Core/PC_HorrorController.uasset` ### Purpose Routes player input through `SS_EnhancedInputManager`, manages camera shake, hit feedback, and UI injection for horror-specific screen effects. ### Creation Steps #### Step 1 — Create Blueprint ``` Content Browser → Game/Core/ Right-click → Blueprint Class Parent Class: PlayerController (or PC_CoreController if it exists in framework) Name: PC_HorrorController ``` #### Step 2 — Variables | Variable | Type | Default | Category | Purpose | |----------|------|---------|----------|---------| | `bGameInputEnabled` | Boolean | `true` | `Input` | Master input toggle (off during cutscenes/death) | | `CameraShakeIntensity` | Float | `1.0` | `Camera` | Global scalar for camera shake effects | | `bHeartbeatEnabled` | Boolean | `true` | `UI` | Toggle diegetic heartbeat indicator | #### Step 3 — Wire Event BeginPlay ``` Event BeginPlay │ ├─ Set Input Mode Game Only (mouse captured, no cursor) ├─ Set Show Mouse Cursor → false │ ├─ [Get Enhanced Input Subsystem] │ └─ Get Engine Subsystem → UEnhancedInputLocalPlayerSubsystem │ ├─ [Bind to Game Phase Changes] │ ├─ Get GI_HorrorGame → Bind to OnGamePhaseChanged │ │ └─ On Paused/Cutscene/DeathLoop → Set bGameInputEnabled = false │ │ └─ On InGame → Set bGameInputEnabled = true │ │ │ └─ SS_UIManager → Bind to OnInputModeChanged │ └─ Update input mode + cursor visibility │ └─ [Start Heartbeat Effect] └─ (Timer: every 0.5s) Get BPC_StateManager → GetHeartRate() ├─ Normal (60-80) → slight controller pulse ├─ Elevated (80-110) → stronger pulse └─ Critical (110+) → rapid, intense pulse + screen edge red ``` #### Step 4 — Override: Setup Input Component ``` Setup Input Component │ ├─ Parent: Setup Input Component │ └─ (Input actions are mapped via SS_EnhancedInputManager and IMC_ contexts — no manual binding needed here. The subsystem handles context pushes.) ``` #### Step 5 — Functions | Function | Inputs | Outputs | Description | |----------|--------|---------|-------------| | `PlayCameraShake` | ShakeClass, Scale: Float | — | `ClientStartCameraShake(ShakeClass, Scale × CameraShakeIntensity)` | | `SetGameInputEnabled` | bEnabled: Boolean | — | Master toggle — disables all input processing | | `OpenPauseMenu` | — | — | `SS_UIManager.PushMenu(PauseMenu)` — bound to IA_PauseMenu | | `GetInteractionSystem` | — | `BPC_InteractionDetector*` | Quick access to interaction component on pawn | ### Communications With | Target | Method | Why | |--------|--------|-----| | `SS_EnhancedInputManager` | Direct | Context management, input state queries | | `SS_UIManager` | Direct + Dispatcher | Input mode coordination | | `GI_HorrorGame` | Dispatcher | Phase change response | | `BPC_StateManager` | Direct (on pawn) | Heart rate for haptic feedback | | `BP_HorrorPlayerCharacter` | Owned Pawn | Camera shake routing | --- ## PS_HorrorPlayerState — Player State **Asset Path:** `Content/Game/Core/PS_HorrorPlayerState.uasset` ### Purpose Tracks player-specific data that persists across level transitions and death/respawn. Custom data: fear history, death count per chapter, sanity tier. ### Creation Steps #### Step 1 — Create Blueprint ``` Content Browser → Game/Core/ Right-click → Blueprint Class Parent Class: PlayerState (or PS_CorePlayerState if it exists in framework) Name: PS_HorrorPlayerState ``` #### Step 2 — Variables | Variable | Type | Default | Category | Purpose | |----------|------|---------|----------|---------| | `SanityTier` | Integer | `100` | `Player` | 100=Calm, 75=Uneasy, 50=Disturbed, 25=Breaking, 0=Catatonic | | `FearHistory` | Array\ | Empty | `Player` | Tracks fear triggers experienced (for ending calculation) | | `DeathsThisChapter` | Integer | `0` | `Player` | Resets per chapter; used for difficulty scaling | | `TotalCollectiblesFound` | Integer | `0` | `Player` | Across all levels | | `PlaystyleTag` | GameplayTag | `Framework.Playstyle.Balanced` | `Player` | Aggressive / Stealthy / Explorer / Balanced | | `PlayerName` | Text | "Dr. Eliza Vance" | `Player` | Display name (set by GM on spawn) | #### Step 3 — Functions | Function | Inputs | Outputs | Description | |----------|--------|---------|-------------| | `RecordFearTrigger` | TriggerTag: GameplayTag | — | Adds tag to FearHistory, notifies BPC_EndingAccumulator | | `SetSanityTier` | NewTier: Int | — | Updates sanity; clamps 0–100; fires OnSanityChanged dispatcher | | `IncrementDeaths` | — | — | DeathsThisChapter++, fires OnDeathCountChanged | | `GetPlaystyle` | — | GameplayTag | Returns PlaystyleTag | | `GetSanityPercentage` | — | Float | Returns SanityTier as 0.0–1.0 float | ### Replication Notes (Multiplayer) All variables should be marked `Replicated` with `ReplicatedUsing = OnRep_`. --- ## GS_HorrorGameState — Game State **Asset Path:** `Content/Game/Core/GS_HorrorGameState.uasset` ### Purpose Shared session state visible to all players (server + all clients in multiplayer). In single-player, serves as the authoritative session data store. ### Creation Steps #### Step 1 — Create Blueprint ``` Content Browser → Game/Core/ Right-click → Blueprint Class Parent Class: GameStateBase (or GS_CoreGameState if it exists in framework) Name: GS_HorrorGameState ``` #### Step 2 — Variables | Variable | Type | Default | Category | Purpose | |----------|------|---------|----------|---------| | `ActiveChapterTag` | GameplayTag | — | `Session` | Current chapter/level identifier | | `bIsVoidActive` | Boolean | `false` | `Session` | True when any player is in void space | | `GlobalFearLevel` | Float | `0.0` | `Session` | 0.0–1.0 — ambient fear level affecting all systems | | `SessionPlaytime` | Float | `0.0` | `Session` | Accumulated playtime in seconds | | `bEndingSequenceActive` | Boolean | `false` | `Session` | True during ending cutscene (blocks all gameplay) | | `GlobalFlags` | Map\ | Empty | `Session` | Chapter-complete flags, puzzle-solved flags, etc. | #### Step 3 — Event Graph ``` Event BeginPlay │ ├─ Set GlobalFearLevel = 0.0 │ └─ [Start Playtime Timer] └─ Set Timer (1.0s, Looping) → SessionPlaytime += 1.0 └─ Only increment when GamePhase == InGame Event Tick (or Timer) │ ├─ Get GI_HorrorGame → CurrentGamePhase │ └─ If InGame: SessionPlaytime += DeltaTime │ └─ Else: don't accumulate │ └─ [Fear Decay] ├─ GlobalFearLevel > 0.0? │ └─ True: GlobalFearLevel -= 0.001 per second (slow decay) │ └─ Clamp to 0.0 minimum └─ Broadcast OnGlobalFearChanged(GlobalFearLevel) ``` #### Step 4 — Functions | Function | Inputs | Outputs | Description | |----------|--------|---------|-------------| | `SetGlobalFlag` | FlagTag: GameplayTag, Value: Boolean | — | Sets session flag + broadcasts OnFlagChanged | | `GetGlobalFlag` | FlagTag: GameplayTag | Boolean | Returns flag value (false if not found) | | `AddFearLevel` | Amount: Float | — | GlobalFearLevel += Amount, clamped 0.0–1.0 | | `SetVoidActive` | bActive: Boolean | — | Sets bIsVoidActive, broadcasts OnVoidStateChanged | | `GetSessionTimeFormatted` | — | Text | Returns "HH:MM:SS" formatted playtime | | `ResetSession` | — | — | Resets all variables (called by New Game) | #### Step 5 — Event Dispatchers | Dispatcher | Parameters | Fired When | |------------|-----------|------------| | `OnFlagChanged` | FlagTag: GameplayTag, Value: Boolean | Any global flag changes | | `OnGlobalFearChanged` | FearLevel: Float | GlobalFearLevel updates | | `OnVoidStateChanged` | bIsVoidActive: Boolean | Void space active/inactive | | `OnChapterChanged` | ChapterTag: GameplayTag | Active chapter changes | | `OnSessionReset` | — | Session data wiped (New Game) | --- ## Combined Wiring — All Core Classes Together ``` [GI_HorrorGame.Init] │ ├─ Initialize subsystems (Audio, Settings, Input) └─ OpenLevel → L_SplashScreen │ └─ L_SplashScreen → auto-advance → L_MainMenu │ └─ [Player clicks New Game] │ └─ GM_HorrorGameMode starts new session │ ├─ Spawn PS_HorrorPlayerState (fresh data) ├─ Spawn GS_HorrorGameState (fresh session) │ ├─ Spawn BP_HorrorPlayerCharacter (pawn) │ └─ Auto-added components: │ ├─ BPC_HealthSystem (100 HP) │ ├─ BPC_StaminaSystem (100 stam) │ ├─ BPC_StressSystem (0 stress) │ ├─ BPC_MovementStateSystem │ ├─ BPC_HidingSystem │ ├─ BPC_EmbodimentSystem │ ├─ BPC_CameraStateLayer │ ├─ BPC_PlayerMetricsTracker │ ├─ BPC_InteractionDetector │ ├─ BPC_InventorySystem │ ├─ BPC_EquipmentSlotSystem │ ├─ BPC_ActiveItemSystem │ ├─ BPC_ConsumableSystem │ ├─ BPC_StateManager │ └─ [others as needed] │ ├─ Spawn PC_HorrorController │ ├─ Bind input contexts │ └─ Set Input Mode Game Only │ └─ Create WBP_GameHUDController ├─ WBP_DiegeticHUDFrame (health, stress, stamina) ├─ WBP_InteractionPromptDisplay ├─ WBP_ObjectiveDisplay ├─ WBP_NotificationToast ├─ WBP_ScreenEffectController └─ WBP_AccessibilityUI (subtitles) ``` --- ## Blueprint Wiring Checklist ### PC_HorrorController - [ ] Create BP child of PlayerController named `PC_HorrorController` - [ ] Add 3 variables (bGameInputEnabled, CameraShakeIntensity, bHeartbeatEnabled) - [ ] Wire `Event BeginPlay` — input mode, phase bindings, heartbeat timer - [ ] Add `PlayCameraShake`, `SetGameInputEnabled`, `OpenPauseMenu`, `GetInteractionSystem` ### PS_HorrorPlayerState - [ ] Create BP child of PlayerState named `PS_HorrorPlayerState` - [ ] Add 5 variables (SanityTier, FearHistory, DeathsThisChapter, TotalCollectiblesFound, PlaystyleTag) - [ ] Add `RecordFearTrigger`, `SetSanityTier`, `IncrementDeaths`, `GetPlaystyle`, `GetSanityPercentage` - [ ] Mark variables Replicated for multiplayer ### GS_HorrorGameState - [ ] Create BP child of GameStateBase named `GS_HorrorGameState` - [ ] Add 6 variables (ActiveChapterTag, bIsVoidActive, GlobalFearLevel, SessionPlaytime, bEndingSequenceActive, GlobalFlags) - [ ] Add 4 event dispatchers (OnFlagChanged, OnGlobalFearChanged, OnVoidStateChanged, OnChapterChanged, OnSessionReset) - [ ] Wire `Event BeginPlay` — fear decay timer - [ ] Add `SetGlobalFlag`, `GetGlobalFlag`, `AddFearLevel`, `SetVoidActive`, `GetSessionTimeFormatted`, `ResetSession` --- ## Notes for Expansion - The `PS_HorrorPlayerState.SanityTier` maps directly to `BPC_StressSystem` — they should sync via dispatcher - `GS_HorrorGameState.GlobalFearLevel` could drive `BPC_PacingDirector` to spawn more/less enemies - In a multiplayer game, `GS_HorrorGameState` is the server-authoritative source for all session data - Consider adding `PS_HorrorPlayerState.FearHistory` as a debug visualization in `WBP_DebugMenu` - The heartbeat haptic effect in `PC_HorrorController` requires gamepad support — add a fallback for KB+M --- *Core controller + state classes for Project Void. See [GAMEINDEX.md](GAMEINDEX.md) for full game structure. See [05_GM_CoreGameMode.md](../blueprints/01-core/05_GM_CoreGameMode.md) and [06_GS_CoreGameState.md](../blueprints/01-core/06_GS_CoreGameState.md) for parent specs.*