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.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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
Reference in New Issue
Block a user