# Player Character — BP_HorrorPlayerCharacter

**Game:** Project Void | **Asset:** `BP_HorrorPlayerCharacter` | **Parent:** GASP-based Character
**Asset Path:** `Content/Game/Characters/BP_HorrorPlayerCharacter.uasset`
**Build Phase:** 4 | **Demonstrates:** All 02-player systems (08-15) + 03-interaction (16) + 04-inventory (26,28,30,31,34) + 08-weapons (70,71,72) + 16-state (130)

---

## Purpose

The player's physical embodiment in the game world. A GASP-based first-person character with all framework components attached. This is the single most important game asset — nearly every framework system interacts with it.

---

## Architecture Overview

```
BP_HorrorPlayerCharacter (Character with GASP Animation Blueprint)
├── Components (auto-attached on spawn)
│   ├── CapsuleComponent (inherited)
│   ├── CameraComponent (first-person, head socket)
│   ├── CharacterMovementComponent (GASP — read-only)
│   ├── SkeletalMeshComponent (GASP — read-only)
│   │
│   ├── [02-player] BPC_HealthSystem            # 08 — Health, damage, death
│   ├── [02-player] BPC_StaminaSystem           # 09 — Sprint, action drain
│   ├── [02-player] BPC_StressSystem            # 10 — Psychological stress
│   ├── [02-player] BPC_MovementStateSystem     # 11 — Walk/Sprint/Crouch
│   ├── [02-player] BPC_HidingSystem            # 12 — Hide in lockers/beds
│   ├── [02-player] BPC_EmbodimentSystem        # 13 — First-person body
│   ├── [02-player] BPC_CameraStateLayer        # 14 — FOV/offset layers
│   ├── [02-player] BPC_PlayerMetricsTracker    # 15 — Accuracy, style
│   │
│   ├── [03-interaction] BPC_InteractionDetector # 16 — Raycast interact
│   │
│   ├── [04-inventory] BPC_InventorySystem      # 31 — Inventory grid
│   ├── [04-inventory] BPC_EquipmentSlotSystem  # 30 — Weapon/tool slots
│   ├── [04-inventory] BPC_ActiveItemSystem     # 26 — Quick-slot cycling
│   ├── [04-inventory] BPC_ConsumableSystem     # 28 — Use medkits/etc
│   ├── [04-inventory] BPC_KeyItemSystem        # 34 — Key items
│   ├── [04-inventory] BPC_JournalSystem        # 33 — Objectives
│   ├── [04-inventory] BPC_CollectibleTracker   # 27 — Collectibles found
│   ├── [04-inventory] BPC_DocumentArchiveSystem# 29 — Read documents
│   ├── [04-inventory] BPC_ItemCombineSystem    # 32 — Combine items
│   │
│   ├── [08-weapons] BPC_AmmoComponent          # 70 — Ammo pool
│   ├── [08-weapons] BPC_RecoilSystem           # 77 — Weapon recoil
│   ├── [08-weapons] BPC_HitReactionSystem      # 75 — Hit flinch
│   ├── [08-weapons] BPC_DamageReceptionSystem  # 72 — Receive damage
│   ├── [08-weapons] BPC_CombatFeedbackComponent# 71 — Hit markers
│   │
│   ├── [16-state] BPC_StateManager             # 130 — Action gating
│   │
│   ├── [07-narrative] BPC_NarrativeStateSystem # 58 — Narrative flags
│   ├── [07-narrative] BPC_ObjectiveSystem      # 59 — Active quests
│   └── [07-narrative] BPC_EndingAccumulator    # 68 — Ending tracker
│
├── Interfaces Implemented
│   ├── I_Damageable (take damage)
│   ├── I_Interactable (can be interacted with by NPCs)
│   └── I_Persistable (save/load state)
```

---

## Creation Steps

### Step 1 — Create Blueprint

```
Content Browser → Game/Characters/
  Right-click → Blueprint Class
  Parent Class: Your GASP Character (or Character if GASP is added to ABP only)
  Name: BP_HorrorPlayerCharacter
```

### Step 2 — Add All Components

In the Components panel, add each component from the list above. Order doesn't matter for Blueprint components — they auto-initialize on BeginPlay.

**Tip:** Create a Blueprint function `InitializeAllComponents` called from `Event BeginPlay` and verify every component is valid before proceeding.

### Step 3 — Configure GASP Integration

```
[GASP Animation Blueprint Setup]
   │
   ├─ Assign GASP AnimBP to SkeletalMeshComponent → Anim Class
   │    └─ Default: ABP_GASP (read-only, do not modify)
   │
   ├─ [GASP Notifies] (extend via Animation Notify overrides, NOT by editing GASP)
   │    └─ Add AnimNotify slots to GASP montages in your ABP child:
   │         ├─ Notify_Footstep → BPC_MovementStateSystem.OnFootstep()
   │         ├─ Notify_EnterAction → BPC_StateManager.EnterAction(Tag)
   │         ├─ Notify_ExitAction → BPC_StateManager.ExitAction()
   │         ├─ Notify_DamageApplied → BPC_DamageReceptionSystem.ReceiveDamage()
   │         └─ (etc — see animation-catalog.md for all 14 notifies)
   │
   └─ [Motion Matching Database]
        └─ Assign your motion matching pose search database
           (GASP handles locomotion blend — you provide the poses)
```

### Step 4 — Wire Event BeginPlay

```
Event BeginPlay
   │
   ├─ Parent: Event BeginPlay (essential for GASP init)
   │
   ├─ [Validate All Components]
   │    ├─ For each BPC_ component:
   │    │    ├─ GetComponentByClass → IsValid? → Log
   │    │    └─ If invalid: FL_GameUtilities.LogError("Missing component: X")
   │    │
   │    └─ REQUIRED components (game cannot function without):
   │         ├─ BPC_HealthSystem → if missing, ERROR + disable input
   │         ├─ BPC_InventorySystem → if missing, ERROR
   │         ├─ BPC_StateManager → if missing, ERROR
   │         └─ BPC_InteractionDetector → if missing, ERROR
   │
   ├─ [Initialize Health]
   │    ├─ BPC_HealthSystem.SetMaxHealth(100.0)
   │    └─ BPC_HealthSystem.SetCurrentHealth(100.0)
   │
   ├─ [Initialize Stamina]
   │    ├─ BPC_StaminaSystem.SetMaxStamina(100.0)
   │    └─ BPC_StaminaSystem.SetCurrentStamina(100.0)
   │
   ├─ [Initialize Stress]
   │    ├─ BPC_StressSystem.SetCurrentStress(0.0)
   │    └─ BPC_StressSystem.SetStressDecayRate(1.0)  // per second in safe areas
   │
   ├─ [Initialize Movement]
   │    ├─ BPC_MovementStateSystem.SetMovementMode(Walking)
   │    └─ BPC_MovementStateSystem.SetPosture(Standing)
   │
   ├─ [Initialize Camera]
   │    ├─ BPC_CameraStateLayer.SetDefaultFOV(90.0)
   │    └─ BPC_EmbodimentSystem.SetVisibilityMode(FirstPerson)
   │
   ├─ [Initialize Inventory]
   │    ├─ BPC_InventorySystem.Initialize(GridWidth=6, GridHeight=4, MaxWeight=50.0)
   │    └─ BPC_EquipmentSlotSystem.Initialize()
   │         └─ Create slots: PrimaryWeapon, Tool, Armor (3 equipment slots)
   │
   ├─ [Initialize State Manager]
   │    ├─ BPC_StateManager.SetupGatingRules(DA_StateGatingTable)
   │    └─ BPC_StateManager.SetInitialState(Standing)
   │
   ├─ [Bind System Interconnections]
   │    │
   │    ├─ BPC_HealthSystem.OnHealthChanged → BPC_StateManager.UpdateVitalSignals
   │    ├─ BPC_HealthSystem.OnDeath → BPC_DeathHandlingSystem.HandleDeath
   │    ├─ BPC_StressSystem.OnStressTierChanged → BPC_CameraStateLayer.SetStressBlur
   │    ├─ BPC_StressSystem.OnStressTierChanged → SS_AudioManager.SetFloatParameter("Stress", value)
   │    ├─ BPC_StaminaSystem.OnStaminaDepleted → BPC_StateManager.ForcePushState(Exhausted)
   │    ├─ BPC_MovementStateSystem.OnModeChanged → BPC_StateManager.UpdateMovementState
   │    ├─ BPC_MovementStateSystem.OnFootstep → SS_AudioManager.PlayFootstep(SurfaceTag)
   │    ├─ BPC_HidingSystem.OnHideStateChanged → BPC_StateManager.SetOverlayState
   │    ├─ BPC_HidingSystem.OnHideStateChanged → SS_EnhancedInputManager.PushContext(Hiding)
   │    └─ (etc — any cross-system event binding)
   │
   └─ [Ready]
        └─ Broadcast OnPlayerReady
             └─ Other systems wait for this before querying player state
```

### Step 5 — Wire Input Handling

```
[Event Graph — Input]

IA_Move (Axis2D) → CharacterMovementComponent.AddMovementInput
IA_Look  (Axis2D) → AddControllerYawInput + AddControllerPitchInput
   │
   ├─ [State Gating Check]
   │    └─ BPC_StateManager.IsActionPermitted(Move) ?
   │         ├─ True → process input
   │         └─ False → ignore input (blocked by state: cutscene, death, etc.)
   │
IA_Interact (Pressed) → BPC_InteractionDetector.Interact()
   └─ Also check: BPC_StateManager.IsActionPermitted(Interact)

IA_Sprint (Pressed) → BPC_StaminaSystem.StartSprint()
   └─ BPC_StateManager.IsActionPermitted(Sprint)? AND Stamina > 0?

IA_Sprint (Released) → BPC_StaminaSystem.StopSprint()

IA_Crouch (Pressed) → BPC_MovementStateSystem.ToggleCrouch()
   └─ BPC_StateManager.IsActionPermitted(Crouch)?

IA_Fire (Pressed) → BPC_ActiveItemSystem.UseEquippedItem()
   ├─ Routes to BP_Pistol_Held.UseItem() or BP_Shotgun_Held.UseItem()
   └─ BPC_StateManager.IsActionPermitted(Fire)?

IA_Fire (Released) → (cease fire for auto weapons)

IA_Aim (Pressed) → BPC_CameraStateLayer.SetLayer(Aiming)
   └─ FOV zooms to 55, slight camera offset forward

IA_Aim (Released) → BPC_CameraStateLayer.RemoveLayer(Aiming)
   └─ FOV returns to 90

IA_Reload (Pressed) → BPC_ActiveItemSystem.ReloadEquippedItem()
   └─ Routes to BP_Pistol_Held.Reload() or BP_Shotgun_Held.Reload()

IA_UseItem (Pressed) → BPC_ConsumableSystem.UseQuickSlotItem()
   └─ Uses whatever is in the quick-use slot (medkit, syringe, etc.)

IA_Flashlight (Pressed) → Toggle flashlight (if equipped in Tool slot)
   └─ Calls I_Toggleable.Toggle on BP_Flashlight_Held

IA_Jump (Pressed) → Character.Jump()
   └─ Also: BPC_ContextualTraversalSystem.TryVaultOrMantle()

IA_OpenWatch (Pressed) → SS_EnhancedInputManager.PushContext(WristwatchUI)
   ├─ SS_UIManager.ShowMenu(InventoryMenu)
   └─ Camera pans down to wristwatch

IA_PauseMenu (Pressed) → PC_HorrorController.OpenPauseMenu()

IA_QuickHeal (Pressed) → BPC_ConsumableSystem.QuickUse(MedKit)
   └─ Uses first available medkit in inventory

IA_QuickSlot1-8 → BPC_ActiveItemSystem.SetQuickSlot(SlotIndex)
```

### Step 6 — Wire Component Communication

Each BPC_ component should communicate via **Event Dispatchers**, not direct references to other components. This keeps components decoupled.

```
Core Dispatcher Bindings (in Event BeginPlay):

[Damage Pipeline]
BPC_DamageReceptionSystem.OnDamageReceived
   ├─ → BPC_HealthSystem.ApplyDamage(Damage)
   ├─ → BPC_HitReactionSystem.PlayHitReaction(DamageInfo)
   ├─ → BPC_CombatFeedbackComponent.ShowHitMarker(DamageInfo)
   ├─ → WBP_ScreenEffectController.ShowDamageVignette()
   └─ → BPC_PlayerMetricsTracker.RecordDamageTaken(Damage)

[Health to State]
BPC_HealthSystem.OnHealthChanged(NewHealth, MaxHealth)
   ├─ → BPC_StateManager.UpdateVitalSignals()
   ├─ → WBP_DiegeticHUDFrame.UpdateHealthBar()
   └─ → SS_AudioManager.SetFloatParameter("HealthPercent", ratio)

[Health to Death]
BPC_HealthSystem.OnDeath(DeathCause, Killer)
   ├─ → BPC_DeathHandlingSystem.HandleDeath()
   └─ → BPC_StateManager.ForcePushState(Death)

[Stress System]
BPC_StressSystem.OnStressTierChanged(OldTier, NewTier)
   ├─ → PS_HorrorPlayerState.SetSanityTier(NewTier * 25)  // convert tier to 0-100
   ├─ → BPC_CameraStateLayer.SetStressBlur(NewTier)
   │    ├─ Calm → no blur
   │    ├─ Uneasy → slight peripheral blur
   │    ├─ Disturbed → moderate blur + vignette
   │    ├─ Breaking → heavy blur + tunnel vision
   │    └─ Catatonic → near-black screen
   ├─ → BPC_MemoryDriftSystem.SetIntensity(NewTier)
   │    └─ Triggers visual/audio hallucinations
   ├─ → SS_AudioManager.SetFloatParameter("StressTier", NewTier)
   └─ → BPC_StateManager.UpdateVitalSignals()

[Stamina System]
BPC_StaminaSystem.OnStaminaChanged(Current, Max)
   ├─ → WBP_DiegeticHUDFrame.UpdateStaminaBar()
   └─ → (If depleted) BPC_StateManager.ForcePushState(Exhausted)
        └─ Blocks Sprint action for 3 seconds

[Hiding System]
BPC_HidingSystem.OnEnterHiding(HidingSpot)
   ├─ → BPC_StateManager.SetOverlayState(Hiding)
   ├─ → SS_EnhancedInputManager.PushContext(Hiding)
   ├─ → BPC_CameraStateLayer.SetLayer(HidePeek)
   ├─ → BPC_StressSystem.StartStressDecay()  // stress decays while hidden
   └─ → WBP_DiegeticHUDFrame.ShowBreathHoldMeter()

BPC_HidingSystem.OnExitHiding()
   ├─ → BPC_StateManager.ClearOverlayState(Hiding)
   ├─ → SS_EnhancedInputManager.PopContext(Hiding)
   ├─ → BPC_CameraStateLayer.RemoveLayer(HidePeek)
   └─ → WBP_DiegeticHUDFrame.HideBreathHoldMeter()

[Inventory Events]
BPC_InventorySystem.OnItemAdded(ItemData, SlotIndex)
   ├─ → WBP_InventoryMenu.UpdateSlot(SlotIndex)
   ├─ → BPC_CollectibleTracker.CheckItem(ItemData) → if collectible, track it
   ├─ → WBP_NotificationToast.Show("Picked up: " + DisplayName)
   └─ → (If weapon) BPC_EquipmentSlotSystem.AutoEquipIfSlotEmpty(ItemData)

BPC_InventorySystem.OnItemRemoved(ItemData, SlotIndex)
   ├─ → WBP_InventoryMenu.ClearSlot(SlotIndex)
   └─ → (If equipped) BPC_EquipmentSlotSystem.UnequipSlot()

[Equipment Events]
BPC_EquipmentSlotSystem.OnItemEquipped(SlotTag, ItemData)
   ├─ → BPC_StateManager.SetEquipmentState(SlotTag, ItemData)
   ├─ → Spawn BP_*_Held actor (pistol, shotgun, flashlight)
   │    └─ Attach to hand socket on SkeletalMeshComponent
   └─ → BPC_ActiveItemSystem.SetCurrentItem(SlotTag, HeldActor)

[State Manager Events]
BPC_StateManager.OnStateChanged(OldState, NewState)
   ├─ → BPC_MovementStateSystem.SetStateRestrictions(NewState)
   │    └─ Death → no movement; Cutscene → no movement; etc.
   ├─ → WBP_HUDController.UpdateHUDActive(newState)
   │    └─ Hide HUD during cutscene/death; show during gameplay
   └─ → SS_EnhancedInputManager.SetContextVisibility(NewState)
        └─ Disable gameplay contexts during UI/Cutscene states

BPC_StateManager.OnActionDenied(ActionTag, BlockReason)
   └─ → WBP_InteractionPromptDisplay.ShowBlocked(ActionTag, BlockReason)
        └─ "Cannot fire — you are hiding"
        └─ "Cannot interact — cutscene playing"
```

---

## Health, Stamina, Stress — The Core Survival Triad

These three systems work together to create the horror survival experience:

```
                        ┌──────────────────────┐
                        │   HEALTH (100 max)    │
                        │   ├─ Damage reduces   │
                        │   ├─ Medkit restores   │
                        │   └─ 0 HP = DEATH     │
                        └──────────┬───────────┘
                                   │ low health
                                   ▼
┌──────────────────────┐    ┌──────────────────────┐
│  STAMINA (100 max)    │    │  STRESS (0-100)      │
│  ├─ Sprint: -10/sec   │    │  ├─ Darkness: +2/sec │
│  ├─ Vault: -15/use    │    │  ├─ Enemy near: +5/s │
│  ├─ Combat: -5/action │    │  ├─ Void: +8/sec     │
│  └─ Regen: +5/sec     │    │  └─ Decay: -1/sec    │
│      (only when still)│    │      (safe areas)    │
└──────────┬───────────┘    └──────────┬───────────┘
           │ depleted                  │ high stress (75+)
           ▼                           ▼
    ┌──────────────┐          ┌──────────────────┐
    │  EXHAUSTED   │          │  HALLUCINATIONS  │
    │  ├─ Can't run│          │  ├─ False enemies │
    │  ├─ Walk slow│          │  ├─ Sounds/lights │
    │  └─ 3s cooldown│        │  └─ Screen distort│
    └──────────────┘          └──────────────────┘
```

---

## Key Variables (Class Defaults)

| Variable | Type | Default | Purpose |
|----------|------|---------|---------|
| `MaxHealth` | Float | `100.0` | Set via BPC_HealthSystem in BeginPlay |
| `MaxStamina` | Float | `100.0` | Set via BPC_StaminaSystem |
| `MaxStress` | Float | `100.0` | Set via BPC_StressSystem |
| `WalkSpeed` | Float | `300.0` | GASP default |
| `SprintSpeed` | Float | `600.0` | GASP default |
| `CrouchSpeed` | Float | `150.0` | GASP default |
| `InteractionRange` | Float | `300.0` | How far the player can interact |
| `bCanSprint` | Boolean | `true` | Disabled when exhausted or state-blocked |
| `bIsFirstPerson` | Boolean | `true` | Horror game — no third-person toggle |
| `DefaultFOV` | Float | `90.0` | Normal gameplay FOV |
| `AimFOV` | Float | `55.0` | When aiming down sights |
| `HidePeekFOV` | Float | `70.0` | When peeking from hiding |

---

## Blueprint Wiring Checklist

### Components
- [ ] Add BPC_HealthSystem (08)
- [ ] Add BPC_StaminaSystem (09)
- [ ] Add BPC_StressSystem (10)
- [ ] Add BPC_MovementStateSystem (11)
- [ ] Add BPC_HidingSystem (12)
- [ ] Add BPC_EmbodimentSystem (13)
- [ ] Add BPC_CameraStateLayer (14)
- [ ] Add BPC_PlayerMetricsTracker (15)
- [ ] Add BPC_InteractionDetector (16)
- [ ] Add BPC_InventorySystem (31)
- [ ] Add BPC_EquipmentSlotSystem (30)
- [ ] Add BPC_ActiveItemSystem (26)
- [ ] Add BPC_ConsumableSystem (28)
- [ ] Add BPC_KeyItemSystem (34)
- [ ] Add BPC_JournalSystem (33)
- [ ] Add BPC_CollectibleTracker (27)
- [ ] Add BPC_DocumentArchiveSystem (29)
- [ ] Add BPC_ItemCombineSystem (32)
- [ ] Add BPC_AmmoComponent (70)
- [ ] Add BPC_RecoilSystem (77)
- [ ] Add BPC_HitReactionSystem (75)
- [ ] Add BPC_DamageReceptionSystem (72)
- [ ] Add BPC_CombatFeedbackComponent (71)
- [ ] Add BPC_StateManager (130)
- [ ] Add BPC_NarrativeStateSystem (58)
- [ ] Add BPC_ObjectiveSystem (59)
- [ ] Add BPC_EndingAccumulator (68)

### Event BeginPlay
- [ ] Call parent BeginPlay
- [ ] Validate all critical components → log errors if missing
- [ ] Initialize Health, Stamina, Stress to max values
- [ ] Initialize Inventory (6×4 grid, 50 weight)
- [ ] Initialize Equipment Slots (PrimaryWeapon, Tool, Armor)
- [ ] Initialize State Manager with DA_StateGatingTable
- [ ] Bind all inter-component dispatchers (Health→Death, Stress→Blur, etc.)

### Input
- [ ] Bind IA_Move, IA_Look (always active unless state-blocked)
- [ ] Bind IA_Interact (state-gated)
- [ ] Bind IA_Sprint (stamina-gated + state-gated)
- [ ] Bind IA_Crouch (state-gated)
- [ ] Bind IA_Fire (state-gated + equipment-gated)
- [ ] Bind IA_Aim (equipment-gated)
- [ ] Bind IA_Reload (state-gated)
- [ ] Bind IA_UseItem (state-gated)
- [ ] Bind IA_Flashlight (state-gated)
- [ ] Bind IA_Jump (state-gated)
- [ ] Bind IA_OpenWatch (state-gated → pushes wristwatch context)
- [ ] Bind IA_PauseMenu
- [ ] Bind IA_QuickHeal
- [ ] Bind IA_QuickSlot1-8
- [ ] Every input check: BPC_StateManager.IsActionPermitted before processing

---

## Notes for Expansion

- **GASP customization:** Never edit GASP AnimBP directly. Create a child AnimBP and override/insert notifies. Add your own locomotion states (limping, crawling) as new GASP states.
- **Component order:** Add components in dependency order if they have BeginPlay initialization dependencies. Health before DeathHandling; Inventory before Equipment.
- **Multiplayer:** All health/stamina/stress mutations must be server-authoritative. Use `HasAuthority()` gates. Replicate with `RepNotify`.
- **Performance:** If FPS drops, consider lazy-initializing non-critical components (CollectibleTracker, DocumentArchive, PlayerMetricsTracker).
- **Mod support:** Keep all default values in a `DA_PlayerConfig` Data Asset (health, stamina, speed, FOV) so modders can override without touching BP.

---

*BP_HorrorPlayerCharacter — The player pawn for Project Void. See [GAMEINDEX.md](GAMEINDEX.md) for full game structure. See [INDEX.md](../blueprints/INDEX.md) for all framework component specs.*
