diff --git a/Content.Client/Weapons/Ranged/Systems/GunSystem.AmmoCounter.cs b/Content.Client/Weapons/Ranged/Systems/GunSystem.AmmoCounter.cs index dfb5418f11..32343af56f 100644 --- a/Content.Client/Weapons/Ranged/Systems/GunSystem.AmmoCounter.cs +++ b/Content.Client/Weapons/Ranged/Systems/GunSystem.AmmoCounter.cs @@ -58,11 +58,11 @@ public sealed partial class GunSystem RaiseLocalEvent(uid, ev, false); } - protected override void UpdateAmmoCount(EntityUid uid) + protected override void UpdateAmmoCount(EntityUid uid, bool prediction = true) { // Don't use resolves because the method is shared and there's no compref and I'm trying to // share as much code as possible - if (!Timing.IsFirstTimePredicted || + if (prediction && !Timing.IsFirstTimePredicted || !TryComp(uid, out var clientComp)) { return; @@ -98,7 +98,7 @@ public sealed partial class GunSystem { MinHeight = 15; HorizontalExpand = true; - VerticalAlignment = VAlignment.Center; + VerticalAlignment = Control.VAlignment.Center; AddChild(new BoxContainer { Orientation = BoxContainer.LayoutOrientation.Vertical, @@ -213,7 +213,7 @@ public sealed partial class GunSystem { MinHeight = 15; HorizontalExpand = true; - VerticalAlignment = VAlignment.Center; + VerticalAlignment = Control.VAlignment.Center; AddChild(new BoxContainer { @@ -300,7 +300,7 @@ public sealed partial class GunSystem { MinHeight = 15; HorizontalExpand = true; - VerticalAlignment = VAlignment.Center; + VerticalAlignment = Control.VAlignment.Center; AddChild(new BoxContainer { @@ -419,7 +419,7 @@ public sealed partial class GunSystem { MinHeight = 15; HorizontalExpand = true; - VerticalAlignment = VAlignment.Center; + VerticalAlignment = Control.VAlignment.Center; AddChild((_bulletsList = new BoxContainer { Orientation = BoxContainer.LayoutOrientation.Horizontal, diff --git a/Content.Shared/Timing/UseDelaySystem.cs b/Content.Shared/Timing/UseDelaySystem.cs index eb1819aeb7..34f12fa55e 100644 --- a/Content.Shared/Timing/UseDelaySystem.cs +++ b/Content.Shared/Timing/UseDelaySystem.cs @@ -61,4 +61,12 @@ public sealed class UseDelaySystem : EntitySystem Dirty(ent); return true; } + + public bool TryResetDelay(EntityUid uid, bool checkDelayed = false, UseDelayComponent? component = null) + { + if (!Resolve(uid, ref component, false)) + return false; + + return TryResetDelay((uid, component), checkDelayed); + } } diff --git a/Content.Shared/Weapons/Ranged/Systems/SharedGunSystem.Revolver.cs b/Content.Shared/Weapons/Ranged/Systems/SharedGunSystem.Revolver.cs index d3d3b7fcde..b8b00799c1 100644 --- a/Content.Shared/Weapons/Ranged/Systems/SharedGunSystem.Revolver.cs +++ b/Content.Shared/Weapons/Ranged/Systems/SharedGunSystem.Revolver.cs @@ -8,6 +8,7 @@ using Robust.Shared.Serialization; using Robust.Shared.Utility; using System; using System.Linq; +using Content.Shared.Interaction.Events; using JetBrains.Annotations; namespace Content.Shared.Weapons.Ranged.Systems; @@ -25,6 +26,17 @@ public partial class SharedGunSystem SubscribeLocalEvent>(OnRevolverVerbs); SubscribeLocalEvent(OnRevolverInteractUsing); SubscribeLocalEvent(OnRevolverGetAmmoCount); + SubscribeLocalEvent(OnRevolverUse); + } + + private void OnRevolverUse(EntityUid uid, RevolverAmmoProviderComponent component, UseInHandEvent args) + { + if (!_useDelay.TryResetDelay(uid)) + return; + + Cycle(component); + UpdateAmmoCount(uid, prediction: false); + Dirty(uid, component); } private void OnRevolverGetAmmoCount(EntityUid uid, RevolverAmmoProviderComponent component, ref GetAmmoCountEvent args) @@ -69,10 +81,9 @@ public partial class SharedGunSystem } // Handle spins - if (Timing.IsFirstTimePredicted) + if (oldIndex != state.CurrentIndex) { - if (oldIndex != state.CurrentIndex) - UpdateAmmoCount(uid); + UpdateAmmoCount(uid, prediction: false); } } @@ -133,6 +144,7 @@ public partial class SharedGunSystem component.AmmoSlots[index] = ent.Value; Containers.Insert(ent.Value, component.AmmoContainer); + SetChamber(index, component, uid); if (ev.Ammo.Count == 0) break; @@ -140,8 +152,8 @@ public partial class SharedGunSystem DebugTools.Assert(ammo.Count == 0); UpdateRevolverAppearance(revolverUid, component); - UpdateAmmoCount(uid); - Dirty(uid, component); + UpdateAmmoCount(revolverUid); + Dirty(revolverUid, component); Audio.PlayPredicted(component.SoundInsert, revolverUid, user); Popup(Loc.GetString("gun-revolver-insert"), revolverUid, user); @@ -161,11 +173,12 @@ public partial class SharedGunSystem component.AmmoSlots[index] = uid; Containers.Insert(uid, component.AmmoContainer); + SetChamber(index, component, uid); Audio.PlayPredicted(component.SoundInsert, revolverUid, user); Popup(Loc.GetString("gun-revolver-insert"), revolverUid, user); UpdateRevolverAppearance(revolverUid, component); - UpdateAmmoCount(uid); - Dirty(uid, component); + UpdateAmmoCount(revolverUid); + Dirty(revolverUid, component); return true; } @@ -173,6 +186,17 @@ public partial class SharedGunSystem return false; } + private void SetChamber(int index, RevolverAmmoProviderComponent component, EntityUid uid) + { + if (TryComp(uid, out var cartridge) && cartridge.Spent) + { + component.Chambers[index] = false; + return; + } + + component.Chambers[index] = true; + } + private void OnRevolverVerbs(EntityUid uid, RevolverAmmoProviderComponent component, GetVerbsEvent args) { if (!args.CanAccess || !args.CanInteract || args.Hands == null) @@ -252,8 +276,7 @@ public partial class SharedGunSystem public void EmptyRevolver(EntityUid revolverUid, RevolverAmmoProviderComponent component, EntityUid? user = null) { - var xform = Transform(revolverUid); - var mapCoordinates = xform.MapPosition; + var mapCoordinates = TransformSystem.GetMapCoordinates(revolverUid); var anyEmpty = false; for (var i = 0; i < component.Capacity; i++) @@ -284,6 +307,7 @@ public partial class SharedGunSystem { component.AmmoSlots[i] = null; Containers.Remove(slot.Value, component.AmmoContainer); + component.Chambers[i] = null; if (!_netManager.IsClient) EjectCartridge(slot.Value); @@ -295,7 +319,7 @@ public partial class SharedGunSystem if (anyEmpty) { Audio.PlayPredicted(component.SoundEject, revolverUid, user); - UpdateAmmoCount(revolverUid); + UpdateAmmoCount(revolverUid, prediction: false); UpdateRevolverAppearance(revolverUid, component); Dirty(revolverUid, component); } @@ -328,51 +352,63 @@ public partial class SharedGunSystem { var index = (currentIndex + i) % component.Capacity; var chamber = component.Chambers[index]; + EntityUid? ent = null; - // Get unspawned ent first if possible. - if (chamber != null) + // Get contained entity if it exists. + if (component.AmmoSlots[index] != null) + { + ent = component.AmmoSlots[index]!; + component.Chambers[index] = false; + } + // Try to spawn a round if it's available. + else if (chamber != null) { if (chamber == true) { - // TODO: This is kinda sussy boy - var ent = Spawn(component.FillPrototype, args.Coordinates); + // Pretend it's always been there. + ent = Spawn(component.FillPrototype, args.Coordinates); - if (TryComp(ent, out var cartridge)) + if (!_netManager.IsClient) { - component.Chambers[index] = false; - SetCartridgeSpent(ent, cartridge, true); - var spawned = Spawn(cartridge.Prototype, args.Coordinates); - args.Ammo.Add((spawned, EnsureShootable(spawned))); - Del(ent); - continue; + component.AmmoSlots[index] = ent; + Containers.Insert(ent.Value, component.AmmoContainer); } - component.Chambers[i] = null; - args.Ammo.Add((ent, EnsureShootable(ent))); + component.Chambers[index] = false; } } - else if (component.AmmoSlots[index] != null) + + // Chamber empty or spent + if (ent == null) + continue; + + if (TryComp(ent, out var cartridge)) { - var ent = component.AmmoSlots[index]!; - - if (TryComp(ent, out var cartridge)) - { - if (cartridge.Spent) - continue; - - SetCartridgeSpent(ent.Value, cartridge, true); - var spawned = Spawn(cartridge.Prototype, args.Coordinates); - args.Ammo.Add((spawned, EnsureShootable(spawned))); + if (cartridge.Spent) continue; - } - Containers.Remove(ent.Value, component.AmmoContainer); - component.AmmoSlots[index] = null; - args.Ammo.Add((ent.Value, EnsureShootable(ent.Value))); - TransformSystem.SetCoordinates(ent.Value, args.Coordinates); + // Mark cartridge as spent and if it's caseless delete from the chamber slot. + SetCartridgeSpent(ent.Value, cartridge, true); + var spawned = Spawn(cartridge.Prototype, args.Coordinates); + args.Ammo.Add((spawned, EnsureComp(spawned))); + + if (cartridge.DeleteOnSpawn) + component.Chambers[index] = null; + } + else + { + component.Chambers[index] = null; + args.Ammo.Add((ent.Value, EnsureComp(ent.Value))); + } + + // Delete the cartridge entity on client + if (_netManager.IsClient) + { + QueueDel(ent); } } + UpdateAmmoCount(uid, prediction: false); UpdateRevolverAppearance(uid, component); Dirty(uid, component); } diff --git a/Content.Shared/Weapons/Ranged/Systems/SharedGunSystem.cs b/Content.Shared/Weapons/Ranged/Systems/SharedGunSystem.cs index c7456ed019..5d061a3f8a 100644 --- a/Content.Shared/Weapons/Ranged/Systems/SharedGunSystem.cs +++ b/Content.Shared/Weapons/Ranged/Systems/SharedGunSystem.cs @@ -15,6 +15,7 @@ using Content.Shared.Popups; using Content.Shared.Projectiles; using Content.Shared.Tag; using Content.Shared.Throwing; +using Content.Shared.Timing; using Content.Shared.Verbs; using Content.Shared.Weapons.Melee; using Content.Shared.Weapons.Melee.Events; @@ -61,6 +62,7 @@ public abstract partial class SharedGunSystem : EntitySystem [Dependency] protected readonly SharedTransformSystem TransformSystem = default!; [Dependency] protected readonly TagSystem TagSystem = default!; [Dependency] protected readonly ThrowingSystem ThrowingSystem = default!; + [Dependency] private readonly UseDelaySystem _useDelay = default!; private const float InteractNextFire = 0.3f; private const double SafetyNextFire = 0.5; @@ -408,7 +410,7 @@ public abstract partial class SharedGunSystem : EntitySystem /// /// Call this whenever the ammo count for a gun changes. /// - protected virtual void UpdateAmmoCount(EntityUid uid) {} + protected virtual void UpdateAmmoCount(EntityUid uid, bool prediction = true) {} protected void SetCartridgeSpent(EntityUid uid, CartridgeAmmoComponent cartridge, bool spent) { diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Revolvers/revolvers.yml b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Revolvers/revolvers.yml index be64e7eb2c..bd043c997d 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Revolvers/revolvers.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Revolvers/revolvers.yml @@ -21,6 +21,7 @@ slots: - suitStorage - Belt + - type: AmmoCounter - type: Gun selectedMode: SemiAuto fireRate: 1.5 @@ -28,6 +29,8 @@ - SemiAuto soundGunshot: path: /Audio/Weapons/Guns/Gunshots/revolver.ogg + - type: UseDelay + delay: 0.66 - type: ContainerContainer containers: revolver-ammo: !type:Container