]> git.smokeofanarchy.ru Git - space-station-14.git/commitdiff
Add support clothing equip/unequip doafters (#24389)
authorNemanja <98561806+EmoGarbage404@users.noreply.github.com>
Sun, 28 Jan 2024 10:48:42 +0000 (05:48 -0500)
committerGitHub <noreply@github.com>
Sun, 28 Jan 2024 10:48:42 +0000 (21:48 +1100)
* add clothing equip/unequip doafters

* boowomp

Content.Shared/Clothing/Components/ClothingComponent.cs
Content.Shared/Clothing/EntitySystems/ClothingSystem.cs
Content.Shared/Interaction/SmartEquipSystem.cs
Content.Shared/Inventory/InventorySystem.Equip.cs

index 321b06114acabe81c475b4f5393003a02fcf51e8..0f4c7f68bfc9774c282d0b3746026130bf17e1da 100644 (file)
@@ -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;
+}
+
index da2a09313ab6571e4988eb0bcdf387dfb7031368..92e31cfd8ea949d189e295993b5e98881ac86a4f 100644 (file)
@@ -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)
index 17c8f2e511fdf63661e9ecc7eb53c1ca6ab74247..fb2bc3c46097ac535203eae1ff33076d7fc7717f 100644 (file)
@@ -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);
     }
 }
index 5e740ec2eaeb924bda22ee068b4adf2ed61d12f3..24006b0c9f9fc97b30dd573fc5a6a9690fdbf186 100644 (file)
@@ -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)