From fa59983bd933307a20244213081d882f948175d6 Mon Sep 17 00:00:00 2001
From: metalgearsloth <31366439+metalgearsloth@users.noreply.github.com>
Date: Thu, 13 Oct 2022 21:36:29 +1100
Subject: [PATCH] Bandaid medibots (#11718)
---
.../Operators/MoveToOperator.cs | 2 +-
.../PickAccessibleComponentOperator.cs | 2 +-
.../Operators/PickAccessibleOperator.cs | 2 +-
.../Specific/MedibotInjectOperator.cs | 13 +++++-----
.../Specific/PickNearbyInjectableOperator.cs | 12 +++++++++-
Content.Server/NPC/NPCBlackboard.cs | 11 +++++++++
Content.Server/NPC/Pathfinding/PathFlags.cs | 5 ++++
.../Pathfinding/PathfindingSystem.Common.cs | 2 +-
.../NPC/Pathfinding/PathfindingSystem.cs | 24 +++++++++++++++++--
.../Systems/NPCSteeringSystem.Obstacles.cs | 6 ++++-
.../Prototypes/Entities/Mobs/NPCs/xeno.yml | 2 ++
11 files changed, 67 insertions(+), 14 deletions(-)
diff --git a/Content.Server/NPC/HTN/PrimitiveTasks/Operators/MoveToOperator.cs b/Content.Server/NPC/HTN/PrimitiveTasks/Operators/MoveToOperator.cs
index 979c40fe31..58fc578845 100644
--- a/Content.Server/NPC/HTN/PrimitiveTasks/Operators/MoveToOperator.cs
+++ b/Content.Server/NPC/HTN/PrimitiveTasks/Operators/MoveToOperator.cs
@@ -42,7 +42,7 @@ public sealed class MoveToOperator : HTNOperator
/// Where the pathfinding result will be stored (if applicable). This gets removed after execution.
///
[ViewVariables, DataField("pathfindKey")]
- public string PathfindKey = "MovementPathfind";
+ public string PathfindKey = NPCBlackboard.PathfindKey;
///
/// How close we need to get before considering movement finished.
diff --git a/Content.Server/NPC/HTN/PrimitiveTasks/Operators/PickAccessibleComponentOperator.cs b/Content.Server/NPC/HTN/PrimitiveTasks/Operators/PickAccessibleComponentOperator.cs
index 5640d39eff..9d84be5f89 100644
--- a/Content.Server/NPC/HTN/PrimitiveTasks/Operators/PickAccessibleComponentOperator.cs
+++ b/Content.Server/NPC/HTN/PrimitiveTasks/Operators/PickAccessibleComponentOperator.cs
@@ -30,7 +30,7 @@ public sealed class PickAccessibleComponentOperator : HTNOperator
/// Where the pathfinding result will be stored (if applicable). This gets removed after execution.
///
[ViewVariables, DataField("pathfindKey")]
- public string PathfindKey = "MovementPathfind";
+ public string PathfindKey = NPCBlackboard.PathfindKey;
public override void Initialize(IEntitySystemManager sysManager)
{
diff --git a/Content.Server/NPC/HTN/PrimitiveTasks/Operators/PickAccessibleOperator.cs b/Content.Server/NPC/HTN/PrimitiveTasks/Operators/PickAccessibleOperator.cs
index f0e1f7869d..441b34dbb0 100644
--- a/Content.Server/NPC/HTN/PrimitiveTasks/Operators/PickAccessibleOperator.cs
+++ b/Content.Server/NPC/HTN/PrimitiveTasks/Operators/PickAccessibleOperator.cs
@@ -23,7 +23,7 @@ public sealed class PickAccessibleOperator : HTNOperator
/// Where the pathfinding result will be stored (if applicable). This gets removed after execution.
///
[ViewVariables, DataField("pathfindKey")]
- public string PathfindKey = "MovementPathfind";
+ public string PathfindKey = NPCBlackboard.PathfindKey;
public override void Initialize(IEntitySystemManager sysManager)
{
diff --git a/Content.Server/NPC/HTN/PrimitiveTasks/Operators/Specific/MedibotInjectOperator.cs b/Content.Server/NPC/HTN/PrimitiveTasks/Operators/Specific/MedibotInjectOperator.cs
index 326fd20131..7a584524e6 100644
--- a/Content.Server/NPC/HTN/PrimitiveTasks/Operators/Specific/MedibotInjectOperator.cs
+++ b/Content.Server/NPC/HTN/PrimitiveTasks/Operators/Specific/MedibotInjectOperator.cs
@@ -50,6 +50,9 @@ public sealed class MedibotInjectOperator : HTNOperator
if (!_entManager.TryGetComponent(owner, out var botComp))
return HTNOperatorStatus.Failed;
+ // To avoid spam, the rest of this needs fixing.
+ _entManager.EnsureComponent(target);
+
if (!_entManager.TryGetComponent(target, out var damage))
return HTNOperatorStatus.Failed;
@@ -62,20 +65,18 @@ public sealed class MedibotInjectOperator : HTNOperator
if (damage.TotalDamage == 0)
return HTNOperatorStatus.Failed;
- if (damage.TotalDamage <= MedibotComponent.StandardMedDamageThreshold)
+ if (damage.TotalDamage >= MedibotComponent.EmergencyMedDamageThreshold)
{
- _solutionSystem.TryAddReagent(target, injectable, botComp.StandardMed, botComp.StandardMedInjectAmount, out var accepted);
- _entManager.EnsureComponent(target);
+ _solutionSystem.TryAddReagent(target, injectable, botComp.EmergencyMed, botComp.EmergencyMedInjectAmount, out var accepted);
_popupSystem.PopupEntity(Loc.GetString("hypospray-component-feel-prick-message"), target, Filter.Entities(target));
SoundSystem.Play("/Audio/Items/hypospray.ogg", Filter.Pvs(target), target);
_chat.TrySendInGameICMessage(owner, Loc.GetString("medibot-finish-inject"), InGameICChatType.Speak, false);
return HTNOperatorStatus.Finished;
}
- if (damage.TotalDamage >= MedibotComponent.EmergencyMedDamageThreshold)
+ if (damage.TotalDamage >= MedibotComponent.StandardMedDamageThreshold)
{
- _solutionSystem.TryAddReagent(target, injectable, botComp.EmergencyMed, botComp.EmergencyMedInjectAmount, out var accepted);
- _entManager.EnsureComponent(target);
+ _solutionSystem.TryAddReagent(target, injectable, botComp.StandardMed, botComp.StandardMedInjectAmount, out var accepted);
_popupSystem.PopupEntity(Loc.GetString("hypospray-component-feel-prick-message"), target, Filter.Entities(target));
SoundSystem.Play("/Audio/Items/hypospray.ogg", Filter.Pvs(target), target);
_chat.TrySendInGameICMessage(owner, Loc.GetString("medibot-finish-inject"), InGameICChatType.Speak, false);
diff --git a/Content.Server/NPC/HTN/PrimitiveTasks/Operators/Specific/PickNearbyInjectableOperator.cs b/Content.Server/NPC/HTN/PrimitiveTasks/Operators/Specific/PickNearbyInjectableOperator.cs
index f7e9621118..5ebc4ca72d 100644
--- a/Content.Server/NPC/HTN/PrimitiveTasks/Operators/Specific/PickNearbyInjectableOperator.cs
+++ b/Content.Server/NPC/HTN/PrimitiveTasks/Operators/Specific/PickNearbyInjectableOperator.cs
@@ -2,7 +2,9 @@ using System.Threading;
using System.Threading.Tasks;
using Content.Server.Chemistry.Components.SolutionManager;
using Content.Server.NPC.Components;
+using Content.Server.NPC.Pathfinding;
using Content.Shared.Damage;
+using Content.Shared.Interaction;
using Content.Shared.MobState.Components;
namespace Content.Server.NPC.HTN.PrimitiveTasks.Operators.Specific;
@@ -11,6 +13,7 @@ public sealed class PickNearbyInjectableOperator : HTNOperator
{
[Dependency] private readonly IEntityManager _entManager = default!;
private EntityLookupSystem _lookup = default!;
+ private PathfindingSystem _pathfinding = default!;
[ViewVariables, DataField("rangeKey")] public string RangeKey = NPCBlackboard.MedibotInjectRange;
@@ -30,6 +33,7 @@ public sealed class PickNearbyInjectableOperator : HTNOperator
{
base.Initialize(sysManager);
_lookup = sysManager.GetEntitySystem();
+ _pathfinding = sysManager.GetEntitySystem();
}
public override async Task<(bool Valid, Dictionary? Effects)> Plan(NPCBlackboard blackboard,
@@ -53,10 +57,16 @@ public sealed class PickNearbyInjectableOperator : HTNOperator
damage.TotalDamage > 0 &&
!recentlyInjected.HasComponent(entity))
{
+ var path = await _pathfinding.GetPath(owner, entity, SharedInteractionSystem.InteractionRange, cancelToken);
+
+ if (path.Result == PathResult.NoPath)
+ continue;
+
return (true, new Dictionary()
{
{TargetKey, entity},
- {TargetMoveKey, _entManager.GetComponent(entity).Coordinates}
+ {TargetMoveKey, _entManager.GetComponent(entity).Coordinates},
+ {NPCBlackboard.PathfindKey, path},
});
}
}
diff --git a/Content.Server/NPC/NPCBlackboard.cs b/Content.Server/NPC/NPCBlackboard.cs
index 9cc6bee96d..4f3c97dd2b 100644
--- a/Content.Server/NPC/NPCBlackboard.cs
+++ b/Content.Server/NPC/NPCBlackboard.cs
@@ -196,6 +196,11 @@ public sealed class NPCBlackboard : IEnumerable>
public const string OwnerCoordinates = "OwnerCoordinates";
public const string MovementTarget = "MovementTarget";
+ ///
+ /// Can the NPC click open entities such as doors.
+ ///
+ public const string NavInteract = "NavInteract";
+
///
/// Can the NPC pry open doors for steering.
///
@@ -205,6 +210,12 @@ public sealed class NPCBlackboard : IEnumerable>
/// Can the NPC smash obstacles for steering.
///
public const string NavSmash = "NavSmash";
+
+ ///
+ /// Default key storage for a movement pathfind.
+ ///
+ public const string PathfindKey = "MovementPathfind";
+
public const string RotateSpeed = "RotateSpeed";
public const string VisionRadius = "VisionRadius";
public const float MeleeRange = 1f;
diff --git a/Content.Server/NPC/Pathfinding/PathFlags.cs b/Content.Server/NPC/Pathfinding/PathFlags.cs
index a30592ae21..1b60e187b8 100644
--- a/Content.Server/NPC/Pathfinding/PathFlags.cs
+++ b/Content.Server/NPC/Pathfinding/PathFlags.cs
@@ -19,4 +19,9 @@ public enum PathFlags : byte
/// Can stuff like walls be broken.
///
Smashing = 1 << 2,
+
+ ///
+ /// Can we open stuff that requires interaction (e.g. click-open doors).
+ ///
+ Interact = 1 << 3,
}
diff --git a/Content.Server/NPC/Pathfinding/PathfindingSystem.Common.cs b/Content.Server/NPC/Pathfinding/PathfindingSystem.Common.cs
index 1be578d385..918276a3b8 100644
--- a/Content.Server/NPC/Pathfinding/PathfindingSystem.Common.cs
+++ b/Content.Server/NPC/Pathfinding/PathfindingSystem.Common.cs
@@ -58,7 +58,7 @@ public sealed partial class PathfindingSystem
// TODO: Handling power + door prying
// Door we should be able to open
- if (isDoor && !isAccess)
+ if (isDoor && !isAccess && (request.Flags & PathFlags.Interact) != 0x0)
{
modifier += 0.5f;
}
diff --git a/Content.Server/NPC/Pathfinding/PathfindingSystem.cs b/Content.Server/NPC/Pathfinding/PathfindingSystem.cs
index 0253bfdae9..1392da58b8 100644
--- a/Content.Server/NPC/Pathfinding/PathfindingSystem.cs
+++ b/Content.Server/NPC/Pathfinding/PathfindingSystem.cs
@@ -280,6 +280,21 @@ namespace Content.Server.NPC.Pathfinding
return distance;
}
+ public async Task GetPath(
+ EntityUid entity,
+ EntityUid target,
+ float range,
+ CancellationToken cancelToken,
+ PathFlags flags = PathFlags.None)
+ {
+ if (!TryComp(entity, out var xform) ||
+ !TryComp(target, out var targetXform))
+ return new PathResultEvent(PathResult.NoPath, new Queue());
+
+ var request = GetRequest(entity, xform.Coordinates, targetXform.Coordinates, range, cancelToken, flags);
+ return await GetPath(request);
+ }
+
public async Task GetPath(
EntityUid entity,
EntityCoordinates start,
@@ -385,16 +400,21 @@ namespace Content.Server.NPC.Pathfinding
{
var flags = PathFlags.None;
- if (blackboard.TryGetValue(NPCBlackboard.NavPry, out var pry))
+ if (blackboard.TryGetValue(NPCBlackboard.NavPry, out var pry) && pry)
{
flags |= PathFlags.Prying;
}
- if (blackboard.TryGetValue(NPCBlackboard.NavSmash, out var smash))
+ if (blackboard.TryGetValue(NPCBlackboard.NavSmash, out var smash) && smash)
{
flags |= PathFlags.Smashing;
}
+ if (blackboard.TryGetValue(NPCBlackboard.NavInteract, out var interact) && interact)
+ {
+ flags |= PathFlags.Interact;
+ }
+
return flags;
}
diff --git a/Content.Server/NPC/Systems/NPCSteeringSystem.Obstacles.cs b/Content.Server/NPC/Systems/NPCSteeringSystem.Obstacles.cs
index 86c8335527..dafa524cf8 100644
--- a/Content.Server/NPC/Systems/NPCSteeringSystem.Obstacles.cs
+++ b/Content.Server/NPC/Systems/NPCSteeringSystem.Obstacles.cs
@@ -63,7 +63,7 @@ public sealed partial class NPCSteeringSystem
if (!doorQuery.TryGetComponent(ent, out var door))
continue;
- if (!door.BumpOpen)
+ if (!door.BumpOpen && (component.Flags & PathFlags.Interact) != 0x0)
{
if (door.State != DoorState.Opening)
{
@@ -71,6 +71,10 @@ public sealed partial class NPCSteeringSystem
return SteeringObstacleStatus.Continuing;
}
}
+ else
+ {
+ return SteeringObstacleStatus.Failed;
+ }
}
return SteeringObstacleStatus.Completed;
diff --git a/Resources/Prototypes/Entities/Mobs/NPCs/xeno.yml b/Resources/Prototypes/Entities/Mobs/NPCs/xeno.yml
index ee258c52ab..ae92371085 100644
--- a/Resources/Prototypes/Entities/Mobs/NPCs/xeno.yml
+++ b/Resources/Prototypes/Entities/Mobs/NPCs/xeno.yml
@@ -15,6 +15,8 @@
- type: HTN
rootTask: XenoCompound
blackboard:
+ NavInteract: !type:Bool
+ true
NavPry: !type:Bool
true
NavSmash: !type:Bool