Bandaid medibots (#11718)

This commit is contained in:
metalgearsloth
2022-10-13 21:36:29 +11:00
committed by GitHub
parent 8e1d599656
commit fa59983bd9
11 changed files with 67 additions and 14 deletions

View File

@@ -42,7 +42,7 @@ public sealed class MoveToOperator : HTNOperator
/// Where the pathfinding result will be stored (if applicable). This gets removed after execution. /// Where the pathfinding result will be stored (if applicable). This gets removed after execution.
/// </summary> /// </summary>
[ViewVariables, DataField("pathfindKey")] [ViewVariables, DataField("pathfindKey")]
public string PathfindKey = "MovementPathfind"; public string PathfindKey = NPCBlackboard.PathfindKey;
/// <summary> /// <summary>
/// How close we need to get before considering movement finished. /// How close we need to get before considering movement finished.

View File

@@ -30,7 +30,7 @@ public sealed class PickAccessibleComponentOperator : HTNOperator
/// Where the pathfinding result will be stored (if applicable). This gets removed after execution. /// Where the pathfinding result will be stored (if applicable). This gets removed after execution.
/// </summary> /// </summary>
[ViewVariables, DataField("pathfindKey")] [ViewVariables, DataField("pathfindKey")]
public string PathfindKey = "MovementPathfind"; public string PathfindKey = NPCBlackboard.PathfindKey;
public override void Initialize(IEntitySystemManager sysManager) public override void Initialize(IEntitySystemManager sysManager)
{ {

View File

@@ -23,7 +23,7 @@ public sealed class PickAccessibleOperator : HTNOperator
/// Where the pathfinding result will be stored (if applicable). This gets removed after execution. /// Where the pathfinding result will be stored (if applicable). This gets removed after execution.
/// </summary> /// </summary>
[ViewVariables, DataField("pathfindKey")] [ViewVariables, DataField("pathfindKey")]
public string PathfindKey = "MovementPathfind"; public string PathfindKey = NPCBlackboard.PathfindKey;
public override void Initialize(IEntitySystemManager sysManager) public override void Initialize(IEntitySystemManager sysManager)
{ {

View File

@@ -50,6 +50,9 @@ public sealed class MedibotInjectOperator : HTNOperator
if (!_entManager.TryGetComponent<MedibotComponent>(owner, out var botComp)) if (!_entManager.TryGetComponent<MedibotComponent>(owner, out var botComp))
return HTNOperatorStatus.Failed; return HTNOperatorStatus.Failed;
// To avoid spam, the rest of this needs fixing.
_entManager.EnsureComponent<NPCRecentlyInjectedComponent>(target);
if (!_entManager.TryGetComponent<DamageableComponent>(target, out var damage)) if (!_entManager.TryGetComponent<DamageableComponent>(target, out var damage))
return HTNOperatorStatus.Failed; return HTNOperatorStatus.Failed;
@@ -62,20 +65,18 @@ public sealed class MedibotInjectOperator : HTNOperator
if (damage.TotalDamage == 0) if (damage.TotalDamage == 0)
return HTNOperatorStatus.Failed; return HTNOperatorStatus.Failed;
if (damage.TotalDamage <= MedibotComponent.StandardMedDamageThreshold) if (damage.TotalDamage >= MedibotComponent.EmergencyMedDamageThreshold)
{ {
_solutionSystem.TryAddReagent(target, injectable, botComp.StandardMed, botComp.StandardMedInjectAmount, out var accepted); _solutionSystem.TryAddReagent(target, injectable, botComp.EmergencyMed, botComp.EmergencyMedInjectAmount, out var accepted);
_entManager.EnsureComponent<NPCRecentlyInjectedComponent>(target);
_popupSystem.PopupEntity(Loc.GetString("hypospray-component-feel-prick-message"), target, Filter.Entities(target)); _popupSystem.PopupEntity(Loc.GetString("hypospray-component-feel-prick-message"), target, Filter.Entities(target));
SoundSystem.Play("/Audio/Items/hypospray.ogg", Filter.Pvs(target), target); SoundSystem.Play("/Audio/Items/hypospray.ogg", Filter.Pvs(target), target);
_chat.TrySendInGameICMessage(owner, Loc.GetString("medibot-finish-inject"), InGameICChatType.Speak, false); _chat.TrySendInGameICMessage(owner, Loc.GetString("medibot-finish-inject"), InGameICChatType.Speak, false);
return HTNOperatorStatus.Finished; return HTNOperatorStatus.Finished;
} }
if (damage.TotalDamage >= MedibotComponent.EmergencyMedDamageThreshold) if (damage.TotalDamage >= MedibotComponent.StandardMedDamageThreshold)
{ {
_solutionSystem.TryAddReagent(target, injectable, botComp.EmergencyMed, botComp.EmergencyMedInjectAmount, out var accepted); _solutionSystem.TryAddReagent(target, injectable, botComp.StandardMed, botComp.StandardMedInjectAmount, out var accepted);
_entManager.EnsureComponent<NPCRecentlyInjectedComponent>(target);
_popupSystem.PopupEntity(Loc.GetString("hypospray-component-feel-prick-message"), target, Filter.Entities(target)); _popupSystem.PopupEntity(Loc.GetString("hypospray-component-feel-prick-message"), target, Filter.Entities(target));
SoundSystem.Play("/Audio/Items/hypospray.ogg", Filter.Pvs(target), target); SoundSystem.Play("/Audio/Items/hypospray.ogg", Filter.Pvs(target), target);
_chat.TrySendInGameICMessage(owner, Loc.GetString("medibot-finish-inject"), InGameICChatType.Speak, false); _chat.TrySendInGameICMessage(owner, Loc.GetString("medibot-finish-inject"), InGameICChatType.Speak, false);

View File

@@ -2,7 +2,9 @@ using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Content.Server.Chemistry.Components.SolutionManager; using Content.Server.Chemistry.Components.SolutionManager;
using Content.Server.NPC.Components; using Content.Server.NPC.Components;
using Content.Server.NPC.Pathfinding;
using Content.Shared.Damage; using Content.Shared.Damage;
using Content.Shared.Interaction;
using Content.Shared.MobState.Components; using Content.Shared.MobState.Components;
namespace Content.Server.NPC.HTN.PrimitiveTasks.Operators.Specific; namespace Content.Server.NPC.HTN.PrimitiveTasks.Operators.Specific;
@@ -11,6 +13,7 @@ public sealed class PickNearbyInjectableOperator : HTNOperator
{ {
[Dependency] private readonly IEntityManager _entManager = default!; [Dependency] private readonly IEntityManager _entManager = default!;
private EntityLookupSystem _lookup = default!; private EntityLookupSystem _lookup = default!;
private PathfindingSystem _pathfinding = default!;
[ViewVariables, DataField("rangeKey")] public string RangeKey = NPCBlackboard.MedibotInjectRange; [ViewVariables, DataField("rangeKey")] public string RangeKey = NPCBlackboard.MedibotInjectRange;
@@ -30,6 +33,7 @@ public sealed class PickNearbyInjectableOperator : HTNOperator
{ {
base.Initialize(sysManager); base.Initialize(sysManager);
_lookup = sysManager.GetEntitySystem<EntityLookupSystem>(); _lookup = sysManager.GetEntitySystem<EntityLookupSystem>();
_pathfinding = sysManager.GetEntitySystem<PathfindingSystem>();
} }
public override async Task<(bool Valid, Dictionary<string, object>? Effects)> Plan(NPCBlackboard blackboard, public override async Task<(bool Valid, Dictionary<string, object>? Effects)> Plan(NPCBlackboard blackboard,
@@ -53,10 +57,16 @@ public sealed class PickNearbyInjectableOperator : HTNOperator
damage.TotalDamage > 0 && damage.TotalDamage > 0 &&
!recentlyInjected.HasComponent(entity)) !recentlyInjected.HasComponent(entity))
{ {
var path = await _pathfinding.GetPath(owner, entity, SharedInteractionSystem.InteractionRange, cancelToken);
if (path.Result == PathResult.NoPath)
continue;
return (true, new Dictionary<string, object>() return (true, new Dictionary<string, object>()
{ {
{TargetKey, entity}, {TargetKey, entity},
{TargetMoveKey, _entManager.GetComponent<TransformComponent>(entity).Coordinates} {TargetMoveKey, _entManager.GetComponent<TransformComponent>(entity).Coordinates},
{NPCBlackboard.PathfindKey, path},
}); });
} }
} }

View File

@@ -196,6 +196,11 @@ public sealed class NPCBlackboard : IEnumerable<KeyValuePair<string, object>>
public const string OwnerCoordinates = "OwnerCoordinates"; public const string OwnerCoordinates = "OwnerCoordinates";
public const string MovementTarget = "MovementTarget"; public const string MovementTarget = "MovementTarget";
/// <summary>
/// Can the NPC click open entities such as doors.
/// </summary>
public const string NavInteract = "NavInteract";
/// <summary> /// <summary>
/// Can the NPC pry open doors for steering. /// Can the NPC pry open doors for steering.
/// </summary> /// </summary>
@@ -205,6 +210,12 @@ public sealed class NPCBlackboard : IEnumerable<KeyValuePair<string, object>>
/// Can the NPC smash obstacles for steering. /// Can the NPC smash obstacles for steering.
/// </summary> /// </summary>
public const string NavSmash = "NavSmash"; public const string NavSmash = "NavSmash";
/// <summary>
/// Default key storage for a movement pathfind.
/// </summary>
public const string PathfindKey = "MovementPathfind";
public const string RotateSpeed = "RotateSpeed"; public const string RotateSpeed = "RotateSpeed";
public const string VisionRadius = "VisionRadius"; public const string VisionRadius = "VisionRadius";
public const float MeleeRange = 1f; public const float MeleeRange = 1f;

View File

@@ -19,4 +19,9 @@ public enum PathFlags : byte
/// Can stuff like walls be broken. /// Can stuff like walls be broken.
/// </summary> /// </summary>
Smashing = 1 << 2, Smashing = 1 << 2,
/// <summary>
/// Can we open stuff that requires interaction (e.g. click-open doors).
/// </summary>
Interact = 1 << 3,
} }

View File

@@ -58,7 +58,7 @@ public sealed partial class PathfindingSystem
// TODO: Handling power + door prying // TODO: Handling power + door prying
// Door we should be able to open // Door we should be able to open
if (isDoor && !isAccess) if (isDoor && !isAccess && (request.Flags & PathFlags.Interact) != 0x0)
{ {
modifier += 0.5f; modifier += 0.5f;
} }

View File

@@ -280,6 +280,21 @@ namespace Content.Server.NPC.Pathfinding
return distance; return distance;
} }
public async Task<PathResultEvent> GetPath(
EntityUid entity,
EntityUid target,
float range,
CancellationToken cancelToken,
PathFlags flags = PathFlags.None)
{
if (!TryComp<TransformComponent>(entity, out var xform) ||
!TryComp<TransformComponent>(target, out var targetXform))
return new PathResultEvent(PathResult.NoPath, new Queue<PathPoly>());
var request = GetRequest(entity, xform.Coordinates, targetXform.Coordinates, range, cancelToken, flags);
return await GetPath(request);
}
public async Task<PathResultEvent> GetPath( public async Task<PathResultEvent> GetPath(
EntityUid entity, EntityUid entity,
EntityCoordinates start, EntityCoordinates start,
@@ -385,16 +400,21 @@ namespace Content.Server.NPC.Pathfinding
{ {
var flags = PathFlags.None; var flags = PathFlags.None;
if (blackboard.TryGetValue<bool>(NPCBlackboard.NavPry, out var pry)) if (blackboard.TryGetValue<bool>(NPCBlackboard.NavPry, out var pry) && pry)
{ {
flags |= PathFlags.Prying; flags |= PathFlags.Prying;
} }
if (blackboard.TryGetValue<bool>(NPCBlackboard.NavSmash, out var smash)) if (blackboard.TryGetValue<bool>(NPCBlackboard.NavSmash, out var smash) && smash)
{ {
flags |= PathFlags.Smashing; flags |= PathFlags.Smashing;
} }
if (blackboard.TryGetValue<bool>(NPCBlackboard.NavInteract, out var interact) && interact)
{
flags |= PathFlags.Interact;
}
return flags; return flags;
} }

View File

@@ -63,7 +63,7 @@ public sealed partial class NPCSteeringSystem
if (!doorQuery.TryGetComponent(ent, out var door)) if (!doorQuery.TryGetComponent(ent, out var door))
continue; continue;
if (!door.BumpOpen) if (!door.BumpOpen && (component.Flags & PathFlags.Interact) != 0x0)
{ {
if (door.State != DoorState.Opening) if (door.State != DoorState.Opening)
{ {
@@ -71,6 +71,10 @@ public sealed partial class NPCSteeringSystem
return SteeringObstacleStatus.Continuing; return SteeringObstacleStatus.Continuing;
} }
} }
else
{
return SteeringObstacleStatus.Failed;
}
} }
return SteeringObstacleStatus.Completed; return SteeringObstacleStatus.Completed;

View File

@@ -15,6 +15,8 @@
- type: HTN - type: HTN
rootTask: XenoCompound rootTask: XenoCompound
blackboard: blackboard:
NavInteract: !type:Bool
true
NavPry: !type:Bool NavPry: !type:Bool
true true
NavSmash: !type:Bool NavSmash: !type:Bool