]> git.smokeofanarchy.ru Git - space-station-14.git/commitdiff
Fix NPC door prying (#15605)
authormetalgearsloth <31366439+metalgearsloth@users.noreply.github.com>
Fri, 21 Apr 2023 05:05:29 +0000 (15:05 +1000)
committerGitHub <noreply@github.com>
Fri, 21 Apr 2023 05:05:29 +0000 (15:05 +1000)
Content.Server/Doors/Systems/DoorSystem.cs
Content.Server/NPC/Components/NPCSteeringComponent.cs
Content.Server/NPC/Systems/NPCSteeringSystem.Context.cs
Content.Server/NPC/Systems/NPCSteeringSystem.Obstacles.cs
Content.Server/NPC/Systems/NPCSteeringSystem.cs
Content.Shared/DoAfter/SharedDoAfterSystem.cs
Content.Shared/Tools/Systems/SharedToolSystem.cs

index d6ecd5d65be0d7b2a05e46b4336bb26cb792b599..e35ef5c9da48b2c3d7603301f72916ed5ff19991 100644 (file)
@@ -1,3 +1,4 @@
+using System.Diagnostics.CodeAnalysis;
 using Content.Server.Access;
 using Content.Server.Atmos.Components;
 using Content.Server.Atmos.EntitySystems;
@@ -127,7 +128,7 @@ public sealed class DoorSystem : SharedDoorSystem
 
         if (tool.Qualities.Contains(door.PryingQuality))
         {
-            args.Handled = TryPryDoor(uid, args.Used, args.User, door);
+            args.Handled = TryPryDoor(uid, args.Used, args.User, door, out _);
         }
     }
 
@@ -164,7 +165,7 @@ public sealed class DoorSystem : SharedDoorSystem
         {
             Text = Loc.GetString("door-pry"),
             Impact = LogImpact.Low,
-            Act = () => TryPryDoor(uid, args.User, args.User, component, true),
+            Act = () => TryPryDoor(uid, args.User, args.User, component, out _, force: true),
         });
     }
 
@@ -172,8 +173,10 @@ public sealed class DoorSystem : SharedDoorSystem
     /// <summary>
     ///     Pry open a door. This does not check if the user is holding the required tool.
     /// </summary>
-    public bool TryPryDoor(EntityUid target, EntityUid tool, EntityUid user, DoorComponent door, bool force = false)
+    public bool TryPryDoor(EntityUid target, EntityUid tool, EntityUid user, DoorComponent door, out DoAfterId? id, bool force = false)
     {
+        id = null;
+
         if (door.State == DoorState.Welded)
             return false;
 
@@ -191,7 +194,7 @@ public sealed class DoorSystem : SharedDoorSystem
         var modEv = new DoorGetPryTimeModifierEvent(user);
         RaiseLocalEvent(target, modEv, false);
 
-        _toolSystem.UseTool(tool, user, target, modEv.PryTimeModifier * door.PryTime, door.PryingQuality, new DoorPryDoAfterEvent());
+        _toolSystem.UseTool(tool, user, target, TimeSpan.FromSeconds(modEv.PryTimeModifier * door.PryTime), new[] {door.PryingQuality}, new DoorPryDoAfterEvent(), out id);
         return true; // we might not actually succeeded, but a do-after has started
     }
 
index 3e87ac9f209940f1e93e6d526d9a99f6f517defd..18a5a565275570bcf46254a3ee1aca58e519fbe2 100644 (file)
@@ -1,5 +1,6 @@
 using System.Threading;
 using Content.Server.NPC.Pathfinding;
+using Content.Shared.DoAfter;
 using Content.Shared.NPC;
 using Robust.Shared.Map;
 using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom;
@@ -96,6 +97,12 @@ public sealed class NPCSteeringComponent : Component
     [ViewVariables] public SteeringStatus Status = SteeringStatus.Moving;
 
     [ViewVariables(VVAccess.ReadWrite)] public PathFlags Flags = PathFlags.None;
+
+    /// <summary>
+    /// If the NPC is using a do_after to clear an obstacle.
+    /// </summary>
+    [DataField("doAfterId")]
+    public DoAfterId? DoAfterId = null;
 }
 
 public enum SteeringStatus : byte
index df7e13e65d5cad57a389aae6d0afc0724a26f5f0..e8ef3c0cb325fdb3d8f6a67e52c25711fa1a639d 100644 (file)
@@ -133,8 +133,10 @@ public sealed partial class NPCSteeringSystem
                 switch (status)
                 {
                     case SteeringObstacleStatus.Completed:
+                        steering.DoAfterId = null;
                         break;
                     case SteeringObstacleStatus.Failed:
+                        steering.DoAfterId = null;
                         // TODO: Blacklist the poly for next query
                         steering.Status = SteeringStatus.NoPath;
                         return false;
index 8fd83e5162332d22898dcd7c27c7c1a6f7a88669..0a49846bced1f9320d88a1f39a57a6a5219951bc 100644 (file)
@@ -2,6 +2,7 @@ using Content.Server.Destructible;
 using Content.Server.NPC.Components;
 using Content.Server.NPC.Pathfinding;
 using Content.Shared.CombatMode;
+using Content.Shared.DoAfter;
 using Content.Shared.Doors.Components;
 using Content.Shared.NPC;
 using Robust.Shared.Physics;
@@ -55,14 +56,27 @@ public sealed partial class NPCSteeringSystem
         if ((poly.Data.CollisionLayer & mask) != 0x0 ||
             (poly.Data.CollisionMask & layer) != 0x0)
         {
+            var id = component.DoAfterId;
+
+            // Still doing what we were doing before.
+            var doAfterStatus = _doAfter.GetStatus(id);
+
+            switch (doAfterStatus)
+            {
+                case DoAfterStatus.Running:
+                    return SteeringObstacleStatus.Continuing;
+                case DoAfterStatus.Cancelled:
+                    return SteeringObstacleStatus.Failed;
+            }
+
             var obstacleEnts = new List<EntityUid>();
 
             GetObstacleEntities(poly, mask, layer, bodyQuery, obstacleEnts);
             var isDoor = (poly.Data.Flags & PathfindingBreadcrumbFlag.Door) != 0x0;
-            var isAccess = (poly.Data.Flags & PathfindingBreadcrumbFlag.Access) != 0x0;
+            var isAccessRequired = (poly.Data.Flags & PathfindingBreadcrumbFlag.Access) != 0x0;
 
             // Just walk into it stupid
-            if (isDoor && !isAccess)
+            if (isDoor && !isAccessRequired)
             {
                 var doorQuery = GetEntityQuery<DoorComponent>();
 
@@ -80,16 +94,12 @@ public sealed partial class NPCSteeringSystem
                             return SteeringObstacleStatus.Continuing;
                         }
                     }
-                    else
-                    {
-                        return SteeringObstacleStatus.Failed;
-                    }
                 }
 
-                return SteeringObstacleStatus.Completed;
+                // If we get to here then didn't succeed for reasons.
             }
 
-            if ((component.Flags & PathFlags.Prying) != 0x0 && isAccess && isDoor)
+            if ((component.Flags & PathFlags.Prying) != 0x0 && isDoor)
             {
                 var doorQuery = GetEntityQuery<DoorComponent>();
 
@@ -101,8 +111,9 @@ public sealed partial class NPCSteeringSystem
                         // TODO: Use the verb.
 
                         if (door.State != DoorState.Opening)
-                            _doors.TryPryDoor(ent, uid, uid, door, true);
+                            _doors.TryPryDoor(ent, uid, uid, door, out id, force: true);
 
+                        component.DoAfterId = id;
                         return SteeringObstacleStatus.Continuing;
                     }
                 }
index 8df27d48e8f2802d6ea2d26c94d1f0fdc8ff32af..7ab92316480bf397c0a5672d7cfe0ce292199659 100644 (file)
@@ -2,6 +2,7 @@ using System.Linq;
 using System.Threading;
 using System.Threading.Tasks;
 using Content.Server.Administration.Managers;
+using Content.Server.DoAfter;
 using Content.Server.Doors.Systems;
 using Content.Server.NPC.Components;
 using Content.Server.NPC.Events;
@@ -47,6 +48,7 @@ namespace Content.Server.NPC.Systems
         [Dependency] private readonly IMapManager _mapManager = default!;
         [Dependency] private readonly IParallelManager _parallel = default!;
         [Dependency] private readonly IRobustRandom _random = default!;
+        [Dependency] private readonly DoAfterSystem _doAfter = default!;
         [Dependency] private readonly DoorSystem _doors = default!;
         [Dependency] private readonly EntityLookupSystem _lookup = default!;
         [Dependency] private readonly FactionSystem _faction = default!;
index 5ac861ab9a79a29f5b3b0d1bfec3468bca90490a..27011816cd513a794c233acabb2cf76264bfa1b1 100644 (file)
@@ -356,7 +356,7 @@ public abstract partial class SharedDoAfterSystem : EntitySystem
         if (doAfter.Cancelled)
             return DoAfterStatus.Cancelled;
 
-        if (GameTiming.CurTime - doAfter.StartTime < doAfter.Args.Delay)
+        if (!doAfter.Completed)
             return DoAfterStatus.Running;
 
         // Theres the chance here that the DoAfter hasn't actually finished yet if the system's update hasn't run yet.
index b480e98df4aa6d0e9e7d5d3ccf614499a8d6f602..8cd99f14aa0c76719f1d2ee606d8f3f1423407ea 100644 (file)
@@ -119,7 +119,7 @@ public abstract partial class SharedToolSystem : EntitySystem
             BreakOnDamage = true,
             BreakOnTargetMove = true,
             BreakOnUserMove = true,
-            NeedHand = true,
+            NeedHand = tool != user,
             AttemptFrequency = fuel <= 0 ? AttemptFrequency.Never : AttemptFrequency.EveryTick
         };