using System.Threading;
using System.Threading.Tasks;
using Content.Server.NPC.Components;
using Content.Shared.MobState;
using Content.Shared.MobState.Components;
using Robust.Shared.Audio;
namespace Content.Server.NPC.HTN.PrimitiveTasks.Operators.Ranged;
public sealed class RangedOperator : HTNOperator
{
[Dependency] private readonly IEntityManager _entManager = default!;
///
/// Key that contains the target entity.
///
[DataField("targetKey", required: true)]
public string TargetKey = default!;
///
/// Minimum damage state that the target has to be in for us to consider attacking.
///
[DataField("targetState")]
public DamageState TargetState = DamageState.Alive;
// Like movement we add a component and pass it off to the dedicated system.
public override async Task<(bool Valid, Dictionary? Effects)> Plan(NPCBlackboard blackboard,
CancellationToken cancelToken)
{
// Don't attack if they're already as wounded as we want them.
if (!blackboard.TryGetValue(TargetKey, out var target, _entManager))
{
return (false, null);
}
if (_entManager.TryGetComponent(target, out var mobState) &&
mobState.CurrentState != null &&
mobState.CurrentState > TargetState)
{
return (false, null);
}
return (true, null);
}
public override void Startup(NPCBlackboard blackboard)
{
base.Startup(blackboard);
var ranged = _entManager.EnsureComponent(blackboard.GetValue(NPCBlackboard.Owner));
ranged.Target = blackboard.GetValue(TargetKey);
if (blackboard.TryGetValue(NPCBlackboard.RotateSpeed, out var rotSpeed, _entManager))
{
ranged.RotationSpeed = new Angle(rotSpeed);
}
if (blackboard.TryGetValue("SoundTargetInLOS", out var losSound, _entManager))
{
ranged.SoundTargetInLOS = losSound;
}
}
public override void Shutdown(NPCBlackboard blackboard, HTNOperatorStatus status)
{
base.Shutdown(blackboard, status);
_entManager.RemoveComponent(blackboard.GetValue(NPCBlackboard.Owner));
blackboard.Remove(TargetKey);
}
public override HTNOperatorStatus Update(NPCBlackboard blackboard, float frameTime)
{
base.Update(blackboard, frameTime);
var owner = blackboard.GetValue(NPCBlackboard.Owner);
var status = HTNOperatorStatus.Continuing;
if (_entManager.TryGetComponent(owner, out var combat))
{
// Success
if (_entManager.TryGetComponent(combat.Target, out var mobState) &&
mobState.CurrentState != null &&
mobState.CurrentState > TargetState)
{
status = HTNOperatorStatus.Finished;
}
else
{
switch (combat.Status)
{
case CombatStatus.TargetUnreachable:
case CombatStatus.NotInSight:
status = HTNOperatorStatus.Failed;
break;
case CombatStatus.Normal:
status = HTNOperatorStatus.Continuing;
break;
default:
status = HTNOperatorStatus.Failed;
break;
}
}
}
if (status != HTNOperatorStatus.Continuing)
{
_entManager.RemoveComponent(owner);
}
return status;
}
}