Shooting NPCs and more (#18042)
* Add pirate shooting * Shooting working * Basics working * Refactor time * More conversion * Update primitives * Update yml * weh * Building again * Draft * weh * b * Start shutdown * Starting to take form * Code side done * is it worky * Fix prototypes * stuff * Shitty working * Juke events working * Even more cleanup * RTX * Fix interaction combat mode and compquery * GetAmmoCount relays * Fix rotation speed * Juke fixes * fixes * weh * The collision avoidance never ends * Fixes * Pause support * framework * lazy * Fix idling * Fix drip * goobed * Fix takeover shutdown bug * Merge fixes * shitter * Fix carpos
This commit is contained in:
@@ -0,0 +1,133 @@
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Content.Server.NPC.Components;
|
||||
using Content.Shared.CombatMode;
|
||||
using Content.Shared.Mobs;
|
||||
using Content.Shared.Mobs.Components;
|
||||
using Robust.Shared.Audio;
|
||||
|
||||
namespace Content.Server.NPC.HTN.PrimitiveTasks.Operators.Combat.Ranged;
|
||||
|
||||
public sealed class GunOperator : HTNOperator, IHtnConditionalShutdown
|
||||
{
|
||||
[Dependency] private readonly IEntityManager _entManager = default!;
|
||||
|
||||
[DataField("shutdownState")]
|
||||
public HTNPlanState ShutdownState { get; } = HTNPlanState.TaskFinished;
|
||||
|
||||
/// <summary>
|
||||
/// Key that contains the target entity.
|
||||
/// </summary>
|
||||
[DataField("targetKey", required: true)]
|
||||
public string TargetKey = default!;
|
||||
|
||||
/// <summary>
|
||||
/// Minimum damage state that the target has to be in for us to consider attacking.
|
||||
/// </summary>
|
||||
[DataField("targetState")]
|
||||
public MobState TargetState = MobState.Alive;
|
||||
|
||||
/// <summary>
|
||||
/// Do we require line of sight of the target before failing.
|
||||
/// </summary>
|
||||
[DataField("requireLOS")]
|
||||
public bool RequireLOS = false;
|
||||
|
||||
// Like movement we add a component and pass it off to the dedicated system.
|
||||
|
||||
public override async Task<(bool Valid, Dictionary<string, object>? Effects)> Plan(NPCBlackboard blackboard,
|
||||
CancellationToken cancelToken)
|
||||
{
|
||||
// Don't attack if they're already as wounded as we want them.
|
||||
if (!blackboard.TryGetValue<EntityUid>(TargetKey, out var target, _entManager))
|
||||
{
|
||||
return (false, null);
|
||||
}
|
||||
|
||||
if (_entManager.TryGetComponent<MobStateComponent>(target, out var mobState) &&
|
||||
mobState.CurrentState > TargetState)
|
||||
{
|
||||
return (false, null);
|
||||
}
|
||||
|
||||
return (true, null);
|
||||
}
|
||||
|
||||
public override void Startup(NPCBlackboard blackboard)
|
||||
{
|
||||
base.Startup(blackboard);
|
||||
var ranged = _entManager.EnsureComponent<NPCRangedCombatComponent>(blackboard.GetValue<EntityUid>(NPCBlackboard.Owner));
|
||||
ranged.Target = blackboard.GetValue<EntityUid>(TargetKey);
|
||||
|
||||
if (blackboard.TryGetValue<float>(NPCBlackboard.RotateSpeed, out var rotSpeed, _entManager))
|
||||
{
|
||||
ranged.RotationSpeed = new Angle(rotSpeed);
|
||||
}
|
||||
|
||||
if (blackboard.TryGetValue<SoundSpecifier>("SoundTargetInLOS", out var losSound, _entManager))
|
||||
{
|
||||
ranged.SoundTargetInLOS = losSound;
|
||||
}
|
||||
}
|
||||
|
||||
public void ConditionalShutdown(NPCBlackboard blackboard)
|
||||
{
|
||||
var owner = blackboard.GetValue<EntityUid>(NPCBlackboard.Owner);
|
||||
_entManager.System<SharedCombatModeSystem>().SetInCombatMode(owner, false);
|
||||
_entManager.RemoveComponent<NPCRangedCombatComponent>(owner);
|
||||
blackboard.Remove<EntityUid>(TargetKey);
|
||||
}
|
||||
|
||||
public override HTNOperatorStatus Update(NPCBlackboard blackboard, float frameTime)
|
||||
{
|
||||
base.Update(blackboard, frameTime);
|
||||
var owner = blackboard.GetValue<EntityUid>(NPCBlackboard.Owner);
|
||||
HTNOperatorStatus status;
|
||||
|
||||
if (_entManager.TryGetComponent<NPCRangedCombatComponent>(owner, out var combat) &&
|
||||
blackboard.TryGetValue<EntityUid>(TargetKey, out var target, _entManager))
|
||||
{
|
||||
combat.Target = target;
|
||||
|
||||
// Success
|
||||
if (_entManager.TryGetComponent<MobStateComponent>(combat.Target, out var mobState) &&
|
||||
mobState.CurrentState > TargetState)
|
||||
{
|
||||
status = HTNOperatorStatus.Finished;
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (combat.Status)
|
||||
{
|
||||
case CombatStatus.TargetUnreachable:
|
||||
status = HTNOperatorStatus.Failed;
|
||||
break;
|
||||
case CombatStatus.NotInSight:
|
||||
if (RequireLOS)
|
||||
status = HTNOperatorStatus.Failed;
|
||||
else
|
||||
status = HTNOperatorStatus.Continuing;
|
||||
break;
|
||||
case CombatStatus.Normal:
|
||||
status = HTNOperatorStatus.Continuing;
|
||||
break;
|
||||
default:
|
||||
status = HTNOperatorStatus.Failed;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
status = HTNOperatorStatus.Failed;
|
||||
}
|
||||
|
||||
// Mark it as finished to continue the plan.
|
||||
if (status == HTNOperatorStatus.Continuing && ShutdownState == HTNPlanState.PlanFinished)
|
||||
{
|
||||
status = HTNOperatorStatus.Finished;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user