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.
This commit is contained in:
Lefteris Notas
2026-05-21 22:27:57 +03:00
parent c515920eea
commit 040db37720
17 changed files with 6795 additions and 43 deletions

View File

@@ -0,0 +1,445 @@
# 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.*