Bandaid medibots (#11718)
This commit is contained in:
@@ -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.
|
||||||
|
|||||||
@@ -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)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -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)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
Reference in New Issue
Block a user