]> git.smokeofanarchy.ru Git - space-station-14.git/commitdiff
pneumatic cannon fixes (#14705)
authordeltanedas <39013340+deltanedas@users.noreply.github.com>
Sat, 25 Mar 2023 23:15:46 +0000 (23:15 +0000)
committerGitHub <noreply@github.com>
Sat, 25 Mar 2023 23:15:46 +0000 (16:15 -0700)
Co-authored-by: deltanedas <@deltanedas:kde.org>
Content.Client/Weapons/Ranged/Systems/GunSystem.cs
Content.Server/PneumaticCannon/PneumaticCannonSystem.cs
Content.Server/Weapons/Ranged/Systems/GunSystem.cs
Content.Shared/PneumaticCannon/PneumaticCannonComponent.cs
Content.Shared/PneumaticCannon/SharedPneumaticCannonSystem.cs
Content.Shared/Weapons/Ranged/Systems/SharedGunSystem.cs
Resources/Prototypes/Entities/Objects/Weapons/Guns/pneumatic_cannon.yml

index f41c50fc90f9e4981462631c5b4215a2814d8caa..0a7d62970fb68fa6148430c18b10f1e56accd447 100644 (file)
@@ -169,7 +169,8 @@ public sealed partial class GunSystem : SharedGunSystem
         });
     }
 
-    public override void Shoot(EntityUid gunUid, GunComponent gun, List<(EntityUid? Entity, IShootable Shootable)> ammo, EntityCoordinates fromCoordinates, EntityCoordinates toCoordinates, EntityUid? user = null)
+    public override void Shoot(EntityUid gunUid, GunComponent gun, List<(EntityUid? Entity, IShootable Shootable)> ammo,
+        EntityCoordinates fromCoordinates, EntityCoordinates toCoordinates, EntityUid? user = null, bool throwItems = false)
     {
         // Rather than splitting client / server for every ammo provider it's easier
         // to just delete the spawned entities. This is for programmer sanity despite the wasted perf.
@@ -178,6 +179,16 @@ public sealed partial class GunSystem : SharedGunSystem
 
         foreach (var (ent, shootable) in ammo)
         {
+            if (throwItems)
+            {
+                Recoil(user, direction);
+                if (ent!.Value.IsClientSide())
+                    Del(ent.Value);
+                else
+                    RemComp<AmmoComponent>(ent.Value);
+                continue;
+            }
+
             switch (shootable)
             {
                 case CartridgeAmmoComponent cartridge:
index b7c3ad609bcc2daf0747a9dbe13d88074246d2b2..cbfc263018495f92fd05cd126fd8c839d311ec1e 100644 (file)
@@ -63,7 +63,8 @@ public sealed class PneumaticCannonSystem : SharedPneumaticCannonSystem
         if (!TryComp<GasTankComponent>(args.EntityUid, out var gas))
             return;
 
-        if (gas.Air.TotalMoles >= component.GasUsage)
+        // only accept tanks if it uses gas
+        if (gas.Air.TotalMoles >= component.GasUsage && component.GasUsage > 0f)
             return;
 
         args.Cancel();
@@ -71,7 +72,9 @@ public sealed class PneumaticCannonSystem : SharedPneumaticCannonSystem
 
     private void OnShoot(EntityUid uid, PneumaticCannonComponent component, ref GunShotEvent args)
     {
-        if (GetGas(uid) is not { } gas)
+        // require a gas tank if it uses gas
+        var gas = GetGas(uid);
+        if (gas == null && component.GasUsage > 0f)
             return;
 
         if(TryComp<StatusEffectsComponent>(args.User, out var status)
@@ -82,6 +85,10 @@ public sealed class PneumaticCannonSystem : SharedPneumaticCannonSystem
                 ("cannon", component.Owner)), uid, args.User);
         }
 
+        // ignore gas stuff if the cannon doesn't use any
+        if (gas == null)
+            return;
+
         // this should always be possible, as we'll eject the gas tank when it no longer is
         var environment = _atmos.GetContainingMixture(component.Owner, false, true);
         var removed = _gasTank.RemoveAir(gas, component.GasUsage);
index cb67880a00a53d408264a4ebfe61f6353392b445..6b1a154a830f59c824f5a2cb58605a79957b9ccb 100644 (file)
@@ -62,7 +62,8 @@ public sealed partial class GunSystem : SharedGunSystem
         args.Price += price * component.UnspawnedCount;
     }
 
-    public override void Shoot(EntityUid gunUid, GunComponent gun, List<(EntityUid? Entity, IShootable Shootable)> ammo, EntityCoordinates fromCoordinates, EntityCoordinates toCoordinates, EntityUid? user = null)
+    public override void Shoot(EntityUid gunUid, GunComponent gun, List<(EntityUid? Entity, IShootable Shootable)> ammo,
+        EntityCoordinates fromCoordinates, EntityCoordinates toCoordinates, EntityUid? user = null, bool throwItems = false)
     {
         // Try a clumsy roll
         // TODO: Who put this here
@@ -110,6 +111,21 @@ public sealed partial class GunSystem : SharedGunSystem
 
         foreach (var (ent, shootable) in ammo)
         {
+            // pneumatic cannon doesn't shoot bullets it just throws them, ignore ammo handling
+            if (throwItems)
+            {
+                if (!HasComp<ProjectileComponent>(ent!.Value))
+                {
+                    RemComp<AmmoComponent>(ent.Value);
+                    // TODO: Someone can probably yeet this a billion miles so need to pre-validate input somewhere up the call stack.
+                    ThrowingSystem.TryThrow(ent.Value, mapDirection, gun.ProjectileSpeed, user);
+                    continue;
+                }
+
+                ShootProjectile(ent.Value, mapDirection, gunVelocity, user, gun.ProjectileSpeed);
+                continue;
+            }
+
             switch (shootable)
             {
                 // Cartridge shoots something else
index 11407f1d3fb79f53b323307a7cc674e720ceb362..45f6c077eb924201a15d150fb0fd69434d6201df 100644 (file)
@@ -37,6 +37,12 @@ public sealed class PneumaticCannonComponent : Component
     /// </summary>
     [DataField("baseProjectileSpeed")]
     public float BaseProjectileSpeed = 20f;
+
+    /// <summary>
+    /// If true, will throw ammo rather than shoot it.
+    /// </summary>
+    [DataField("throwItems"), ViewVariables(VVAccess.ReadWrite)]
+    public bool ThrowItems = true;
 }
 
 /// <summary>
index 7071676b2c5f56ed490aeed631784d15da278991..27384f8d55150e19eacc61f02ac627363e65fb08 100644 (file)
@@ -20,6 +20,13 @@ public abstract class SharedPneumaticCannonSystem : EntitySystem
 
     private void OnAttemptShoot(EntityUid uid, PneumaticCannonComponent component, ref AttemptShootEvent args)
     {
+        // if the cannon doesn't need gas then it will always predict firing
+        if (component.GasUsage == 0f)
+            return;
+
+        // pneumatic cannon usually doesn't shoot bullets
+        args.ThrowItems = component.ThrowItems;
+
         // we don't have atmos on shared, so just predict by the existence of a slot item
         // server will handle auto ejecting/not adding the slot item if it doesnt have enough gas,
         // so this won't mispredict
index 84f5922d69cd0619d336b1563558bf40c00cb515..4a0a5ec69a7d9b0525c72e7973659e0ab065cd37 100644 (file)
@@ -238,7 +238,6 @@ public abstract partial class SharedGunSystem : EntitySystem
             return;
         }
 
-
         var curTime = Timing.CurTime;
 
         // Need to do this to play the clicking sound for empty automatic weapons
@@ -313,7 +312,7 @@ public abstract partial class SharedGunSystem : EntitySystem
         }
 
         // Shoot confirmed - sounds also played here in case it's invalid (e.g. cartridge already spent).
-        Shoot(gunUid, gun, ev.Ammo, fromCoordinates, toCoordinates.Value, user);
+        Shoot(gunUid, gun, ev.Ammo, fromCoordinates, toCoordinates.Value, user, throwItems: attemptEv.ThrowItems);
         var shotEv = new GunShotEvent(user);
         RaiseLocalEvent(gunUid, ref shotEv);
         // Projectiles cause impulses especially important in non gravity environments
@@ -331,10 +330,11 @@ public abstract partial class SharedGunSystem : EntitySystem
         EntityUid ammo,
         EntityCoordinates fromCoordinates,
         EntityCoordinates toCoordinates,
-        EntityUid? user = null)
+        EntityUid? user = null,
+        bool throwItems = false)
     {
         var shootable = EnsureComp<AmmoComponent>(ammo);
-        Shoot(gunUid, gun, new List<(EntityUid? Entity, IShootable Shootable)>(1) { (ammo, shootable) }, fromCoordinates, toCoordinates, user);
+        Shoot(gunUid, gun, new List<(EntityUid? Entity, IShootable Shootable)>(1) { (ammo, shootable) }, fromCoordinates, toCoordinates, user, throwItems);
     }
 
     public abstract void Shoot(
@@ -343,7 +343,8 @@ public abstract partial class SharedGunSystem : EntitySystem
         List<(EntityUid? Entity, IShootable Shootable)> ammo,
         EntityCoordinates fromCoordinates,
         EntityCoordinates toCoordinates,
-        EntityUid? user = null);
+        EntityUid? user = null,
+        bool throwItems = false);
 
     protected abstract void Popup(string message, EntityUid? uid, EntityUid? user);
 
@@ -438,8 +439,9 @@ public abstract partial class SharedGunSystem : EntitySystem
 /// </remarks>
 /// <param name="User">The user that attempted to fire this gun.</param>
 /// <param name="Cancelled">Set this to true if the shot should be cancelled.</param>
+/// <param name="ThrowItems">Set this to true if the ammo shouldn't actually be fired, just thrown.</param>
 [ByRefEvent]
-public record struct AttemptShootEvent(EntityUid User, bool Cancelled=false);
+public record struct AttemptShootEvent(EntityUid User, bool Cancelled = false, bool ThrowItems = false);
 
 /// <summary>
 ///     Raised directed on the gun after firing.
index 01a6ff8db75b728e2f89eed0d9dfe9c8c7192083..d689776d3247923b10707e6ce132c6ba8465c685 100644 (file)
     containers:
       storagebase: !type:Container
         ents: []
+
+# shoots bullets instead of throwing them, no other changes
+- type: entity
+  parent: WeaponImprovisedPneumaticCannon
+  id: WeaponImprovisedPneumaticCannonGun
+  suffix: Gun
+  components:
+  - type: PneumaticCannon
+    throwItems: false
+
+# doesn't need gas, extra capacity
+- type: entity
+  parent: WeaponImprovisedPneumaticCannonGun
+  id: WeaponImprovisedPneumaticCannonAdmeme
+  suffix: Admeme
+  components:
+  - type: Item
+    size: 9999
+  - type: Storage
+    capacity: 9999
+  - type: PneumaticCannon
+    gasUsage: 0
+    throwItems: false
+  - type: Gun
+    fireRate: 10
+    selectedMode: FullAuto
+    availableModes:
+    - SemiAuto
+    - FullAuto
+    soundGunshot:
+      path: /Audio/Effects/thunk.ogg
+    soundEmpty:
+      path: /Audio/Items/hiss.ogg