Fix NPC door prying (#15605)
This commit is contained in:
@@ -1,3 +1,4 @@
|
|||||||
|
using System.Diagnostics.CodeAnalysis;
|
||||||
using Content.Server.Access;
|
using Content.Server.Access;
|
||||||
using Content.Server.Atmos.Components;
|
using Content.Server.Atmos.Components;
|
||||||
using Content.Server.Atmos.EntitySystems;
|
using Content.Server.Atmos.EntitySystems;
|
||||||
@@ -127,7 +128,7 @@ public sealed class DoorSystem : SharedDoorSystem
|
|||||||
|
|
||||||
if (tool.Qualities.Contains(door.PryingQuality))
|
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"),
|
Text = Loc.GetString("door-pry"),
|
||||||
Impact = LogImpact.Low,
|
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>
|
/// <summary>
|
||||||
/// Pry open a door. This does not check if the user is holding the required tool.
|
/// Pry open a door. This does not check if the user is holding the required tool.
|
||||||
/// </summary>
|
/// </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)
|
if (door.State == DoorState.Welded)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
@@ -191,7 +194,7 @@ public sealed class DoorSystem : SharedDoorSystem
|
|||||||
var modEv = new DoorGetPryTimeModifierEvent(user);
|
var modEv = new DoorGetPryTimeModifierEvent(user);
|
||||||
RaiseLocalEvent(target, modEv, false);
|
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
|
return true; // we might not actually succeeded, but a do-after has started
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
using System.Threading;
|
using System.Threading;
|
||||||
using Content.Server.NPC.Pathfinding;
|
using Content.Server.NPC.Pathfinding;
|
||||||
|
using Content.Shared.DoAfter;
|
||||||
using Content.Shared.NPC;
|
using Content.Shared.NPC;
|
||||||
using Robust.Shared.Map;
|
using Robust.Shared.Map;
|
||||||
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom;
|
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom;
|
||||||
@@ -96,6 +97,12 @@ public sealed class NPCSteeringComponent : Component
|
|||||||
[ViewVariables] public SteeringStatus Status = SteeringStatus.Moving;
|
[ViewVariables] public SteeringStatus Status = SteeringStatus.Moving;
|
||||||
|
|
||||||
[ViewVariables(VVAccess.ReadWrite)] public PathFlags Flags = PathFlags.None;
|
[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
|
public enum SteeringStatus : byte
|
||||||
|
|||||||
@@ -133,8 +133,10 @@ public sealed partial class NPCSteeringSystem
|
|||||||
switch (status)
|
switch (status)
|
||||||
{
|
{
|
||||||
case SteeringObstacleStatus.Completed:
|
case SteeringObstacleStatus.Completed:
|
||||||
|
steering.DoAfterId = null;
|
||||||
break;
|
break;
|
||||||
case SteeringObstacleStatus.Failed:
|
case SteeringObstacleStatus.Failed:
|
||||||
|
steering.DoAfterId = null;
|
||||||
// TODO: Blacklist the poly for next query
|
// TODO: Blacklist the poly for next query
|
||||||
steering.Status = SteeringStatus.NoPath;
|
steering.Status = SteeringStatus.NoPath;
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ using Content.Server.Destructible;
|
|||||||
using Content.Server.NPC.Components;
|
using Content.Server.NPC.Components;
|
||||||
using Content.Server.NPC.Pathfinding;
|
using Content.Server.NPC.Pathfinding;
|
||||||
using Content.Shared.CombatMode;
|
using Content.Shared.CombatMode;
|
||||||
|
using Content.Shared.DoAfter;
|
||||||
using Content.Shared.Doors.Components;
|
using Content.Shared.Doors.Components;
|
||||||
using Content.Shared.NPC;
|
using Content.Shared.NPC;
|
||||||
using Robust.Shared.Physics;
|
using Robust.Shared.Physics;
|
||||||
@@ -55,14 +56,27 @@ public sealed partial class NPCSteeringSystem
|
|||||||
if ((poly.Data.CollisionLayer & mask) != 0x0 ||
|
if ((poly.Data.CollisionLayer & mask) != 0x0 ||
|
||||||
(poly.Data.CollisionMask & layer) != 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>();
|
var obstacleEnts = new List<EntityUid>();
|
||||||
|
|
||||||
GetObstacleEntities(poly, mask, layer, bodyQuery, obstacleEnts);
|
GetObstacleEntities(poly, mask, layer, bodyQuery, obstacleEnts);
|
||||||
var isDoor = (poly.Data.Flags & PathfindingBreadcrumbFlag.Door) != 0x0;
|
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
|
// Just walk into it stupid
|
||||||
if (isDoor && !isAccess)
|
if (isDoor && !isAccessRequired)
|
||||||
{
|
{
|
||||||
var doorQuery = GetEntityQuery<DoorComponent>();
|
var doorQuery = GetEntityQuery<DoorComponent>();
|
||||||
|
|
||||||
@@ -80,16 +94,12 @@ public sealed partial class NPCSteeringSystem
|
|||||||
return SteeringObstacleStatus.Continuing;
|
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>();
|
var doorQuery = GetEntityQuery<DoorComponent>();
|
||||||
|
|
||||||
@@ -101,8 +111,9 @@ public sealed partial class NPCSteeringSystem
|
|||||||
// TODO: Use the verb.
|
// TODO: Use the verb.
|
||||||
|
|
||||||
if (door.State != DoorState.Opening)
|
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;
|
return SteeringObstacleStatus.Continuing;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ using System.Linq;
|
|||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Content.Server.Administration.Managers;
|
using Content.Server.Administration.Managers;
|
||||||
|
using Content.Server.DoAfter;
|
||||||
using Content.Server.Doors.Systems;
|
using Content.Server.Doors.Systems;
|
||||||
using Content.Server.NPC.Components;
|
using Content.Server.NPC.Components;
|
||||||
using Content.Server.NPC.Events;
|
using Content.Server.NPC.Events;
|
||||||
@@ -47,6 +48,7 @@ namespace Content.Server.NPC.Systems
|
|||||||
[Dependency] private readonly IMapManager _mapManager = default!;
|
[Dependency] private readonly IMapManager _mapManager = default!;
|
||||||
[Dependency] private readonly IParallelManager _parallel = default!;
|
[Dependency] private readonly IParallelManager _parallel = default!;
|
||||||
[Dependency] private readonly IRobustRandom _random = default!;
|
[Dependency] private readonly IRobustRandom _random = default!;
|
||||||
|
[Dependency] private readonly DoAfterSystem _doAfter = default!;
|
||||||
[Dependency] private readonly DoorSystem _doors = default!;
|
[Dependency] private readonly DoorSystem _doors = default!;
|
||||||
[Dependency] private readonly EntityLookupSystem _lookup = default!;
|
[Dependency] private readonly EntityLookupSystem _lookup = default!;
|
||||||
[Dependency] private readonly FactionSystem _faction = default!;
|
[Dependency] private readonly FactionSystem _faction = default!;
|
||||||
|
|||||||
@@ -356,7 +356,7 @@ public abstract partial class SharedDoAfterSystem : EntitySystem
|
|||||||
if (doAfter.Cancelled)
|
if (doAfter.Cancelled)
|
||||||
return DoAfterStatus.Cancelled;
|
return DoAfterStatus.Cancelled;
|
||||||
|
|
||||||
if (GameTiming.CurTime - doAfter.StartTime < doAfter.Args.Delay)
|
if (!doAfter.Completed)
|
||||||
return DoAfterStatus.Running;
|
return DoAfterStatus.Running;
|
||||||
|
|
||||||
// Theres the chance here that the DoAfter hasn't actually finished yet if the system's update hasn't run yet.
|
// Theres the chance here that the DoAfter hasn't actually finished yet if the system's update hasn't run yet.
|
||||||
|
|||||||
@@ -119,7 +119,7 @@ public abstract partial class SharedToolSystem : EntitySystem
|
|||||||
BreakOnDamage = true,
|
BreakOnDamage = true,
|
||||||
BreakOnTargetMove = true,
|
BreakOnTargetMove = true,
|
||||||
BreakOnUserMove = true,
|
BreakOnUserMove = true,
|
||||||
NeedHand = true,
|
NeedHand = tool != user,
|
||||||
AttemptFrequency = fuel <= 0 ? AttemptFrequency.Never : AttemptFrequency.EveryTick
|
AttemptFrequency = fuel <= 0 ? AttemptFrequency.Never : AttemptFrequency.EveryTick
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user