Add support clothing equip/unequip doafters (#24389)
* add clothing equip/unequip doafters * boowomp
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
using Content.Shared.Clothing.EntitySystems;
|
||||
using Content.Shared.DoAfter;
|
||||
using Content.Shared.Inventory;
|
||||
using Robust.Shared.Audio;
|
||||
using Robust.Shared.GameStates;
|
||||
@@ -66,6 +67,12 @@ public sealed partial class ClothingComponent : Component
|
||||
public ClothingMask UnisexMask = ClothingMask.UniformFull;
|
||||
|
||||
public string? InSlot;
|
||||
|
||||
[DataField, ViewVariables(VVAccess.ReadWrite)]
|
||||
public TimeSpan EquipDelay = TimeSpan.Zero;
|
||||
|
||||
[DataField, ViewVariables(VVAccess.ReadWrite)]
|
||||
public TimeSpan UnequipDelay = TimeSpan.Zero;
|
||||
}
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
@@ -85,3 +92,30 @@ public enum ClothingMask : byte
|
||||
UniformFull,
|
||||
UniformTop
|
||||
}
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public sealed partial class ClothingEquipDoAfterEvent : DoAfterEvent
|
||||
{
|
||||
public string Slot;
|
||||
|
||||
public ClothingEquipDoAfterEvent(string slot)
|
||||
{
|
||||
Slot = slot;
|
||||
}
|
||||
|
||||
public override DoAfterEvent Clone() => this;
|
||||
}
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public sealed partial class ClothingUnequipDoAfterEvent : DoAfterEvent
|
||||
{
|
||||
public string Slot;
|
||||
|
||||
public ClothingUnequipDoAfterEvent(string slot)
|
||||
{
|
||||
Slot = slot;
|
||||
}
|
||||
|
||||
public override DoAfterEvent Clone() => this;
|
||||
}
|
||||
|
||||
|
||||
@@ -7,7 +7,6 @@ using Content.Shared.Inventory;
|
||||
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;
|
||||
@@ -33,7 +32,11 @@ public abstract class ClothingSystem : EntitySystem
|
||||
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)
|
||||
@@ -64,17 +67,17 @@ public abstract class ClothingSystem : EntitySystem
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -113,6 +116,22 @@ public abstract class ClothingSystem : EntitySystem
|
||||
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)
|
||||
|
||||
@@ -118,7 +118,7 @@ public sealed class SmartEquipSystem : EntitySystem
|
||||
}
|
||||
|
||||
_hands.TryDrop(uid, hands.ActiveHand, handsComp: hands);
|
||||
_inventory.TryEquip(uid, handItem.Value, equipmentSlot, predicted: true);
|
||||
_inventory.TryEquip(uid, handItem.Value, equipmentSlot, predicted: true, checkDoafter:true);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -209,7 +209,7 @@ public sealed class SmartEquipSystem : EntitySystem
|
||||
return;
|
||||
}
|
||||
|
||||
_inventory.TryUnequip(uid, equipmentSlot, inventory: inventory, predicted: true);
|
||||
_inventory.TryUnequip(uid, equipmentSlot, inventory: inventory, predicted: true, checkDoafter: true);
|
||||
_hands.TryPickup(uid, slotItem, handsComp: hands);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
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;
|
||||
@@ -24,6 +25,7 @@ public abstract partial class InventorySystem
|
||||
[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!;
|
||||
@@ -90,7 +92,7 @@ public abstract partial class InventorySystem
|
||||
// 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);
|
||||
@@ -114,15 +116,15 @@ public abstract partial class InventorySystem
|
||||
|
||||
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))
|
||||
{
|
||||
@@ -149,6 +151,34 @@ public abstract partial class InventorySystem
|
||||
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)
|
||||
@@ -156,7 +186,7 @@ public abstract partial class InventorySystem
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!silent && clothing != null && clothing.EquipSound != null)
|
||||
if (!silent && clothing != null)
|
||||
{
|
||||
_audio.PlayPredicted(clothing.EquipSound, target, actor);
|
||||
}
|
||||
@@ -284,9 +314,10 @@ public abstract partial class InventorySystem
|
||||
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(
|
||||
@@ -298,9 +329,10 @@ public abstract partial class InventorySystem
|
||||
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(
|
||||
@@ -312,9 +344,10 @@ public abstract partial class InventorySystem
|
||||
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(
|
||||
@@ -327,7 +360,8 @@ public abstract partial class InventorySystem
|
||||
bool predicted = false,
|
||||
InventoryComponent? inventory = null,
|
||||
ClothingComponent? clothing = null,
|
||||
bool reparent = true)
|
||||
bool reparent = true,
|
||||
bool checkDoafter = false)
|
||||
{
|
||||
removedItem = null;
|
||||
|
||||
@@ -364,6 +398,33 @@ public abstract partial class InventorySystem
|
||||
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)
|
||||
|
||||
Reference in New Issue
Block a user