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;
[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";
}
#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;
}
/// <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 _);
/// 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)
{
/// </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)
return false;
}
- if (hands.CountFreeHands() < component.FreeHandsRequired)
+ if (_handsSystem.CountFreeableHands((user, hands)) < component.FreeHandsRequired)
{
if (!quiet)
{
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)