Shotgun spread refactor (#27773)

* Moves spread data to new component

* Refactors shotgun spread code

* Makes shotgun cartridges and projectiles use new component

* Attempts to fix nullable build error

* Fixes hitscan weapons that I broke :(

* Saviour commit?

---------

Co-authored-by: EmoGarbage404 <retron404@gmail.com>
This commit is contained in:
RiceMar1244
2024-08-03 09:26:32 -04:00
committed by GitHub
parent 64273cb914
commit b432dc6125
6 changed files with 144 additions and 61 deletions

View File

@@ -128,28 +128,9 @@ public sealed partial class GunSystem : SharedGunSystem
// Cartridge shoots something else // Cartridge shoots something else
case CartridgeAmmoComponent cartridge: case CartridgeAmmoComponent cartridge:
if (!cartridge.Spent) if (!cartridge.Spent)
{
if (cartridge.Count > 1)
{
var ev = new GunGetAmmoSpreadEvent(cartridge.Spread);
RaiseLocalEvent(gunUid, ref ev);
var angles = LinearSpread(mapAngle - ev.Spread / 2,
mapAngle + ev.Spread / 2, cartridge.Count);
for (var i = 0; i < cartridge.Count; i++)
{ {
var uid = Spawn(cartridge.Prototype, fromEnt); var uid = Spawn(cartridge.Prototype, fromEnt);
ShootOrThrow(uid, angles[i].ToVec(), gunVelocity, gun, gunUid, user); CreateAndFireProjectiles(uid, cartridge);
shotProjectiles.Add(uid);
}
}
else
{
var uid = Spawn(cartridge.Prototype, fromEnt);
ShootOrThrow(uid, mapDirection, gunVelocity, gun, gunUid, user);
shotProjectiles.Add(uid);
}
RaiseLocalEvent(ent!.Value, new AmmoShotEvent() RaiseLocalEvent(ent!.Value, new AmmoShotEvent()
{ {
@@ -157,8 +138,6 @@ public sealed partial class GunSystem : SharedGunSystem
}); });
SetCartridgeSpent(ent.Value, cartridge, true); SetCartridgeSpent(ent.Value, cartridge, true);
MuzzleFlash(gunUid, cartridge, mapDirection.ToAngle(), user);
Audio.PlayPredicted(gun.SoundGunshotModified, gunUid, user);
if (cartridge.DeleteOnSpawn) if (cartridge.DeleteOnSpawn)
Del(ent.Value); Del(ent.Value);
@@ -177,10 +156,10 @@ public sealed partial class GunSystem : SharedGunSystem
break; break;
// Ammo shoots itself // Ammo shoots itself
case AmmoComponent newAmmo: case AmmoComponent newAmmo:
shotProjectiles.Add(ent!.Value); if (ent == null)
MuzzleFlash(gunUid, newAmmo, mapDirection.ToAngle(), user); break;
Audio.PlayPredicted(gun.SoundGunshotModified, gunUid, user); CreateAndFireProjectiles(ent.Value, newAmmo);
ShootOrThrow(ent.Value, mapDirection, gunVelocity, gun, gunUid, user);
break; break;
case HitscanPrototype hitscan: case HitscanPrototype hitscan:
@@ -295,6 +274,36 @@ public sealed partial class GunSystem : SharedGunSystem
{ {
FiredProjectiles = shotProjectiles, FiredProjectiles = shotProjectiles,
}); });
void CreateAndFireProjectiles(EntityUid ammoEnt, AmmoComponent ammoComp)
{
if (TryComp<ProjectileSpreadComponent>(ammoEnt, out var ammoSpreadComp))
{
var spreadEvent = new GunGetAmmoSpreadEvent(ammoSpreadComp.Spread);
RaiseLocalEvent(gunUid, ref spreadEvent);
var angles = LinearSpread(mapAngle - spreadEvent.Spread / 2,
mapAngle + spreadEvent.Spread / 2, ammoSpreadComp.Count);
ShootOrThrow(ammoEnt, angles[0].ToVec(), gunVelocity, gun, gunUid, user);
shotProjectiles.Add(ammoEnt);
for (var i = 1; i < ammoSpreadComp.Count; i++)
{
var newuid = Spawn(ammoSpreadComp.Proto, fromEnt);
ShootOrThrow(newuid, angles[i].ToVec(), gunVelocity, gun, gunUid, user);
shotProjectiles.Add(ammoEnt);
}
}
else
{
ShootOrThrow(ammoEnt, mapDirection, gunVelocity, gun, gunUid, user);
shotProjectiles.Add(ammoEnt);
}
MuzzleFlash(gunUid, ammoComp, mapDirection.ToAngle(), user);
Audio.PlayPredicted(gun.SoundGunshotModified, gunUid, user);
}
} }
private void ShootOrThrow(EntityUid uid, Vector2 mapDirection, Vector2 gunVelocity, GunComponent gun, EntityUid gunUid, EntityUid? user) private void ShootOrThrow(EntityUid uid, Vector2 mapDirection, Vector2 gunVelocity, GunComponent gun, EntityUid gunUid, EntityUid? user)

View File

@@ -0,0 +1,32 @@
using Content.Shared.Weapons.Ranged.Systems;
using Robust.Shared.GameStates;
using Robust.Shared.Prototypes;
namespace Content.Shared.Projectiles;
/// <summary>
/// Spawns a spread of the projectiles when fired
/// </summary>
[RegisterComponent, NetworkedComponent, Access(typeof(SharedGunSystem))]
public sealed partial class ProjectileSpreadComponent : Component
{
/// <summary>
/// The entity prototype that will be fired by the rest of the spread.
/// Will generally be the same entity prototype as the first projectile being fired.
/// Needed for ammo components that do not specify a fired prototype, unlike cartridges.
/// </summary>
[DataField(required: true)]
public EntProtoId Proto;
/// <summary>
/// How much the ammo spreads when shot, in degrees. Does nothing if count is 0.
/// </summary>
[DataField]
public Angle Spread = Angle.FromDegrees(5);
/// <summary>
/// How many prototypes are spawned when shot.
/// </summary>
[DataField]
public int Count = 1;
}

View File

@@ -30,18 +30,6 @@ public sealed partial class CartridgeAmmoComponent : AmmoComponent
[AutoNetworkedField] [AutoNetworkedField]
public bool Spent = false; public bool Spent = false;
/// <summary>
/// How much the ammo spreads when shot, in degrees. Does nothing if count is 0.
/// </summary>
[ViewVariables(VVAccess.ReadWrite), DataField("spread")]
public Angle Spread = Angle.FromDegrees(5);
/// <summary>
/// How many prototypes are spawned when shot.
/// </summary>
[ViewVariables(VVAccess.ReadWrite), DataField("count")]
public int Count = 1;
/// <summary> /// <summary>
/// Caseless ammunition. /// Caseless ammunition.
/// </summary> /// </summary>

View File

@@ -9,8 +9,6 @@
- Cartridge - Cartridge
- ShellShotgun - ShellShotgun
- type: CartridgeAmmo - type: CartridgeAmmo
count: 6
spread: 15
soundEject: soundEject:
collection: ShellEject collection: ShellEject
- type: Sprite - type: Sprite
@@ -32,7 +30,6 @@
map: [ "enum.AmmoVisualLayers.Base" ] map: [ "enum.AmmoVisualLayers.Base" ]
- type: CartridgeAmmo - type: CartridgeAmmo
proto: PelletShotgunBeanbag proto: PelletShotgunBeanbag
count: 1
- type: SpentAmmoVisuals - type: SpentAmmoVisuals
state: "beanbag" state: "beanbag"
@@ -47,8 +44,6 @@
map: [ "enum.AmmoVisualLayers.Base" ] map: [ "enum.AmmoVisualLayers.Base" ]
- type: CartridgeAmmo - type: CartridgeAmmo
proto: PelletShotgunSlug proto: PelletShotgunSlug
count: 1
spread: 0
- type: SpentAmmoVisuals - type: SpentAmmoVisuals
state: "slug" state: "slug"
@@ -63,7 +58,6 @@
map: [ "enum.AmmoVisualLayers.Base" ] map: [ "enum.AmmoVisualLayers.Base" ]
- type: CartridgeAmmo - type: CartridgeAmmo
proto: PelletShotgunFlare proto: PelletShotgunFlare
count: 1
- type: SpentAmmoVisuals - type: SpentAmmoVisuals
state: "flare" state: "flare"
@@ -77,7 +71,7 @@
- state: base - state: base
map: [ "enum.AmmoVisualLayers.Base" ] map: [ "enum.AmmoVisualLayers.Base" ]
- type: CartridgeAmmo - type: CartridgeAmmo
proto: PelletShotgun proto: PelletShotgunSpread
- type: entity - type: entity
id: ShellShotgunIncendiary id: ShellShotgunIncendiary
@@ -89,7 +83,7 @@
- state: incendiary - state: incendiary
map: [ "enum.AmmoVisualLayers.Base" ] map: [ "enum.AmmoVisualLayers.Base" ]
- type: CartridgeAmmo - type: CartridgeAmmo
proto: PelletShotgunIncendiary proto: PelletShotgunIncendiarySpread
- type: SpentAmmoVisuals - type: SpentAmmoVisuals
state: "incendiary" state: "incendiary"
@@ -103,7 +97,7 @@
- state: practice - state: practice
map: [ "enum.AmmoVisualLayers.Base" ] map: [ "enum.AmmoVisualLayers.Base" ]
- type: CartridgeAmmo - type: CartridgeAmmo
proto: PelletShotgunPractice proto: PelletShotgunPracticeSpread
- type: SpentAmmoVisuals - type: SpentAmmoVisuals
state: "practice" state: "practice"
@@ -118,7 +112,6 @@
map: [ "enum.AmmoVisualLayers.Base" ] map: [ "enum.AmmoVisualLayers.Base" ]
- type: CartridgeAmmo - type: CartridgeAmmo
proto: PelletShotgunTranquilizer proto: PelletShotgunTranquilizer
count: 1
- type: ChemicalAmmo - type: ChemicalAmmo
- type: SolutionContainerManager - type: SolutionContainerManager
solutions: solutions:
@@ -145,9 +138,7 @@
graph: ImprovisedShotgunShellGraph graph: ImprovisedShotgunShellGraph
node: shell node: shell
- type: CartridgeAmmo - type: CartridgeAmmo
count: 10 proto: PelletShotgunImprovisedSpread
spread: 45
proto: PelletShotgunImprovised
- type: SpentAmmoVisuals - type: SpentAmmoVisuals
state: "improvised" state: "improvised"
@@ -161,8 +152,6 @@
- state: depleted-uranium - state: depleted-uranium
map: [ "enum.AmmoVisualLayers.Base" ] map: [ "enum.AmmoVisualLayers.Base" ]
- type: CartridgeAmmo - type: CartridgeAmmo
count: 5 proto: PelletShotgunUraniumSpread
spread: 6
proto: PelletShotgunUranium
- type: SpentAmmoVisuals - type: SpentAmmoVisuals
state: "depleted-uranium" state: "depleted-uranium"

View File

@@ -42,6 +42,16 @@
types: types:
Piercing: 10 Piercing: 10
- type: entity
id: PelletShotgunSpread
noSpawn: true
parent: PelletShotgun
components:
- type: ProjectileSpread
proto: PelletShotgun
count: 6
spread: 15
- type: entity - type: entity
id: PelletShotgunIncendiary id: PelletShotgunIncendiary
name: pellet (.50 incendiary) name: pellet (.50 incendiary)
@@ -59,6 +69,16 @@
- type: IgnitionSource - type: IgnitionSource
ignited: true ignited: true
- type: entity
id: PelletShotgunIncendiarySpread
noSpawn: true
parent: PelletShotgunIncendiary
components:
- type: ProjectileSpread
proto: PelletShotgunIncendiary
count: 6
spread: 15
- type: entity - type: entity
id: PelletShotgunPractice id: PelletShotgunPractice
name: pellet (.50 practice) name: pellet (.50 practice)
@@ -73,6 +93,16 @@
types: types:
Blunt: 1 Blunt: 1
- type: entity
id: PelletShotgunPracticeSpread
noSpawn: true
parent: PelletShotgunPractice
components:
- type: ProjectileSpread
proto: PelletShotgunPractice
count: 6
spread: 15
- type: entity - type: entity
id: PelletShotgunImprovised id: PelletShotgunImprovised
name: improvised pellet name: improvised pellet
@@ -88,6 +118,15 @@
Piercing: 3 Piercing: 3
Slash: 3 Slash: 3
- type: entity
id: PelletShotgunImprovisedSpread
noSpawn: true
parent: PelletShotgunImprovised
components:
- type: ProjectileSpread
proto: PelletShotgunImprovised
count: 10
spread: 45
- type: entity - type: entity
id: PelletShotgunTranquilizer id: PelletShotgunTranquilizer
@@ -178,6 +217,16 @@
Radiation: 5 Radiation: 5
Piercing: 5 Piercing: 5
- type: entity
id: PelletShotgunUraniumSpread
noSpawn: true
parent: PelletShotgunUranium
components:
- type: ProjectileSpread
proto: PelletShotgunUranium
count: 5
spread: 6
- type: entity - type: entity
id: PelletGrapeshot #tally fucking ho id: PelletGrapeshot #tally fucking ho
name: grapeshot pellet name: grapeshot pellet
@@ -196,6 +245,16 @@
Piercing: 25 Piercing: 25
Structural: 5 Structural: 5
- type: entity
id: PelletGrapeshotSpread
noSpawn: true
parent: PelletGrapeshot
components:
- type: ProjectileSpread
proto: PelletGrapeshot
count: 5
spread: 40
- type: entity - type: entity
id: PelletGlass id: PelletGlass
name: glass shard name: glass shard
@@ -215,3 +274,13 @@
damage: damage:
types: types:
Slash: 25 Slash: 25
- type: entity
id: PelletGlassSpread
parent: PelletGlass
noSpawn: true
components:
- type: ProjectileSpread
proto: PelletGlass
count: 5
spread: 10

View File

@@ -175,9 +175,7 @@
parent: BaseCannonBall parent: BaseCannonBall
components: components:
- type: CartridgeAmmo - type: CartridgeAmmo
proto: PelletGrapeshot proto: PelletGrapeshotSpread
count: 5
spread: 40
deleteOnSpawn: true deleteOnSpawn: true
- type: Sprite - type: Sprite
sprite: Objects/Weapons/Guns/Ammunition/Explosives/explosives.rsi sprite: Objects/Weapons/Guns/Ammunition/Explosives/explosives.rsi
@@ -190,9 +188,7 @@
parent: BaseCannonBall parent: BaseCannonBall
components: components:
- type: CartridgeAmmo - type: CartridgeAmmo
proto: PelletGlass proto: PelletGlassSpread
count: 5
spread: 10
deleteOnSpawn: true deleteOnSpawn: true
- type: Sprite - type: Sprite
sprite: Objects/Weapons/Guns/Ammunition/Explosives/explosives.rsi sprite: Objects/Weapons/Guns/Ammunition/Explosives/explosives.rsi