using Content.Shared.Inventory.Events;
using Content.Shared.Item;
using Content.Shared.Tag;
-using Content.Shared.Timing;
using Robust.Shared.GameStates;
namespace Content.Shared.Clothing.EntitySystems;
SubscribeLocalEvent<ClothingComponent, GotEquippedEvent>(OnGotEquipped);
SubscribeLocalEvent<ClothingComponent, GotUnequippedEvent>(OnGotUnequipped);
SubscribeLocalEvent<ClothingComponent, ItemMaskToggledEvent>(OnMaskToggled);
+
+ SubscribeLocalEvent<ClothingComponent, ClothingEquipDoAfterEvent>(OnEquipDoAfter);
+ SubscribeLocalEvent<ClothingComponent, ClothingUnequipDoAfterEvent>(OnUnequipDoAfter);
}
+
private void OnUseInHand(Entity<ClothingComponent> ent, ref UseInHandEvent args)
{
if (args.Handled || !ent.Comp.QuickEquip)
if (TryComp(slotEntity, out ClothingComponent? item) && !item.QuickEquip)
continue;
- if (!_invSystem.TryUnequip(userEnt, slotDef.Name, true, inventory: userEnt, clothing: toEquipEnt))
+ if (!_invSystem.TryUnequip(userEnt, slotDef.Name, true, inventory: userEnt, checkDoafter: true))
continue;
- if (!_invSystem.TryEquip(userEnt, toEquipEnt, slotDef.Name, true, inventory: userEnt, clothing: toEquipEnt))
+ if (!_invSystem.TryEquip(userEnt, toEquipEnt, slotDef.Name, true, inventory: userEnt, clothing: toEquipEnt, checkDoafter: true))
continue;
_handsSystem.PickupOrDrop(userEnt, slotEntity.Value, handsComp: userEnt);
}
else
{
- if (!_invSystem.TryEquip(userEnt, toEquipEnt, slotDef.Name, true, inventory: userEnt, clothing: toEquipEnt))
+ if (!_invSystem.TryEquip(userEnt, toEquipEnt, slotDef.Name, true, inventory: userEnt, clothing: toEquipEnt, checkDoafter: true))
continue;
}
SetEquippedPrefix(ent, args.IsToggled ? "toggled" : null, ent);
}
+ private void OnEquipDoAfter(Entity<ClothingComponent> ent, ref ClothingEquipDoAfterEvent args)
+ {
+ if (args.Handled || args.Cancelled || args.Target is not { } target)
+ return;
+ args.Handled = _invSystem.TryEquip(args.User, target, ent, args.Slot, clothing: ent.Comp, predicted: true, checkDoafter: false);
+ }
+
+ private void OnUnequipDoAfter(Entity<ClothingComponent> ent, ref ClothingUnequipDoAfterEvent args)
+ {
+ 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);
+ if (args.Handled)
+ _handsSystem.TryPickup(args.User, ent);
+ }
+
#region Public API
public void SetEquippedPrefix(EntityUid uid, string? prefix, ClothingComponent? clothing = null)
using System.Diagnostics.CodeAnalysis;
using Content.Shared.Clothing.Components;
+using Content.Shared.DoAfter;
using Content.Shared.Hands;
using Content.Shared.Hands.Components;
using Content.Shared.Hands.EntitySystems;
[Dependency] private readonly SharedItemSystem _item = default!;
[Dependency] private readonly SharedAudioSystem _audio = default!;
[Dependency] private readonly SharedContainerSystem _containerSystem = default!;
+ [Dependency] private readonly SharedDoAfterSystem _doAfter = default!;
[Dependency] private readonly SharedHandsSystem _handsSystem = default!;
[Dependency] private readonly IGameTiming _gameTiming = default!;
[Dependency] private readonly SharedTransformSystem _transform = default!;
// unequip the item.
if (itemUid != null)
{
- if (!TryUnequip(actor, ev.Slot, out var item, predicted: true, inventory: inventory))
+ if (!TryUnequip(actor, ev.Slot, out var item, predicted: true, inventory: inventory, checkDoafter: true))
return;
_handsSystem.PickupOrDrop(actor, item.Value);
RaiseLocalEvent(held.Value, new HandDeselectedEvent(actor), false);
- TryEquip(actor, actor, held.Value, ev.Slot, predicted: true, inventory: inventory, force: true);
+ TryEquip(actor, actor, held.Value, ev.Slot, predicted: true, inventory: inventory, force: true, checkDoafter: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) =>
- TryEquip(uid, uid, itemUid, slot, silent, force, predicted, inventory, clothing);
+ InventoryComponent? inventory = null, ClothingComponent? clothing = null, bool checkDoafter = false) =>
+ TryEquip(uid, uid, itemUid, slot, silent, force, predicted, inventory, clothing, checkDoafter);
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)
+ InventoryComponent? inventory = null, ClothingComponent? clothing = null, bool checkDoafter = false)
{
if (!Resolve(target, ref inventory, false))
{
return false;
}
+ if (checkDoafter &&
+ clothing != null &&
+ clothing.EquipDelay > TimeSpan.Zero &&
+ (clothing.Slots & slotDefinition.SlotFlags) != 0 &&
+ _containerSystem.CanInsert(itemUid, slotContainer))
+ {
+ var args = new DoAfterArgs(
+ EntityManager,
+ actor,
+ clothing.EquipDelay,
+ new ClothingEquipDoAfterEvent(slot),
+ itemUid,
+ target,
+ itemUid)
+ {
+ BlockDuplicate = true,
+ BreakOnHandChange = true,
+ BreakOnUserMove = true,
+ BreakOnTargetMove = true,
+ CancelDuplicate = true,
+ RequireCanInteract = true,
+ NeedHand = true
+ };
+
+ _doAfter.TryStartDoAfter(args);
+ return false;
+ }
+
if (!_containerSystem.Insert(itemUid, slotContainer))
{
if(!silent && _gameTiming.IsFirstTimePredicted)
return false;
}
- if (!silent && clothing != null && clothing.EquipSound != null)
+ if (!silent && clothing != null)
{
_audio.PlayPredicted(clothing.EquipSound, target, actor);
}
bool predicted = false,
InventoryComponent? inventory = null,
ClothingComponent? clothing = null,
- bool reparent = true)
+ bool reparent = true,
+ bool checkDoafter = false)
{
- return TryUnequip(uid, uid, slot, silent, force, predicted, inventory, clothing, reparent);
+ return TryUnequip(uid, uid, slot, silent, force, predicted, inventory, clothing, reparent, checkDoafter);
}
public bool TryUnequip(
bool predicted = false,
InventoryComponent? inventory = null,
ClothingComponent? clothing = null,
- bool reparent = true)
+ bool reparent = true,
+ bool checkDoafter = false)
{
- return TryUnequip(actor, target, slot, out _, silent, force, predicted, inventory, clothing, reparent);
+ return TryUnequip(actor, target, slot, out _, silent, force, predicted, inventory, clothing, reparent, checkDoafter);
}
public bool TryUnequip(
bool predicted = false,
InventoryComponent? inventory = null,
ClothingComponent? clothing = null,
- bool reparent = true)
+ bool reparent = true,
+ bool checkDoafter = false)
{
- return TryUnequip(uid, uid, slot, out removedItem, silent, force, predicted, inventory, clothing, reparent);
+ return TryUnequip(uid, uid, slot, out removedItem, silent, force, predicted, inventory, clothing, reparent, checkDoafter);
}
public bool TryUnequip(
bool predicted = false,
InventoryComponent? inventory = null,
ClothingComponent? clothing = null,
- bool reparent = true)
+ bool reparent = true,
+ bool checkDoafter = false)
{
removedItem = null;
if (!force && !_containerSystem.CanRemove(removedItem.Value, slotContainer))
return false;
+ if (checkDoafter &&
+ Resolve(removedItem.Value, ref clothing, false) &&
+ (clothing.Slots & slotDefinition.SlotFlags) != 0 &&
+ clothing.UnequipDelay > TimeSpan.Zero)
+ {
+ var args = new DoAfterArgs(
+ EntityManager,
+ actor,
+ clothing.UnequipDelay,
+ new ClothingUnequipDoAfterEvent(slot),
+ removedItem.Value,
+ target,
+ removedItem.Value)
+ {
+ BlockDuplicate = true,
+ BreakOnHandChange = true,
+ BreakOnUserMove = true,
+ BreakOnTargetMove = true,
+ CancelDuplicate = true,
+ RequireCanInteract = true,
+ NeedHand = true
+ };
+
+ _doAfter.TryStartDoAfter(args);
+ return false;
+ }
+
foreach (var slotDef in inventory.Slots)
{
if (slotDef != slotDefinition && slotDef.DependsOn == slotDefinition.Name)