Make wielding automatically drop the item on your other hand (#27975)

* 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
This commit is contained in:
DrSmugleaf
2024-05-18 18:35:46 -07:00
committed by GitHub
parent 676fc22eb4
commit 3d41d5f2bc
5 changed files with 79 additions and 9 deletions

View File

@@ -1,4 +1,5 @@
using System.Linq; using System.Linq;
using Content.Shared.Hands.EntitySystems;
namespace Content.Shared.Hands.Components; namespace Content.Shared.Hands.Components;
@@ -20,6 +21,15 @@ public static class HandHelpers
/// </summary> /// </summary>
public static int CountFreeHands(this HandsComponent component) => component.Hands.Values.Count(hand => hand.IsEmpty); 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> /// <summary>
/// Get a list of hands that are currently holding nothing. This is a LinQ method, not a property, so cache /// 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. /// it instead of accessing this multiple times.

View File

@@ -5,7 +5,6 @@ using Content.Shared.Administration.Logs;
using Content.Shared.Hands.Components; using Content.Shared.Hands.Components;
using Content.Shared.Interaction; using Content.Shared.Interaction;
using Content.Shared.Inventory.VirtualItem; using Content.Shared.Inventory.VirtualItem;
using Content.Shared.Item;
using Content.Shared.Storage.EntitySystems; using Content.Shared.Storage.EntitySystems;
using Robust.Shared.Containers; using Robust.Shared.Containers;
using Robust.Shared.Input.Binding; using Robust.Shared.Input.Binding;
@@ -299,4 +298,16 @@ public abstract partial class SharedHandsSystem
return hands.Hands.TryGetValue(handId, out hand); 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;
}
} }

View File

@@ -4,6 +4,7 @@ using Content.Shared.Hands.EntitySystems;
using Content.Shared.Interaction; using Content.Shared.Interaction;
using Content.Shared.Inventory.Events; using Content.Shared.Inventory.Events;
using Content.Shared.Item; using Content.Shared.Item;
using Content.Shared.Popups;
using Robust.Shared.Containers; using Robust.Shared.Containers;
using Robust.Shared.Network; using Robust.Shared.Network;
using Robust.Shared.Prototypes; using Robust.Shared.Prototypes;
@@ -29,6 +30,7 @@ public abstract class SharedVirtualItemSystem : EntitySystem
[Dependency] private readonly SharedItemSystem _itemSystem = default!; [Dependency] private readonly SharedItemSystem _itemSystem = default!;
[Dependency] private readonly InventorySystem _inventorySystem = default!; [Dependency] private readonly InventorySystem _inventorySystem = default!;
[Dependency] private readonly SharedHandsSystem _handsSystem = default!; [Dependency] private readonly SharedHandsSystem _handsSystem = default!;
[Dependency] private readonly SharedPopupSystem _popup = default!;
[ValidatePrototypeId<EntityPrototype>] [ValidatePrototypeId<EntityPrototype>]
private const string VirtualItem = "VirtualItem"; private const string VirtualItem = "VirtualItem";
@@ -71,23 +73,53 @@ public abstract class SharedVirtualItemSystem : EntitySystem
} }
#region Hands #region Hands
/// <summary> /// <summary>
/// Spawns a virtual item in a empty hand /// Spawns a virtual item in a empty hand
/// </summary> /// </summary>
/// <param name="blockingEnt">The entity we will make a virtual entity copy of</param> /// <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="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)"/> /// <inheritdoc cref="TrySpawnVirtualItemInHand(Robust.Shared.GameObjects.EntityUid,Robust.Shared.GameObjects.EntityUid,bool)"/>
public bool TrySpawnVirtualItemInHand(EntityUid blockingEnt, EntityUid user, [NotNullWhen(true)] out EntityUid? virtualItem) 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; return false;
_handsSystem.DoPickup(user, hand, virtualItem.Value); 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, empty, virtualItem.Value);
return true; 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="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="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="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) public bool TrySpawnVirtualItemInInventory(EntityUid blockingEnt, EntityUid user, string slot, bool force = false)
{ {
return TrySpawnVirtualItemInInventory(blockingEnt, user, slot, force, out _); 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, /// that's done check if the found virtual entity is a copy of our matching entity,
/// if it is, delete it /// if it is, delete it
/// </summary> /// </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> /// <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) public void DeleteInSlotMatching(EntityUid user, EntityUid matching, string? slotName = null)
{ {
@@ -178,6 +213,7 @@ public abstract class SharedVirtualItemSystem : EntitySystem
/// </summary> /// </summary>
/// <param name="blockingEnt">The entity we will make a virtual entity copy of</param> /// <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="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) public bool TrySpawnVirtualItem(EntityUid blockingEnt, EntityUid user, [NotNullWhen(true)] out EntityUid? virtualItem)
{ {
if (_netManager.IsClient) if (_netManager.IsClient)

View File

@@ -161,7 +161,7 @@ public sealed class WieldableSystem : EntitySystem
return false; return false;
} }
if (hands.CountFreeHands() < component.FreeHandsRequired) if (_handsSystem.CountFreeableHands((user, hands)) < component.FreeHandsRequired)
{ {
if (!quiet) if (!quiet)
{ {
@@ -202,9 +202,21 @@ public sealed class WieldableSystem : EntitySystem
if (component.WieldSound != null) if (component.WieldSound != null)
_audioSystem.PlayPredicted(component.WieldSound, used, user); _audioSystem.PlayPredicted(component.WieldSound, used, user);
var virtuals = new List<EntityUid>();
for (var i = 0; i < component.FreeHandsRequired; i++) 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) if (TryComp(used, out UseDelayComponent? useDelay)

View File

@@ -0,0 +1 @@
virtual-item-dropped-other = You dropped {THE($dropped)}!