]> git.smokeofanarchy.ru Git - space-station-14.git/commitdiff
Add WieldingBlockerComponent (#37778)
authorslarticodefast <161409025+slarticodefast@users.noreply.github.com>
Mon, 26 May 2025 03:50:30 +0000 (05:50 +0200)
committerGitHub <noreply@github.com>
Mon, 26 May 2025 03:50:30 +0000 (23:50 -0400)
initial commit

Content.Shared/Hands/EntitySystems/SharedHandsSystem.Relay.cs
Content.Shared/Inventory/InventorySystem.Relay.cs
Content.Shared/Wieldable/Components/WieldingBlockerComponent.cs [new file with mode: 0644]
Content.Shared/Wieldable/Events.cs
Content.Shared/Wieldable/SharedWieldableSystem.cs
Resources/Locale/en-US/wieldable/wieldable-component.ftl

index aa367f71f72f8f856919e46d8b4b3ce40be7b74a..67db19389460e234ca9f007b1c84eb0736404526 100644 (file)
@@ -4,6 +4,7 @@ using Content.Shared.Hands.Components;
 using Content.Shared.Movement.Systems;
 using Content.Shared.Projectiles;
 using Content.Shared.Weapons.Ranged.Events;
+using Content.Shared.Wieldable;
 
 namespace Content.Shared.Hands.EntitySystems;
 
@@ -19,6 +20,8 @@ public abstract partial class SharedHandsSystem
         SubscribeLocalEvent<HandsComponent, ExtinguishEvent>(RefRelayEvent);
         SubscribeLocalEvent<HandsComponent, ProjectileReflectAttemptEvent>(RefRelayEvent);
         SubscribeLocalEvent<HandsComponent, HitScanReflectAttemptEvent>(RefRelayEvent);
+        SubscribeLocalEvent<HandsComponent, WieldAttemptEvent>(RefRelayEvent);
+        SubscribeLocalEvent<HandsComponent, UnwieldAttemptEvent>(RefRelayEvent);
     }
 
     private void RelayEvent<T>(Entity<HandsComponent> entity, ref T args) where T : EntityEventArgs
index 84f2dc374bb567fe40ce10e72320320379964c3f..f3ab87be389f29d98dabd5878a8aad53819a5455 100644 (file)
@@ -24,6 +24,7 @@ using Content.Shared.Strip.Components;
 using Content.Shared.Temperature;
 using Content.Shared.Verbs;
 using Content.Shared.Weapons.Ranged.Events;
+using Content.Shared.Wieldable;
 using Content.Shared.Zombies;
 
 namespace Content.Shared.Inventory;
@@ -63,6 +64,8 @@ public partial class InventorySystem
         SubscribeLocalEvent<InventoryComponent, ProjectileReflectAttemptEvent>(RefRelayInventoryEvent);
         SubscribeLocalEvent<InventoryComponent, HitScanReflectAttemptEvent>(RefRelayInventoryEvent);
         SubscribeLocalEvent<InventoryComponent, GetContrabandDetailsEvent>(RefRelayInventoryEvent);
+        SubscribeLocalEvent<InventoryComponent, WieldAttemptEvent>(RefRelayInventoryEvent);
+        SubscribeLocalEvent<InventoryComponent, UnwieldAttemptEvent>(RefRelayInventoryEvent);
 
         // Eye/vision events
         SubscribeLocalEvent<InventoryComponent, CanSeeAttemptEvent>(RelayInventoryEvent);
diff --git a/Content.Shared/Wieldable/Components/WieldingBlockerComponent.cs b/Content.Shared/Wieldable/Components/WieldingBlockerComponent.cs
new file mode 100644 (file)
index 0000000..320322d
--- /dev/null
@@ -0,0 +1,23 @@
+using Robust.Shared.GameStates;
+
+namespace Content.Shared.Wieldable.Components;
+
+/// <summary>
+/// Blocks an entity from wielding items.
+/// When added to an item, it will block wielding when held in hand or equipped.
+/// </summary>
+[RegisterComponent, NetworkedComponent, AutoGenerateComponentState]
+public sealed partial class WieldingBlockerComponent : Component
+{
+    /// <summary>
+    /// Block wielding when this item is held in a hand?
+    /// </summary>
+    [DataField, AutoNetworkedField]
+    public bool BlockInHand = true;
+
+    /// <summary>
+    /// Block wielding when this item is equipped?
+    /// </summary>
+    [DataField, AutoNetworkedField]
+    public bool BlockEquipped = true;
+}
index fe7e084c02733135bba52944f1feae7acbbb4b25..f682ce8b80ebb794eb3438f5db4fdd8dcc30ed4d 100644 (file)
@@ -1,3 +1,5 @@
+using Content.Shared.Inventory;
+
 namespace Content.Shared.Wieldable;
 
 /// <summary>
@@ -14,12 +16,18 @@ public readonly record struct ItemWieldedEvent(EntityUid User);
 public readonly record struct ItemUnwieldedEvent(EntityUid User, bool Force);
 
 /// <summary>
-/// Raised directed on an item before a user tries to wield it.
+/// Raised directed on an user and all the items in their inventory and hands before they wield an item.
 /// If this event is cancelled wielding will not happen.
 /// </summary>
 [ByRefEvent]
-public record struct WieldAttemptEvent(EntityUid User, bool Cancelled = false)
+public record struct WieldAttemptEvent(EntityUid User, EntityUid Wielded, bool Cancelled = false) : IInventoryRelayEvent
 {
+    /// <summary>
+    /// Popup message for the user to tell them why they cannot wield if Cancelled
+    /// </summary>
+    public string? Message;
+
+    SlotFlags IInventoryRelayEvent.TargetSlots => SlotFlags.WITHOUT_POCKET;
     public void Cancel()
     {
         Cancelled = true;
@@ -27,15 +35,21 @@ public record struct WieldAttemptEvent(EntityUid User, bool Cancelled = false)
 }
 
 /// <summary>
-/// Raised directed on an item before a user tries to stop wielding it willingly.
+/// Raised directed on an user and all the items in their inventory and hands before they unwield an item willingly.
 /// If this event is cancelled unwielding will not happen.
 /// </summary>
 /// <remarks>
 /// This event is not raised if the user is forced to unwield the item.
 /// </remarks>
 [ByRefEvent]
-public record struct UnwieldAttemptEvent(EntityUid User, bool Cancelled = false)
+public record struct UnwieldAttemptEvent(EntityUid User, EntityUid Wielded, bool Cancelled = false) : IInventoryRelayEvent
 {
+    /// <summary>
+    /// Popup message for the user to tell them why they cannot unwield if Cancelled
+    /// </summary>
+    public string? Message;
+
+    SlotFlags IInventoryRelayEvent.TargetSlots => SlotFlags.WITHOUT_POCKET;
     public void Cancel()
     {
         Cancelled = true;
index ec476e6db6a3c4419f7f8644ceb4a4a3d986dd9a..83ed58388a10205d6522d9ab459c32df9002971b 100644 (file)
@@ -1,11 +1,12 @@
 using System.Linq;
-using Content.Shared.Camera;
 using Content.Shared.Examine;
 using Content.Shared.Hands;
 using Content.Shared.Hands.Components;
 using Content.Shared.Hands.EntitySystems;
 using Content.Shared.IdentityManagement;
 using Content.Shared.Interaction.Events;
+using Content.Shared.Inventory;
+using Content.Shared.Inventory.Events;
 using Content.Shared.Inventory.VirtualItem;
 using Content.Shared.Item;
 using Content.Shared.Movement.Components;
@@ -22,7 +23,6 @@ using Content.Shared.Weapons.Ranged.Systems;
 using Content.Shared.Wieldable.Components;
 using Robust.Shared.Audio.Systems;
 using Robust.Shared.Collections;
-using Robust.Shared.Network;
 using Robust.Shared.Timing;
 
 namespace Content.Shared.Wieldable;
@@ -51,6 +51,12 @@ public abstract class SharedWieldableSystem : EntitySystem
         SubscribeLocalEvent<WieldableComponent, GetVerbsEvent<InteractionVerb>>(AddToggleWieldVerb);
         SubscribeLocalEvent<WieldableComponent, HandDeselectedEvent>(OnDeselectWieldable);
 
+        SubscribeLocalEvent<WieldingBlockerComponent, GotEquippedEvent>(OnBlockerEquipped);
+        SubscribeLocalEvent<WieldingBlockerComponent, GotEquippedHandEvent>(OnBlockerEquippedHand);
+        SubscribeLocalEvent<WieldingBlockerComponent, WieldAttemptEvent>(OnBlockerAttempt);
+        SubscribeLocalEvent<WieldingBlockerComponent, InventoryRelayedEvent<WieldAttemptEvent>>(OnBlockerAttempt);
+        SubscribeLocalEvent<WieldingBlockerComponent, HeldRelayedEvent<WieldAttemptEvent>>(OnBlockerAttempt);
+
         SubscribeLocalEvent<MeleeRequiresWieldComponent, AttemptMeleeEvent>(OnMeleeAttempt);
         SubscribeLocalEvent<GunRequiresWieldComponent, ExaminedEvent>(OnExamineRequires);
         SubscribeLocalEvent<GunRequiresWieldComponent, ShotAttemptedEvent>(OnShootAttempt);
@@ -186,14 +192,55 @@ public abstract class SharedWieldableSystem : EntitySystem
             return;
 
         if (!component.Wielded)
-            args.Handled = TryWield(uid, component, args.User);
+        {
+            TryWield(uid, component, args.User);
+            args.Handled = true; // always mark as handled or we will cycle ammo when wielding is blocked
+        }
         else if (component.UnwieldOnUse)
-            args.Handled = TryUnwield(uid, component, args.User);
+        {
+            TryUnwield(uid, component, args.User);
+            args.Handled = true;
+        }
 
         if (HasComp<UseDelayComponent>(uid) && !component.UseDelayOnWield)
             args.ApplyDelay = false;
     }
 
+    private void OnBlockerEquipped(Entity<WieldingBlockerComponent> ent, ref GotEquippedEvent args)
+    {
+        if (ent.Comp.BlockEquipped)
+            UnwieldAll(args.Equipee, force: true);
+    }
+
+    private void OnBlockerEquippedHand(Entity<WieldingBlockerComponent> ent, ref GotEquippedHandEvent args)
+    {
+        if (ent.Comp.BlockInHand)
+            UnwieldAll(args.User, force: true);
+    }
+
+    private void OnBlockerAttempt(Entity<WieldingBlockerComponent> ent, ref InventoryRelayedEvent<WieldAttemptEvent> args)
+    {
+        if (ent.Comp.BlockEquipped)
+        {
+            args.Args.Message = Loc.GetString("wieldable-component-blocked-wield", ("blocker", ent.Owner), ("item", args.Args.Wielded));
+            args.Args.Cancelled = true;
+        }
+    }
+
+    private void OnBlockerAttempt(Entity<WieldingBlockerComponent> ent, ref HeldRelayedEvent<WieldAttemptEvent> args)
+    {
+        if (ent.Comp.BlockInHand)
+        {
+            args.Args.Message = Loc.GetString("wieldable-component-blocked-wield", ("blocker", ent.Owner), ("item", args.Args.Wielded));
+            args.Args.Cancelled = true;
+        }
+    }
+
+    private void OnBlockerAttempt(Entity<WieldingBlockerComponent> ent, ref WieldAttemptEvent args)
+    {
+        args.Cancelled = true;
+    }
+
     public bool CanWield(EntityUid uid, WieldableComponent component, EntityUid user, bool quiet = false)
     {
         // Do they have enough hands free?
@@ -242,11 +289,15 @@ public abstract class SharedWieldableSystem : EntitySystem
                 return false;
         }
 
-        var attemptEv = new WieldAttemptEvent(user);
-        RaiseLocalEvent(used, ref attemptEv);
+        var attemptEv = new WieldAttemptEvent(user, used);
+        RaiseLocalEvent(user, ref attemptEv);
 
         if (attemptEv.Cancelled)
+        {
+            if (attemptEv.Message != null)
+                _popup.PopupClient(attemptEv.Message, user, user);
             return false;
+        }
 
         if (TryComp<ItemComponent>(used, out var item))
         {
@@ -298,11 +349,15 @@ public abstract class SharedWieldableSystem : EntitySystem
 
         if (!force)
         {
-            var attemptEv = new UnwieldAttemptEvent(user);
-            RaiseLocalEvent(used, ref attemptEv);
+            var attemptEv = new UnwieldAttemptEvent(user, used);
+            RaiseLocalEvent(user, ref attemptEv);
 
             if (attemptEv.Cancelled)
+            {
+                if (attemptEv.Message != null)
+                    _popup.PopupClient(attemptEv.Message, user, user);
                 return false;
+            }
         }
 
         SetWielded((used, component), false);
@@ -312,6 +367,19 @@ public abstract class SharedWieldableSystem : EntitySystem
         return true;
     }
 
+    /// <summary>
+    /// Makes an entity unwield all currently wielded items.
+    /// </summary>
+    /// <param name="force">If this is true we will bypass UnwieldAttemptEvent.</param>
+    public void UnwieldAll(Entity<HandsComponent?> wielder, bool force = false)
+    {
+        foreach (var held in _hands.EnumerateHeld(wielder.Owner, wielder.Comp))
+        {
+            if (TryComp<WieldableComponent>(held, out var wieldable))
+                TryUnwield(held, wieldable, wielder, force);
+        }
+    }
+
     /// <summary>
     /// Sets wielded without doing any checks.
     /// </summary>
index 1c88e4572706437514b722f7062d9ee675ec934e..f4c544696080ae0e2543a0eef242147cd8c1c773 100644 (file)
@@ -7,6 +7,7 @@ wieldable-component-successful-wield = You wield { THE($item) }.
 wieldable-component-failed-wield = You unwield { THE($item) }.
 wieldable-component-successful-wield-other = { CAPITALIZE(THE($user)) } wields { THE($item) }.
 wieldable-component-failed-wield-other = { CAPITALIZE(THE($user)) } unwields { THE($item) }.
+wieldable-component-blocked-wield = { CAPITALIZE(THE($blocker)) } blocks you from wielding { THE($item) }.
 
 wieldable-component-no-hands = You don't have enough hands!
 wieldable-component-not-enough-free-hands = {$number ->