]> git.smokeofanarchy.ru Git - space-station-14.git/commitdiff
Make wielding automatically drop the item on your other hand (#27975)
authorDrSmugleaf <10968691+DrSmugleaf@users.noreply.github.com>
Sun, 19 May 2024 01:35:46 +0000 (18:35 -0700)
committerGitHub <noreply@github.com>
Sun, 19 May 2024 01:35:46 +0000 (18:35 -0700)
* Make wielding automatically drop the item on your other hand

* Fix docs

* Remove redundant parameter

* Fix not deleting virtuals on fail

* Make count freeable hands method

* Add popup when dropping item

Content.Shared/Hands/Components/HandHelpers.cs
Content.Shared/Hands/EntitySystems/SharedHandsSystem.cs
Content.Shared/Inventory/VirtualItem/SharedVirtualItemSystem.cs
Content.Shared/Wieldable/WieldableSystem.cs
Resources/Locale/en-US/virtual/virtual-item.ftl [new file with mode: 0644]

index 11fff6d9c8a9926512efaf64b6e71715dcfea67b..aecf3a6936933039a810bfec93c851ebf91e6f47 100644 (file)
@@ -1,4 +1,5 @@
 using System.Linq;
+using Content.Shared.Hands.EntitySystems;
 
 namespace Content.Shared.Hands.Components;
 
@@ -20,6 +21,15 @@ public static class HandHelpers
     /// </summary>
     public static int CountFreeHands(this HandsComponent component) => component.Hands.Values.Count(hand => hand.IsEmpty);
 
+    /// <summary>
+    ///     Get the number of hands that are not currently holding anything. This is a LinQ method, not a property, so
+    ///     cache it instead of accessing this multiple times.
+    /// </summary>
+    public static int CountFreeableHands(this Entity<HandsComponent> component, SharedHandsSystem system)
+    {
+        return system.CountFreeableHands(component);
+    }
+
     /// <summary>
     ///     Get a list of hands that are currently holding nothing. This is a LinQ method, not a property, so cache
     ///     it instead of accessing this multiple times.
index fd732009e9a2f6b6777f69681d4ef7050ba15ed3..e48aafeab52f69883db6ee824c8bb08119244cee 100644 (file)
@@ -5,7 +5,6 @@ using Content.Shared.Administration.Logs;
 using Content.Shared.Hands.Components;
 using Content.Shared.Interaction;
 using Content.Shared.Inventory.VirtualItem;
-using Content.Shared.Item;
 using Content.Shared.Storage.EntitySystems;
 using Robust.Shared.Containers;
 using Robust.Shared.Input.Binding;
@@ -299,4 +298,16 @@ public abstract partial class SharedHandsSystem
 
         return hands.Hands.TryGetValue(handId, out hand);
     }
+
+    public int CountFreeableHands(Entity<HandsComponent> hands)
+    {
+        var freeable = 0;
+        foreach (var hand in hands.Comp.Hands.Values)
+        {
+            if (hand.IsEmpty || CanDropHeld(hands, hand))
+                freeable++;
+        }
+
+        return freeable;
+    }
 }
index e45530e4582313491d93b4b6ddce7c969f75f601..b31cc75576387d40e89d7ebab7586d5d0ccfdd64 100644 (file)
@@ -4,6 +4,7 @@ using Content.Shared.Hands.EntitySystems;
 using Content.Shared.Interaction;
 using Content.Shared.Inventory.Events;
 using Content.Shared.Item;
+using Content.Shared.Popups;
 using Robust.Shared.Containers;
 using Robust.Shared.Network;
 using Robust.Shared.Prototypes;
@@ -29,6 +30,7 @@ public abstract class SharedVirtualItemSystem : EntitySystem
     [Dependency] private readonly SharedItemSystem _itemSystem = default!;
     [Dependency] private readonly InventorySystem _inventorySystem = default!;
     [Dependency] private readonly SharedHandsSystem _handsSystem = default!;
+    [Dependency] private readonly SharedPopupSystem _popup = default!;
 
     [ValidatePrototypeId<EntityPrototype>]
     private const string VirtualItem = "VirtualItem";
@@ -71,23 +73,53 @@ public abstract class SharedVirtualItemSystem : EntitySystem
     }
 
     #region Hands
+
     /// <summary>
     /// Spawns a virtual item in a empty hand
     /// </summary>
     /// <param name="blockingEnt">The entity we will make a virtual entity copy of</param>
     /// <param name="user">The entity that we want to insert the virtual entity</param>
-    public bool TrySpawnVirtualItemInHand(EntityUid blockingEnt, EntityUid user)
+    /// <param name="dropOthers">Whether or not to try and drop other items to make space</param>
+    public bool TrySpawnVirtualItemInHand(EntityUid blockingEnt, EntityUid user, bool dropOthers = false)
     {
-        return TrySpawnVirtualItemInHand(blockingEnt, user, out _);
+        return TrySpawnVirtualItemInHand(blockingEnt, user, out _, dropOthers);
     }
 
-    /// <inheritdoc cref="TrySpawnVirtualItemInHand(Robust.Shared.GameObjects.EntityUid,Robust.Shared.GameObjects.EntityUid)"/>
-    public bool TrySpawnVirtualItemInHand(EntityUid blockingEnt, EntityUid user, [NotNullWhen(true)] out EntityUid? virtualItem)
+    /// <inheritdoc cref="TrySpawnVirtualItemInHand(Robust.Shared.GameObjects.EntityUid,Robust.Shared.GameObjects.EntityUid,bool)"/>
+    public bool TrySpawnVirtualItemInHand(EntityUid blockingEnt, EntityUid user, [NotNullWhen(true)] out EntityUid? virtualItem, bool dropOthers = false)
     {
-        if (!TrySpawnVirtualItem(blockingEnt, user, out virtualItem) || !_handsSystem.TryGetEmptyHand(user, out var hand))
+        virtualItem = null;
+        if (!_handsSystem.TryGetEmptyHand(user, out var empty))
+        {
+            if (!dropOthers)
+                return false;
+
+            foreach (var hand in _handsSystem.EnumerateHands(user))
+            {
+                if (hand.HeldEntity is not { } held)
+                    continue;
+
+                if (held == blockingEnt || HasComp<VirtualItemComponent>(held))
+                    continue;
+
+                if (!_handsSystem.TryDrop(user, hand))
+                    continue;
+
+                if (!TerminatingOrDeleted(held))
+                    _popup.PopupClient(Loc.GetString("virtual-item-dropped-other", ("dropped", held)), user, user);
+
+                empty = hand;
+                break;
+            }
+        }
+
+        if (empty == null)
+            return false;
+
+        if (!TrySpawnVirtualItem(blockingEnt, user, out virtualItem))
             return false;
 
-        _handsSystem.DoPickup(user, hand, virtualItem.Value);
+        _handsSystem.DoPickup(user, empty, virtualItem.Value);
         return true;
     }
 
@@ -120,6 +152,7 @@ public abstract class SharedVirtualItemSystem : EntitySystem
     /// <param name="blockingEnt">The entity we will make a virtual entity copy of</param>
     /// <param name="user">The entity that we want to insert the virtual entity</param>
     /// <param name="slot">The slot to which we will insert the virtual entity (could be the "shoes" slot, for example)</param>
+    /// <param name="force">Whether or not to force an equip</param>
     public bool TrySpawnVirtualItemInInventory(EntityUid blockingEnt, EntityUid user, string slot, bool force = false)
     {
         return TrySpawnVirtualItemInInventory(blockingEnt, user, slot, force, out _);
@@ -140,6 +173,8 @@ public abstract class SharedVirtualItemSystem : EntitySystem
     /// that's done check if the found virtual entity is a copy of our matching entity,
     /// if it is, delete it
     /// </summary>
+    /// <param name="user">The entity that we want to delete the virtual entity from</param>
+    /// <param name="matching">The entity that made the virtual entity</param>
     /// <param name="slotName">Set this param if you have the name of the slot, it avoids unnecessary queries</param>
     public void DeleteInSlotMatching(EntityUid user, EntityUid matching, string? slotName = null)
     {
@@ -178,6 +213,7 @@ public abstract class SharedVirtualItemSystem : EntitySystem
     /// </summary>
     /// <param name="blockingEnt">The entity we will make a virtual entity copy of</param>
     /// <param name="user">The entity that we want to insert the virtual entity</param>
+    /// <param name="virtualItem">The virtual item, if spawned</param>
     public bool TrySpawnVirtualItem(EntityUid blockingEnt, EntityUid user, [NotNullWhen(true)] out EntityUid? virtualItem)
     {
         if (_netManager.IsClient)
index b765566f44af66de6a13ad2bd4eda1c0d41f40fd..cee6c65fa11eb91e1e6d788387bcb3c308803217 100644 (file)
@@ -161,7 +161,7 @@ public sealed class WieldableSystem : EntitySystem
             return false;
         }
 
-        if (hands.CountFreeHands() < component.FreeHandsRequired)
+        if (_handsSystem.CountFreeableHands((user, hands)) < component.FreeHandsRequired)
         {
             if (!quiet)
             {
@@ -202,9 +202,21 @@ public sealed class WieldableSystem : EntitySystem
         if (component.WieldSound != null)
             _audioSystem.PlayPredicted(component.WieldSound, used, user);
 
+        var virtuals = new List<EntityUid>();
         for (var i = 0; i < component.FreeHandsRequired; i++)
         {
-            _virtualItemSystem.TrySpawnVirtualItemInHand(used, user);
+            if (_virtualItemSystem.TrySpawnVirtualItemInHand(used, user, out var virtualItem, true))
+            {
+                virtuals.Add(virtualItem.Value);
+                continue;
+            }
+
+            foreach (var existingVirtual in virtuals)
+            {
+                QueueDel(existingVirtual);
+            }
+
+            return false;
         }
 
         if (TryComp(used, out UseDelayComponent? useDelay)
diff --git a/Resources/Locale/en-US/virtual/virtual-item.ftl b/Resources/Locale/en-US/virtual/virtual-item.ftl
new file mode 100644 (file)
index 0000000..cb91f24
--- /dev/null
@@ -0,0 +1 @@
+virtual-item-dropped-other = You dropped {THE($dropped)}!