- 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.
317 lines
12 KiB
Markdown
317 lines
12 KiB
Markdown
# 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.*
|