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

316
docs/game/weapons-index.md Normal file
View File

@@ -0,0 +1,316 @@
# Weapons Index — All Held Weapon Actors
**Game:** Project Void | **Build Phase:** 10
**Framework Systems:** 69_BP_WeaponBase, 70_BPC_AmmoComponent, 74_BPC_FirearmSystem, 76_BPC_MeleeSystem, 77_BPC_RecoilSystem, 78_BPC_ReloadSystem
---
## Purpose
Defines the 4 held weapon/tool actors used by the player. Each is spawned by `BPC_EquipmentSlotSystem` when an item is equipped and attached to the player's hand socket.
---
## Weapon Catalog
| # | Actor | Type | Damage | Fire Rate | Mag Size | Slot | Interfaces |
|---|-------|------|:---:|:---:|:---:|------|------------|
| 1 | `BP_Pistol_Held` | Firearm | 15 | 0.15s (hitscan) | 12 | PrimaryWeapon | I_UsableItem |
| 2 | `BP_Shotgun_Held` | Firearm | 45 (total) | 1.0s (pellets) | 2 | PrimaryWeapon | I_UsableItem |
| 3 | `BP_Flashlight_Held` | Tool | 0 | — | — | Tool | I_UsableItem, I_Toggleable |
| 4 | `BP_Crowbar_Held` | Melee/Tool | 20 | 0.8s (swing) | — | Tool | I_UsableItem, I_MeleeWeapon |
---
## 1. BP_Pistol_Held (Full build in [item-pistol.md](item-pistol.md))
**Quick Reference:**
```
Components:
├─ SkeletalMeshComponent (slide animation)
├─ SceneComponent "MuzzleSocket"
├─ AudioComponent "FireSound"
├─ AudioComponent "ReloadSound"
└─ ParticleSystemComponent "MuzzleFlash"
Core Loop:
IA_Fire → UseItem() → Ammo check → Hitscan → Damage → Recoil → Timer lockout
IA_Reload → Reload() → BPC_AmmoComponent.ConsumeAmmo() → update magazine
States:
├─ Idle (can fire)
├─ Firing (timer lockout)
├─ Empty (out of ammo — click sound)
└─ Reloading (animation, blocked input)
```
---
## 2. BP_Shotgun_Held
**Parent:** `BP_WeaponBase` (69)
### Components
| # | Component | Name | Purpose |
|---|-----------|------|---------|
| 1 | `SkeletalMeshComponent` | `WeaponMesh` | Break-action double barrel |
| 2 | `SceneComponent` | `MuzzleSocket` | End of barrel |
| 3 | `AudioComponent` | `FireSound` | Loud shotgun blast |
| 4 | `AudioComponent` | `ReloadSound` | Shell insertion click |
| 5 | `AudioComponent` | `BreakOpenSound` | Opening action sound |
| 6 | `AudioComponent` | `BreakCloseSound` | Closing action snap |
| 7 | `ParticleSystemComponent` | `MuzzleFlash` | Large muzzle flash |
| 8 | `PointLightComponent` | `MuzzleLight` | Brief flash on fire |
### Variables
| Variable | Type | Default | Purpose |
|----------|------|---------|---------|
| `CurrentShells` | Int | `2` | Shells currently loaded (0-2) |
| `MaxShells` | Int | `2` | Always 2 for double-barrel |
| `bIsFiring` | Bool | `false` | Fire lockout |
| `bIsReloading` | Bool | `false` | Reload lockout |
| `bIsBrokenOpen` | Bool | `false` | Break-action state |
| `WeaponData` | DA_ItemData* | — | Shotgun Data Asset |
| `PelletCount` | Int | `6` | Pellets per shot |
| `PelletSpreadAngle` | Float | `5.0` | Degrees of spread cone |
### Fire Logic (Pellet Spread)
```
UseItem() → (called by IA_Fire or IA_Fire+IA_Aim for ADS)
├─ bIsFiring? → Return False
├─ bIsReloading? → Return False
├─ bIsBrokenOpen? → Auto-close barrels → wait 0.3s
├─ CurrentShells > 0? → Branch
│ ├─ True:
│ │ ├─ Set bIsFiring = true
│ │ ├─ CurrentShells -= 1
│ │ │
│ │ ├─ [Fire Both Barrels if 2 shells loaded?]
│ │ │ └─ Designer option: single or double fire
│ │ │ └─ Default: single fire (double on alt-fire)
│ │ │
│ │ ├─ [Multi-Trace Pellet System]
│ │ │ │
│ │ │ ├─ For i = 0 to PelletCount:
│ │ │ │ ├─ Calculate spread direction:
│ │ │ │ │ ├─ BaseDir: Camera forward vector
│ │ │ │ │ └─ Apply Random Cone (PelletSpreadAngle)
│ │ │ │ │
│ │ │ │ ├─ Start: MuzzleSocket.GetWorldLocation
│ │ │ │ ├─ End: Start + SpreadDir * FireRange
│ │ │ │ │
│ │ │ │ └─ Line Trace By Channel (Visibility)
│ │ │ │ ├─ Hit? → Branch
│ │ │ │ │ ├─ True:
│ │ │ │ │ │ ├─ HitActor → I_Damageable?
│ │ │ │ │ │ │ └─ ApplyDamage(PelletDamage, ...)
│ │ │ │ │ │ └─ Spawn impact decal
│ │ │ │ │ └─ False: continue
│ │ │ │ └─ Draw debug line (editor only, color per pellet)
│ │ │ │
│ │ │ └─ Track total pellets hit for combat feedback
│ │ │
│ │ ├─ [Effects]
│ │ │ ├─ MuzzleFlash → Activate
│ │ │ ├─ FireSound → Play
│ │ │ ├─ MuzzleLight → SetVisibility(true) → Delay(0.05) → false
│ │ │ └─ Camera shake (heavy): PlayCameraShake(ShotgunKick)
│ │ │
│ │ ├─ [Recoil]
│ │ │ └─ BPC_RecoilSystem.ApplyRecoil(WeaponData, ×3 heavy multiplier)
│ │ │
│ │ ├─ [Post-Fire]
│ │ │ ├─ Delay(FireRateTimer) → Set bIsFiring = false
│ │ │ └─ IF CurrentShells == 0 → Auto-break-open for reload
│ │ │ └─ Set bIsBrokenOpen = true, play break animation
│ │ │
│ │ └─ Return True
│ │
│ └─ False: (empty)
│ ├─ Play click/empty sound
│ └─ Return False
```
### Reload Logic (Shell-by-Shell)
```
Reload()
├─ CurrentShells >= MaxShells? → Return (full)
├─ bIsReloading? → Return (already reloading)
├─ [If not broken open] → Play break-open animation → Set bIsBrokenOpen = true
├─ Set bIsReloading = true
├─ [Shell Loop — reload one shell at a time]
│ │
│ ├─ BPC_AmmoComponent.GetAmmoCount(ShellAmmoTypeTag)
│ │
│ ├─ While CurrentShells < MaxShells AND BPC_AmmoComponent.AmmoCount > 0:
│ │ ├─ BPC_AmmoComponent.ConsumeAmmo(ShellAmmoTypeTag, 1)
│ │ ├─ CurrentShells += 1
│ │ ├─ Play ReloadSound (shell click)
│ │ └─ Delay(ShellReloadDelay = 0.8s)
│ │
│ └─ [Player CAN fire mid-reload if at least 1 shell loaded]
│ └─ If IA_Fire pressed during reload:
│ ├─ Stop reload loop
│ ├─ Play break-close animation
│ ├─ Set bIsBrokenOpen = false
│ ├─ Set bIsReloading = false
│ └─ Process Fire (with whatever shells are loaded)
├─ [Reload Complete]
│ ├─ Play break-close animation
│ ├─ Set bIsBrokenOpen = false
│ ├─ Set bIsReloading = false
│ └─ Broadcast OnReloadComplete
```
### Damage Falloff
```
CalculatePelletDamage(BaseDamage, Distance):
├─ IF Distance <= 500: multiplier = 1.0 (point-blank: devastating)
├─ IF Distance <= 1500: multiplier = 0.7 (close range: lethal)
├─ IF Distance <= 2500: multiplier = 0.4 (medium: wounding)
└─ IF Distance > 2500: multiplier = 0.15 (long: minor)
└─ Return BaseDamage × multiplier / PelletCount
```
---
## 3. BP_Flashlight_Held (Full build in [item-flashlight.md](item-flashlight.md))
**Quick Reference:**
- Implements `I_UsableItem` and `I_Toggleable`
- UseItem() → toggles light on/off
- Battery consumed at 2%/second while on
- Battery restored by using `DA_Item_Battery` from consumable system
- SpotLightComponent with Cone Angle: 15° / 30°
---
## 4. BP_Crowbar_Held
**Parent:** `Actor` | **Implements:** `I_UsableItem`, `I_MeleeWeapon`
### Components
| # | Component | Name | Purpose |
|---|-----------|------|---------|
| 1 | `StaticMeshComponent` | `CrowbarMesh` | Rusted crowbar model |
| 2 | `BoxComponent` | `SwingHitbox` | Melee hit detection (disabled until swing) |
### Variables
| Variable | Type | Default | Purpose |
|----------|------|---------|---------|
| `SwingDamage` | Float | `20.0` | Damage per swing |
| `SwingCooldown` | Float | `0.8` | Seconds between swings |
| `bIsSwinging` | Bool | `false` | Swing lockout |
| `SwingRange` | Float | `250.0` | Units of reach |
| `SwingArc` | Float | `90.0` | Degrees of arc |
### Melee Logic
```
UseItem() → BPC_MeleeSystem.Swing(Self)
├─ bIsSwinging? → Return False
├─ Set bIsSwinging = true
├─ [Swing Animation]
│ └─ Timeline (0.0 → 1.0 over 0.3s) → Update crowbar rotation
├─ [Swing Hitbox — enable at 0.15s (mid-swing)]
│ ├─ Delay(0.15) → SwingHitbox.SetCollisionEnabled(QueryOnly)
│ ├─ OnComponentBeginOverlap(SwingHitbox, OtherActor):
│ │ ├─ OtherActor → DoesImplementInterface(I_Damageable)?
│ │ │ ├─ True:
│ │ │ │ ├─ ApplyDamage(SwingDamage, Self, Melee, HitLocation, HitDirection)
│ │ │ │ ├─ Play hit sound (metal thud)
│ │ │ │ └─ BPC_CombatFeedbackComponent.ShowHitMarker()
│ │ │ └─ False: Play wall/object hit sound
│ │ └─ (Hit each actor only once per swing — use a hit-set)
│ │
│ └─ Delay(0.15) → SwingHitbox.SetCollisionEnabled(NoCollision)
├─ [Swing Complete]
│ ├─ Delay(SwingCooldown) → Set bIsSwinging = false
│ └─ Return True
```
### Pry Function
```
CanPryOpen(DoorActor: BP_DoorActor*) → Boolean
└─ Return (DoorActor.IsBarricaded())
PryDoor(DoorActor: BP_DoorActor*)
├─ DoorActor.Open() (forces open, breaks barricade)
├─ Play wood/metal break sound
├─ DoorActor.SetLocked(false) permanently
└─ SS_AudioManager.PlaySFX("crowbar_pry")
```
---
## Weapon Animation Notifies (GASP Integration)
All held weapons fire animation notifies that the GASP AnimBP listens to:
| Notify | Weapon | Purpose |
|--------|--------|---------|
| `Notify_Fire` | Pistol, Shotgun | Triggers fire animation blend |
| `Notify_ReloadStart` | Pistol, Shotgun | Enters reload animation state |
| `Notify_ReloadEnd` | Pistol, Shotgun | Exits reload animation state |
| `Notify_MeleeSwing` | Crowbar | Triggers melee swing blend |
| `Notify_Equip` | All | Weapon equip animation |
| `Notify_Unequip` | All | Weapon holster animation |
| `Notify_AimDownSights` | Pistol, Shotgun | ADS pose transition |
| `Notify_HipFire` | Pistol, Shotgun | Hip fire pose transition |
These are added to montage slots in the **GASP child AnimBP**, NOT in the weapon BP itself.
---
## Quick Comparison
| Feature | Pistol | Shotgun | Flashlight | Crowbar |
|---------|--------|---------|-----------|---------|
| **Role** | Ranged DPS | Burst damage | Vision | Utility + Melee |
| **Best Range** | Medium-Long | Close | Infinite (light) | Melee |
| **Ammo Management** | Magazine | Shell-by-shell | Battery (%) | None |
| **Reload Strategy** | Dump + reload | Tactical (can interrupt) | Replace battery | N/A |
| **Recoil** | Light | Heavy | None | None |
| **ADS Benefit** | Higher accuracy | Tighter spread | N/A | N/A |
| **Stress Impact** | None | +5 (loud) | -1/sec (safe light) | None |
| **Silent?** | No | No | Yes | No (swing noise) |
| **Attracts Enemies?** | Yes (2000u radius) | Yes (3000u radius) | Yes (800u radius) | Yes (1200u radius) |
---
## Notes for Expansion
- Add **weapon degradation**: pistol jams after 100 shots without cleaning
- Add **flashlight flicker**: battery below 10% causes random light flicker (horror mechanic)
- Add **shotgun slug ammo**: alternate ammo type — single slug instead of pellets, longer range
- Add **crowbar upgrade**: wrap with cloth → silent melee swings (no enemy alert)
- Add **aim-assist** for controller players (configurable in accessibility)
- Add **weapon inspection animation**: hold reload key to inspect weapon (cosmetic)
- Multiplayer: all fire/reload must be server-authoritative with client prediction for effects
---
*Weapons Index for Project Void. See [GAMEINDEX.md](GAMEINDEX.md) for full game structure. See [item-pistol.md](item-pistol.md) and [item-flashlight.md](item-flashlight.md) for detailed build walkthroughs.*