diff --git a/Content.Server/Inventory/ServerInventorySystem.cs b/Content.Server/Inventory/ServerInventorySystem.cs index e3783753bb..64cfc447b4 100644 --- a/Content.Server/Inventory/ServerInventorySystem.cs +++ b/Content.Server/Inventory/ServerInventorySystem.cs @@ -31,8 +31,8 @@ namespace Content.Server.Inventory var enumerator = new InventorySlotEnumerator(source.Comp); while (enumerator.NextItem(out var item, out var slot)) { - if (TryUnequip(source, slot.Name, true, true, inventory: source.Comp)) - TryEquip(target, item, slot.Name , true, true, inventory: target.Comp); + if (TryUnequip(source, slot.Name, true, true, inventory: source.Comp, triggerHandContact: true)) + TryEquip(target, item, slot.Name , true, true, inventory: target.Comp, triggerHandContact: true); } } } diff --git a/Content.Server/Strip/StrippableSystem.cs b/Content.Server/Strip/StrippableSystem.cs index b74e40e1da..b3efa392b6 100644 --- a/Content.Server/Strip/StrippableSystem.cs +++ b/Content.Server/Strip/StrippableSystem.cs @@ -9,6 +9,7 @@ using Content.Shared.Ensnaring.Components; using Content.Shared.Hands.Components; using Content.Shared.Hands.EntitySystems; using Content.Shared.IdentityManagement; +using Content.Shared.Interaction; using Content.Shared.Interaction.Events; using Content.Shared.Inventory; using Content.Shared.Inventory.VirtualItem; diff --git a/Content.Shared/Clothing/EntitySystems/ClothingSystem.cs b/Content.Shared/Clothing/EntitySystems/ClothingSystem.cs index d752afc1ad..a7e52180cd 100644 --- a/Content.Shared/Clothing/EntitySystems/ClothingSystem.cs +++ b/Content.Shared/Clothing/EntitySystems/ClothingSystem.cs @@ -65,14 +65,14 @@ public abstract class ClothingSystem : EntitySystem if (!_invSystem.TryUnequip(userEnt, slotDef.Name, true, inventory: userEnt, checkDoafter: true)) continue; - if (!_invSystem.TryEquip(userEnt, toEquipEnt, slotDef.Name, true, inventory: userEnt, clothing: toEquipEnt, checkDoafter: true)) + if (!_invSystem.TryEquip(userEnt, toEquipEnt, slotDef.Name, true, inventory: userEnt, clothing: toEquipEnt, checkDoafter: true, triggerHandContact: true)) continue; _handsSystem.PickupOrDrop(userEnt, slotEntity.Value, handsComp: userEnt); } else { - if (!_invSystem.TryEquip(userEnt, toEquipEnt, slotDef.Name, true, inventory: userEnt, clothing: toEquipEnt, checkDoafter: true)) + if (!_invSystem.TryEquip(userEnt, toEquipEnt, slotDef.Name, true, inventory: userEnt, clothing: toEquipEnt, checkDoafter: true, triggerHandContact: true)) continue; } @@ -134,7 +134,7 @@ public abstract class ClothingSystem : EntitySystem { if (args.Handled || args.Cancelled || args.Target is not { } target) return; - args.Handled = _invSystem.TryUnequip(args.User, target, args.Slot, clothing: ent.Comp, predicted: true, checkDoafter: false); + args.Handled = _invSystem.TryUnequip(args.User, target, args.Slot, clothing: ent.Comp, predicted: true, checkDoafter: false, triggerHandContact: true); if (args.Handled) _handsSystem.TryPickup(args.User, ent); } diff --git a/Content.Shared/Clothing/EntitySystems/ToggleableClothingSystem.cs b/Content.Shared/Clothing/EntitySystems/ToggleableClothingSystem.cs index c63dfb5901..4c8de4def1 100644 --- a/Content.Shared/Clothing/EntitySystems/ToggleableClothingSystem.cs +++ b/Content.Shared/Clothing/EntitySystems/ToggleableClothingSystem.cs @@ -160,7 +160,7 @@ public sealed class ToggleableClothingSystem : EntitySystem // This should maybe double check that the entity currently in the slot is actually the attached clothing, but // if its not, then something else has gone wrong already... if (component.Container != null && component.Container.ContainedEntity == null && component.ClothingUid != null) - _inventorySystem.TryUnequip(args.Equipee, component.Slot, force: true); + _inventorySystem.TryUnequip(args.Equipee, component.Slot, force: true, triggerHandContact: true); } private void OnRemoveToggleable(EntityUid uid, ToggleableClothingComponent component, ComponentRemove args) @@ -248,7 +248,7 @@ public sealed class ToggleableClothingSystem : EntitySystem user, user); } else - _inventorySystem.TryEquip(user, parent, component.ClothingUid.Value, component.Slot); + _inventorySystem.TryEquip(user, parent, component.ClothingUid.Value, component.Slot, triggerHandContact: true); } private void OnGetActions(EntityUid uid, ToggleableClothingComponent component, GetItemActionsEvent args) diff --git a/Content.Shared/Hands/EntitySystems/SharedHandsSystem.Pickup.cs b/Content.Shared/Hands/EntitySystems/SharedHandsSystem.Pickup.cs index 0fbf87f5af..5c95983631 100644 --- a/Content.Shared/Hands/EntitySystems/SharedHandsSystem.Pickup.cs +++ b/Content.Shared/Hands/EntitySystems/SharedHandsSystem.Pickup.cs @@ -242,6 +242,8 @@ public abstract partial class SharedHandsSystem : EntitySystem return; } + _interactionSystem.DoContactInteraction(uid, entity); //Possibly fires twice if manually picked up via interacting with the object + if (log) _adminLogger.Add(LogType.Pickup, LogImpact.Low, $"{ToPrettyString(uid):user} picked up {ToPrettyString(entity):entity}"); diff --git a/Content.Shared/Inventory/InventorySystem.Equip.cs b/Content.Shared/Inventory/InventorySystem.Equip.cs index 8158b8c2f6..4988fd96be 100644 --- a/Content.Shared/Inventory/InventorySystem.Equip.cs +++ b/Content.Shared/Inventory/InventorySystem.Equip.cs @@ -97,7 +97,7 @@ public abstract partial class InventorySystem // unequip the item. if (itemUid != null) { - if (!TryUnequip(actor, ev.Slot, out var item, predicted: true, inventory: inventory, checkDoafter: true)) + if (!TryUnequip(actor, ev.Slot, out var item, predicted: true, inventory: inventory, checkDoafter: true, triggerHandContact: true)) return; _handsSystem.PickupOrDrop(actor, item.Value); @@ -120,15 +120,15 @@ public abstract partial class InventorySystem RaiseLocalEvent(held.Value, new HandDeselectedEvent(actor)); - TryEquip(actor, actor, held.Value, ev.Slot, predicted: true, inventory: inventory, force: true, checkDoafter: true); + TryEquip(actor, actor, held.Value, ev.Slot, predicted: true, inventory: inventory, force: true, checkDoafter: true, triggerHandContact: true); } public bool TryEquip(EntityUid uid, EntityUid itemUid, string slot, bool silent = false, bool force = false, bool predicted = false, - InventoryComponent? inventory = null, ClothingComponent? clothing = null, bool checkDoafter = false) => - TryEquip(uid, uid, itemUid, slot, silent, force, predicted, inventory, clothing, checkDoafter); + InventoryComponent? inventory = null, ClothingComponent? clothing = null, bool checkDoafter = false, bool triggerHandContact = false) => + TryEquip(uid, uid, itemUid, slot, silent, force, predicted, inventory, clothing, checkDoafter, triggerHandContact); public bool TryEquip(EntityUid actor, EntityUid target, EntityUid itemUid, string slot, bool silent = false, bool force = false, bool predicted = false, - InventoryComponent? inventory = null, ClothingComponent? clothing = null, bool checkDoafter = false) + InventoryComponent? inventory = null, ClothingComponent? clothing = null, bool checkDoafter = false, bool triggerHandContact = false) { if (!Resolve(target, ref inventory, false)) { @@ -190,6 +190,10 @@ public abstract partial class InventorySystem _audio.PlayPredicted(clothing.EquipSound, target, actor); } + // If new gloves are equipped, trigger OnContactInteraction for held items + if (triggerHandContact && !((slotDefinition.SlotFlags & SlotFlags.GLOVES) == 0)) + TriggerHandContactInteraction(target); + Dirty(target, inventory); _movementSpeed.RefreshMovementSpeedModifiers(target); @@ -320,9 +324,10 @@ public abstract partial class InventorySystem InventoryComponent? inventory = null, ClothingComponent? clothing = null, bool reparent = true, - bool checkDoafter = false) + bool checkDoafter = false, + bool triggerHandContact = false) { - return TryUnequip(uid, uid, slot, silent, force, predicted, inventory, clothing, reparent, checkDoafter); + return TryUnequip(uid, uid, slot, silent, force, predicted, inventory, clothing, reparent, checkDoafter, triggerHandContact); } public bool TryUnequip( @@ -335,9 +340,10 @@ public abstract partial class InventorySystem InventoryComponent? inventory = null, ClothingComponent? clothing = null, bool reparent = true, - bool checkDoafter = false) + bool checkDoafter = false, + bool triggerHandContact = false) { - return TryUnequip(actor, target, slot, out _, silent, force, predicted, inventory, clothing, reparent, checkDoafter); + return TryUnequip(actor, target, slot, out _, silent, force, predicted, inventory, clothing, reparent, checkDoafter, triggerHandContact); } public bool TryUnequip( @@ -350,9 +356,10 @@ public abstract partial class InventorySystem InventoryComponent? inventory = null, ClothingComponent? clothing = null, bool reparent = true, - bool checkDoafter = false) + bool checkDoafter = false, + bool triggerHandContact = false) { - return TryUnequip(uid, uid, slot, out removedItem, silent, force, predicted, inventory, clothing, reparent, checkDoafter); + return TryUnequip(uid, uid, slot, out removedItem, silent, force, predicted, inventory, clothing, reparent, checkDoafter, triggerHandContact); } public bool TryUnequip( @@ -366,7 +373,8 @@ public abstract partial class InventorySystem InventoryComponent? inventory = null, ClothingComponent? clothing = null, bool reparent = true, - bool checkDoafter = false) + bool checkDoafter = false, + bool triggerHandContact = false) { var itemsDropped = 0; return TryUnequip(actor, target, slot, out removedItem, ref itemsDropped, @@ -385,7 +393,8 @@ public abstract partial class InventorySystem InventoryComponent? inventory = null, ClothingComponent? clothing = null, bool reparent = true, - bool checkDoafter = false) + bool checkDoafter = false, + bool triggerHandContact = false) { removedItem = null; @@ -476,6 +485,10 @@ public abstract partial class InventorySystem _audio.PlayPredicted(clothing.UnequipSound, target, actor); } + // If gloves are unequipped, OnContactInteraction should trigger for held items + if (triggerHandContact && !((slotDefinition.SlotFlags & SlotFlags.GLOVES) == 0)) + TriggerHandContactInteraction(target); + Dirty(target, inventory); _movementSpeed.RefreshMovementSpeedModifiers(target); @@ -551,4 +564,12 @@ public abstract partial class InventorySystem entityUid = container.ContainedEntity; return entityUid != null; } + + public void TriggerHandContactInteraction(EntityUid uid) + { + foreach (var item in _handsSystem.EnumerateHeld(uid)) + { + _interactionSystem.DoContactInteraction(uid, item); + } + } } diff --git a/Content.Shared/Strip/SharedStrippableSystem.cs b/Content.Shared/Strip/SharedStrippableSystem.cs index 3645b5a0b9..d851f46060 100644 --- a/Content.Shared/Strip/SharedStrippableSystem.cs +++ b/Content.Shared/Strip/SharedStrippableSystem.cs @@ -23,6 +23,8 @@ namespace Content.Shared.Strip; public abstract class SharedStrippableSystem : EntitySystem { + [Dependency] private readonly SharedInteractionSystem _interactionSystem = default!; + [Dependency] private readonly SharedUserInterfaceSystem _ui = default!; [Dependency] private readonly InventorySystem _inventorySystem = default!; @@ -244,7 +246,7 @@ public abstract class SharedStrippableSystem : EntitySystem if (!_handsSystem.TryDrop(user, handsComp: user.Comp)) return; - _inventorySystem.TryEquip(user, target, held, slot); + _inventorySystem.TryEquip(user, target, held, slot, triggerHandContact: true); _adminLogger.Add(LogType.Stripping, LogImpact.Medium, $"{ToPrettyString(user):actor} has placed the item {ToPrettyString(held):item} in {ToPrettyString(target):target}'s {slot} slot"); } @@ -306,6 +308,8 @@ public abstract class SharedStrippableSystem : EntitySystem var prefix = stealth ? "stealthily " : ""; _adminLogger.Add(LogType.Stripping, LogImpact.Low, $"{ToPrettyString(user):actor} is trying to {prefix}strip the item {ToPrettyString(item):item} from {ToPrettyString(target):target}'s {slot} slot"); + _interactionSystem.DoContactInteraction(user, item); + var doAfterArgs = new DoAfterArgs(EntityManager, user, time, new StrippableDoAfterEvent(false, true, slot), user, target, item) { Hidden = stealth, @@ -333,7 +337,7 @@ public abstract class SharedStrippableSystem : EntitySystem if (!CanStripRemoveInventory(user, target, item, slot)) return; - if (!_inventorySystem.TryUnequip(user, target, slot)) + if (!_inventorySystem.TryUnequip(user, target, slot, triggerHandContact: true)) return; RaiseLocalEvent(item, new DroppedEvent(user), true); // Gas tank internals etc. @@ -511,6 +515,8 @@ public abstract class SharedStrippableSystem : EntitySystem var prefix = stealth ? "stealthily " : ""; _adminLogger.Add(LogType.Stripping, LogImpact.Low, $"{ToPrettyString(user):actor} is trying to {prefix}strip the item {ToPrettyString(item):item} from {ToPrettyString(target):target}'s hands"); + _interactionSystem.DoContactInteraction(user, item); + var doAfterArgs = new DoAfterArgs(EntityManager, user, time, new StrippableDoAfterEvent(false, false, handName), user, target, item) { Hidden = stealth,