Weapons · Updated May 22, 2026

Shotgun

Pump-action shotgun in the style of Halo's M90. Fires a spread of 8 pellets per blast.

Pump-action shotgun in the style of Halo's M90. Fires a spread of 8 pellets per blast. Multi-pellet fire is powered by PelletCount on FSLWeaponFireMode — all existing weapons default to 1 and are unaffected.


#How Multi-Pellet Fire Works

PelletCount was added to FSLWeaponFireMode (default 1). In USLGameplayAbility_Fire::ExecuteFire:

  • Cosmetics, fire cue, and ammo decrement — fire once per trigger pull, outside the pellet loop
  • Trace loop — runs PelletCount times; each iteration calls ComputeFireDirection independently, producing a fresh random direction within BulletConeAngleDegrees
  • Listen server host — N damage traces, one impact cue execution per pellet that hits
  • Remote client — N FSLShotInfo entries queued to Server_ProcessShots; server validates each pellet independently with its sweep radius forgiveness

Single-pellet weapons (PelletCount = 1) are completely unchanged — the loop runs once with identical behaviour to before.


#Data Asset — DA_SL_Shotgun

Location: Content/SystemLink/Weapons/Shotgun/DA_SL_Shotgun

#Primary Fire Mode

FieldValueNotes
bEnabled
FireTypeHitscan
FireModeSingleShotOne blast per trigger press
PelletCount88 independent traces per blast
BulletConeAngleDegrees5.0Half-angle — ~10° total spread cone
MaxBulletConeAngleDegrees6.5Slight extra spread while moving
MaxBulletSpreadSpeed400.0Full extra spread at walking speed
RoundsPerMinute0Irrelevant for SingleShot
PostFireDelay0.8Ability stays alive 0.8s after the blast — drives pump animation via bIsFiring
MaxAmmo60No reload — pickups refill CurrentAmmo directly, clamped to this value
BaseDamage12.0Per pellet — 96 max at point blank (8×12)
MaxRange3000.0Effective range ~20m; drops off fast
MuzzleSocketNameMuzzleFlashMatch socket name on the shotgun FP mesh
AmmoDecrementEffectGE_SL_AmmoDecrementSame GE as the AR — decrements by 1 per blast
FireCueTagGameplayCues.Weapon.Shotgun.PrimaryFireMuzzle blast + shell eject
StopFireCueTag(leave empty)No looping sound to stop
ImpactCueTagGameplayCues.Weapon.Shotgun.ImpactPer-pellet impact — sparks, surface mark
RecoilPitchKick3.5Heavy upward kick per blast
RecoilYawRange0.8Slight random yaw per blast
RecoilRecoverySpeed5.0Slower recovery than AR (pump feel)
RecoilMaxAccumulation10.0

#Equip Fields

FieldValue
EquipAbilityClassBP_GA_SL_TP_Shotgun_Equip
FPEquipAbilityClassBP_GA_SL_FP_Shotgun_Equip
EquipCueTagGameplayCues.Weapon.Shotgun.Equip

#Pump Delay

PostFireDelay = 0.8 on DA_SL_Shotgun's primary fire mode keeps the fire ability alive for 0.8s after the blast. During that window SLTags.States.Weapon.Firing is on the ASC → bIsFiring is true → the anim blueprint drives the pump animation. The ability ends automatically when the timer expires.

Re-fire is blocked by Activation Blocked Tags = SLTags.States.Weapon.Firing on BP_GA_SL_Shotgun_PrimaryFire — the ability cannot re-activate while the tag is present. No cooldown GE required.


#Gameplay Tags to Register

Add these in Project Settings → GameplayTags before creating cue Blueprints:


GameplayCues.Weapon.Shotgun.PrimaryFire

GameplayCues.Weapon.Shotgun.Impact

GameplayCues.Weapon.Shotgun.Equip

SLTags.Abilities.Equip.ThirdPerson.Shotgun  ← trigger tag for TP equip ability

SLTags.Abilities.Equip.FirstPerson.Shotgun  ← trigger tag for FP equip ability

All are ini tags (Project Settings → GameplayTags). Same FirstPerson/ThirdPerson pattern as the AR.


#Assets to Create

AssetLocationSourceNotes
DA_SL_ShotgunContent/SystemLink/Weapons/Shotgun/New data asset (USLWeaponDataAsset)Fill with values above
BP_WeaponActor_ShotgunContent/SystemLink/Weapons/Shotgun/Duplicate BP_WeaponActor_AssaultRiflePoint WeaponData → DA_SL_Shotgun
BP_GA_SL_TP_Shotgun_EquipContent/SystemLink/AbilitySystem/Abilities/Weapons/Shotgun/Duplicate BP_GA_SL_TP_AssultRifle_EquipTrigger tag → SLTags.Abilities.Equip.ThirdPerson.Shotgun (full CDO setup below)
BP_GA_SL_FP_Shotgun_EquipContent/SystemLink/AbilitySystem/Abilities/Weapons/Shotgun/Duplicate BP_GA_SL_FP_AssultRifle_EquipTrigger tag → SLTags.Abilities.Equip.FirstPerson.Shotgun (full CDO setup below)
BP_GA_SL_Shotgun_PrimaryFireContent/SystemLink/AbilitySystem/Abilities/Weapons/Shotgun/Duplicate BP_GA_SL_AssualtRifle_PrimaryFireNo cooldown GE — pump delay is driven by PostFireDelay on the data asset. Set Activation Blocked Tags = SLTags.States.Weapon.Firing (full CDO setup below)
GC_SL_Shotgun_PrimaryFireContent/SystemLink/AbilitySystem/Cues/Weapons/Shotgun/Duplicate GC_SL_AssaultRifle_PrimaryFireTag → GameplayCues.Weapon.Shotgun.PrimaryFire; wide muzzle flash
GC_SL_Shotgun_ImpactContent/SystemLink/AbilitySystem/Cues/Weapons/Shotgun/Duplicate GC_SL_AssaultRifle_ImpactTag → GameplayCues.Weapon.Shotgun.Impact
GC_SL_Shotgun_EquipContent/SystemLink/AbilitySystem/Cues/Weapons/Shotgun/Duplicate GC_SL_AssaultRifle_EquipTag → GameplayCues.Weapon.Shotgun.Equip
BP_SL_WeaponPickup_ShotgunContent/SystemLink/Pickups/Weapons/Shotgun/Duplicate AR pickupPoint WeaponActorClass → BP_WeaponActor_Shotgun

#Equip Ability — Tag Setup

Both equip ability duplicates need their trigger tag updated. The TP ability is the coordinator:

BP_GA_SL_TP_Shotgun_Equip CDO:


AbilityTags            = SLTags.Abilities.Equip.ThirdPerson.Shotgun

ActivationOwnedTags    = SLTags.States.Weapon.Equipping

Triggers[0].TriggerTag = SLTags.Abilities.Equip.ThirdPerson.Shotgun

Triggers[0].Source     = GameplayEvent

BP_GA_SL_FP_Shotgun_Equip CDO:


AbilityTags            = SLTags.Abilities.Equip.FirstPerson.Shotgun

Triggers[0].TriggerTag = SLTags.Abilities.Equip.FirstPerson.Shotgun

Triggers[0].Source     = GameplayEvent

The TP equip ability fires the FP trigger via GetEquipTagFromAbilityClassSendGameplayEvent (same pattern as the AR equip ability — no changes needed to the internal logic, just the tags).


#Fire Ability — BP_GA_SL_Shotgun_PrimaryFire

Duplicate BP_GA_SL_AssualtRifle_PrimaryFire. Changes needed:

  1. AbilityTagsSLTags.Abilities.PrimaryFire (same as AR — both respond to the same fire event)
  1. Activation Owned TagsSLTags.States.Weapon.Firing
  1. Activation Blocked TagsSLTags.States.Weapon.Firing (blocks refire during the 0.8s pump delay)
  1. bIsPrimaryFire = true (inherited default, no change needed)

No cooldown GE needed — pump delay is driven by PostFireDelay = 0.8 on the data asset.

OnLocallyPredictedShotFired — implement to play the blast sound and muzzle flash locally.

OnProjectileHitPredicted — fires once per pellet that hits. For a shotgun that means up to 8 invocations per blast for the local player and up to 8 invocations for the listen-server host (the host has no predicted-impact replication path; this BP event is the only way it sees impact FX). If multiple pellets cluster on the same surface, naive impact decal spawning will pile up — dedupe by impact location, throttle decals, or clamp the per-blast count if you need a cleaner look.


#Damage Feel — Tuning Notes

  • Point blank (all 8 pellets): 8 × 12 = 96 damage — nearly kills a full-health player in one shot
  • Mid range (4 pellets hit): 4 × 12 = 48 — solid chip damage
  • Long range (1–2 pellets): 12–24 — tickle damage, rewards range management
  • Increase BaseDamage to 15 for one-shot-kill potential at close range (120 total); lower to 10 for a more forgiving feel (80 total)
  • BulletConeAngleDegrees = 5° is a tight spread — increase to 7–8° for a wider, more forgiving cone

#Build Order

  1. Register gameplay tags
  1. Create data asset DA_SL_Shotgun with values above (set PostFireDelay = 0.8)
  1. Create weapon actor BP → point to data asset
  1. Duplicate and update equip ability BPs (update tags only)
  1. Duplicate and update fire ability BP (set Activation Owned Tags + Activation Blocked Tags)
  1. Create cue Blueprints (GC_ assets) with correct tags
  1. Create pickup BP
  1. Place shotgun pickup in TestMap
  1. Test: fire blast, count impacts, verify ammo decrements by 1 per blast, verify pump delay blocks rapid fire

#Test Checklist

#Single-player / gameplay correctness

  • [ ] Fire blast → 8 separate impact cues fire on hit surfaces
  • [ ] Ammo decrements by 1 per blast (not 8)
  • [ ] Pump cooldown prevents firing again for ~0.8s
  • [ ] Recoil kicks up noticeably per blast
  • [ ] Cycle weapon swaps to/from shotgun correctly with ammo preserved
  • [ ] Pickup replaces equipped weapon when inventory full
  • [ ] Shotgun drops on death with correct ammo count

#Multiplayer correctness (run Docs/FireAbilityNetworkTesting.md)

  • [ ] Test 1 — no OnLocallyPredictedShotFired / OnWeaponFired BP events fire on the server for remote players
  • [ ] Test 2 — predicted impacts never spawn through walls (channel parity)
  • [ ] Test 3 — one Server_ProcessShots RPC per blast, not 8 (and AR full-auto unchanged)
  • [ ] Dying mid-pump cleanly tears down the fire ability (no lingering States.Weapon.Firing tag)
  • [ ] Local player hears/sees muzzle flash exactly once per blast (cue BP correctly skips locally-controlled instigator)