using System.Threading; using System.Threading.Tasks; using Content.Server.NPC.Components; using Content.Server.Storage.EntitySystems; using Content.Shared.CombatMode; using Robust.Server.Containers; namespace Content.Server.NPC.HTN.PrimitiveTasks.Operators.Combat.Melee; public sealed partial class EscapeOperator : HTNOperator, IHtnConditionalShutdown { [Dependency] private readonly IEntityManager _entManager = default!; private ContainerSystem _container = default!; private EntityStorageSystem _entityStorage = default!; [DataField("shutdownState")] public HTNPlanState ShutdownState { get; private set; } = HTNPlanState.TaskFinished; [DataField("targetKey", required: true)] public string TargetKey = default!; public override void Initialize(IEntitySystemManager sysManager) { base.Initialize(sysManager); _container = sysManager.GetEntitySystem(); _entityStorage = sysManager.GetEntitySystem(); } public override void Startup(NPCBlackboard blackboard) { base.Startup(blackboard); var owner = blackboard.GetValue(NPCBlackboard.Owner); var target = blackboard.GetValue(TargetKey); if (_entityStorage.TryOpenStorage(owner, target)) { TaskShutdown(blackboard, HTNOperatorStatus.Finished); return; } var melee = _entManager.EnsureComponent(owner); melee.MissChance = blackboard.GetValueOrDefault(NPCBlackboard.MeleeMissChance, _entManager); melee.Target = target; } public override async Task<(bool Valid, Dictionary? Effects)> Plan(NPCBlackboard blackboard, CancellationToken cancelToken) { var owner = blackboard.GetValue(NPCBlackboard.Owner); if (!blackboard.TryGetValue(TargetKey, out var target, _entManager)) { return (false, null); } if (!_container.IsEntityInContainer(owner)) { return (false, null); } if (_entityStorage.TryOpenStorage(owner, target)) { return (false, null); } return (true, null); } public void ConditionalShutdown(NPCBlackboard blackboard) { var owner = blackboard.GetValue(NPCBlackboard.Owner); _entManager.System().SetInCombatMode(owner, false); _entManager.RemoveComponent(owner); blackboard.Remove(TargetKey); } public override void TaskShutdown(NPCBlackboard blackboard, HTNOperatorStatus status) { base.TaskShutdown(blackboard, status); ConditionalShutdown(blackboard); } public override void PlanShutdown(NPCBlackboard blackboard) { base.PlanShutdown(blackboard); ConditionalShutdown(blackboard); } public override HTNOperatorStatus Update(NPCBlackboard blackboard, float frameTime) { base.Update(blackboard, frameTime); var owner = blackboard.GetValue(NPCBlackboard.Owner); HTNOperatorStatus status; if (_entManager.TryGetComponent(owner, out var combat) && blackboard.TryGetValue(TargetKey, out var target, _entManager)) { combat.Target = target; // Success if (!_container.IsEntityInContainer(owner)) { status = HTNOperatorStatus.Finished; } else { if (_entityStorage.TryOpenStorage(owner, target)) { status = HTNOperatorStatus.Finished; } else { switch (combat.Status) { case CombatStatus.TargetOutOfRange: 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; } }