Add support clothing equip/unequip doafters (#24389)

* add clothing equip/unequip doafters

* boowomp
This commit is contained in:
Nemanja
2024-01-28 05:48:42 -05:00
committed by GitHub
parent 19a05e11d0
commit 804c76f8c9
4 changed files with 133 additions and 19 deletions

View File

@@ -1,4 +1,5 @@
using Content.Shared.Clothing.EntitySystems; using Content.Shared.Clothing.EntitySystems;
using Content.Shared.DoAfter;
using Content.Shared.Inventory; using Content.Shared.Inventory;
using Robust.Shared.Audio; using Robust.Shared.Audio;
using Robust.Shared.GameStates; using Robust.Shared.GameStates;
@@ -66,6 +67,12 @@ public sealed partial class ClothingComponent : Component
public ClothingMask UnisexMask = ClothingMask.UniformFull; public ClothingMask UnisexMask = ClothingMask.UniformFull;
public string? InSlot; public string? InSlot;
[DataField, ViewVariables(VVAccess.ReadWrite)]
public TimeSpan EquipDelay = TimeSpan.Zero;
[DataField, ViewVariables(VVAccess.ReadWrite)]
public TimeSpan UnequipDelay = TimeSpan.Zero;
} }
[Serializable, NetSerializable] [Serializable, NetSerializable]
@@ -85,3 +92,30 @@ public enum ClothingMask : byte
UniformFull, UniformFull,
UniformTop 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;
}

View File

@@ -7,7 +7,6 @@ using Content.Shared.Inventory;
using Content.Shared.Inventory.Events; using Content.Shared.Inventory.Events;
using Content.Shared.Item; using Content.Shared.Item;
using Content.Shared.Tag; using Content.Shared.Tag;
using Content.Shared.Timing;
using Robust.Shared.GameStates; using Robust.Shared.GameStates;
namespace Content.Shared.Clothing.EntitySystems; namespace Content.Shared.Clothing.EntitySystems;
@@ -33,7 +32,11 @@ public abstract class ClothingSystem : EntitySystem
SubscribeLocalEvent<ClothingComponent, GotEquippedEvent>(OnGotEquipped); SubscribeLocalEvent<ClothingComponent, GotEquippedEvent>(OnGotEquipped);
SubscribeLocalEvent<ClothingComponent, GotUnequippedEvent>(OnGotUnequipped); SubscribeLocalEvent<ClothingComponent, GotUnequippedEvent>(OnGotUnequipped);
SubscribeLocalEvent<ClothingComponent, ItemMaskToggledEvent>(OnMaskToggled); SubscribeLocalEvent<ClothingComponent, ItemMaskToggledEvent>(OnMaskToggled);
SubscribeLocalEvent<ClothingComponent, ClothingEquipDoAfterEvent>(OnEquipDoAfter);
SubscribeLocalEvent<ClothingComponent, ClothingUnequipDoAfterEvent>(OnUnequipDoAfter);
} }
private void OnUseInHand(Entity<ClothingComponent> ent, ref UseInHandEvent args) private void OnUseInHand(Entity<ClothingComponent> ent, ref UseInHandEvent args)
{ {
if (args.Handled || !ent.Comp.QuickEquip) if (args.Handled || !ent.Comp.QuickEquip)
@@ -64,17 +67,17 @@ public abstract class ClothingSystem : EntitySystem
if (TryComp(slotEntity, out ClothingComponent? item) && !item.QuickEquip) if (TryComp(slotEntity, out ClothingComponent? item) && !item.QuickEquip)
continue; continue;
if (!_invSystem.TryUnequip(userEnt, slotDef.Name, true, inventory: userEnt, clothing: toEquipEnt)) if (!_invSystem.TryUnequip(userEnt, slotDef.Name, true, inventory: userEnt, checkDoafter: true))
continue; 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; continue;
_handsSystem.PickupOrDrop(userEnt, slotEntity.Value, handsComp: userEnt); _handsSystem.PickupOrDrop(userEnt, slotEntity.Value, handsComp: userEnt);
} }
else 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; continue;
} }
@@ -113,6 +116,22 @@ public abstract class ClothingSystem : EntitySystem
SetEquippedPrefix(ent, args.IsToggled ? "toggled" : null, ent); 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 #region Public API
public void SetEquippedPrefix(EntityUid uid, string? prefix, ClothingComponent? clothing = null) public void SetEquippedPrefix(EntityUid uid, string? prefix, ClothingComponent? clothing = null)

View File

@@ -118,7 +118,7 @@ public sealed class SmartEquipSystem : EntitySystem
} }
_hands.TryDrop(uid, hands.ActiveHand, handsComp: hands); _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; return;
} }
@@ -209,7 +209,7 @@ public sealed class SmartEquipSystem : EntitySystem
return; 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); _hands.TryPickup(uid, slotItem, handsComp: hands);
} }
} }

View File

@@ -1,5 +1,6 @@
using System.Diagnostics.CodeAnalysis; using System.Diagnostics.CodeAnalysis;
using Content.Shared.Clothing.Components; using Content.Shared.Clothing.Components;
using Content.Shared.DoAfter;
using Content.Shared.Hands; using Content.Shared.Hands;
using Content.Shared.Hands.Components; using Content.Shared.Hands.Components;
using Content.Shared.Hands.EntitySystems; using Content.Shared.Hands.EntitySystems;
@@ -24,6 +25,7 @@ public abstract partial class InventorySystem
[Dependency] private readonly SharedItemSystem _item = default!; [Dependency] private readonly SharedItemSystem _item = default!;
[Dependency] private readonly SharedAudioSystem _audio = default!; [Dependency] private readonly SharedAudioSystem _audio = default!;
[Dependency] private readonly SharedContainerSystem _containerSystem = default!; [Dependency] private readonly SharedContainerSystem _containerSystem = default!;
[Dependency] private readonly SharedDoAfterSystem _doAfter = default!;
[Dependency] private readonly SharedHandsSystem _handsSystem = default!; [Dependency] private readonly SharedHandsSystem _handsSystem = default!;
[Dependency] private readonly IGameTiming _gameTiming = default!; [Dependency] private readonly IGameTiming _gameTiming = default!;
[Dependency] private readonly SharedTransformSystem _transform = default!; [Dependency] private readonly SharedTransformSystem _transform = default!;
@@ -90,7 +92,7 @@ public abstract partial class InventorySystem
// unequip the item. // unequip the item.
if (itemUid != null) 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; return;
_handsSystem.PickupOrDrop(actor, item.Value); _handsSystem.PickupOrDrop(actor, item.Value);
@@ -114,15 +116,15 @@ public abstract partial class InventorySystem
RaiseLocalEvent(held.Value, new HandDeselectedEvent(actor), false); 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, public bool TryEquip(EntityUid uid, 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) =>
TryEquip(uid, uid, itemUid, slot, silent, force, predicted, inventory, clothing); 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, 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)) if (!Resolve(target, ref inventory, false))
{ {
@@ -149,6 +151,34 @@ public abstract partial class InventorySystem
return 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 (!_containerSystem.Insert(itemUid, slotContainer))
{ {
if(!silent && _gameTiming.IsFirstTimePredicted) if(!silent && _gameTiming.IsFirstTimePredicted)
@@ -156,7 +186,7 @@ public abstract partial class InventorySystem
return false; return false;
} }
if (!silent && clothing != null && clothing.EquipSound != null) if (!silent && clothing != null)
{ {
_audio.PlayPredicted(clothing.EquipSound, target, actor); _audio.PlayPredicted(clothing.EquipSound, target, actor);
} }
@@ -284,9 +314,10 @@ public abstract partial class InventorySystem
bool predicted = false, bool predicted = false,
InventoryComponent? inventory = null, InventoryComponent? inventory = null,
ClothingComponent? clothing = 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( public bool TryUnequip(
@@ -298,9 +329,10 @@ public abstract partial class InventorySystem
bool predicted = false, bool predicted = false,
InventoryComponent? inventory = null, InventoryComponent? inventory = null,
ClothingComponent? clothing = 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( public bool TryUnequip(
@@ -312,9 +344,10 @@ public abstract partial class InventorySystem
bool predicted = false, bool predicted = false,
InventoryComponent? inventory = null, InventoryComponent? inventory = null,
ClothingComponent? clothing = 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( public bool TryUnequip(
@@ -327,7 +360,8 @@ public abstract partial class InventorySystem
bool predicted = false, bool predicted = false,
InventoryComponent? inventory = null, InventoryComponent? inventory = null,
ClothingComponent? clothing = null, ClothingComponent? clothing = null,
bool reparent = true) bool reparent = true,
bool checkDoafter = false)
{ {
removedItem = null; removedItem = null;
@@ -364,6 +398,33 @@ public abstract partial class InventorySystem
if (!force && !_containerSystem.CanRemove(removedItem.Value, slotContainer)) if (!force && !_containerSystem.CanRemove(removedItem.Value, slotContainer))
return false; 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) foreach (var slotDef in inventory.Slots)
{ {
if (slotDef != slotDefinition && slotDef.DependsOn == slotDefinition.Name) if (slotDef != slotDefinition && slotDef.DependsOn == slotDefinition.Name)