diff --git a/Content.Server/NPC/HTN/PrimitiveTasks/Operators/Interactions/InteractWithOperator.cs b/Content.Server/NPC/HTN/PrimitiveTasks/Operators/Interactions/InteractWithOperator.cs index 8e3ab5238a3314..7d6f0005730b5f 100644 --- a/Content.Server/NPC/HTN/PrimitiveTasks/Operators/Interactions/InteractWithOperator.cs +++ b/Content.Server/NPC/HTN/PrimitiveTasks/Operators/Interactions/InteractWithOperator.cs @@ -1,5 +1,6 @@ using Content.Server.Interaction; using Content.Shared.CombatMode; +using Content.Shared.DoAfter; using Content.Shared.Timing; namespace Content.Server.NPC.HTN.PrimitiveTasks.Operators.Interactions; @@ -7,6 +8,13 @@ namespace Content.Server.NPC.HTN.PrimitiveTasks.Operators.Interactions; public sealed partial class InteractWithOperator : HTNOperator { [Dependency] private readonly IEntityManager _entManager = default!; + private SharedDoAfterSystem _doAfterSystem = default!; + + public override void Initialize(IEntitySystemManager sysManager) + { + base.Initialize(sysManager); + _doAfterSystem = sysManager.GetEntitySystem(); + } /// /// Key that contains the target entity. @@ -14,10 +22,53 @@ public sealed partial class InteractWithOperator : HTNOperator [DataField(required: true)] public string TargetKey = default!; + /// + /// Exit with failure if doafter wasn't raised + /// + [DataField] + public bool ExpectDoAfter = false; + + public string CurrentDoAfter = "CurrentInteractWithDoAfter"; + + + // Ensure that CurrentDoAfter doesn't exist as we enter this operator, + // the code currently relies on the result of a TryGetValue + public override void Startup(NPCBlackboard blackboard) + { + blackboard.Remove(CurrentDoAfter); + + } + + // Not really sure if we should clean it up, I guess some operator could use it + public override void TaskShutdown(NPCBlackboard blackboard, HTNOperatorStatus status) + { + blackboard.Remove(CurrentDoAfter); + } + public override HTNOperatorStatus Update(NPCBlackboard blackboard, float frameTime) { var owner = blackboard.GetValue(NPCBlackboard.Owner); + // Handle ongoing doAfter, and store the doAfter.nextId so we can detect if we started one + ushort nextId = 0; + if (_entManager.TryGetComponent(owner, out var doAfter)) + { + // if CurrentDoAfter contains something, we have an active doAfter + if (blackboard.TryGetValue(CurrentDoAfter, out var doAfterId, _entManager)) + { + var status = _doAfterSystem.GetStatus(owner, doAfterId, null); + return status switch + { + DoAfterStatus.Running => HTNOperatorStatus.Continuing, + DoAfterStatus.Finished => HTNOperatorStatus.Finished, + _ => HTNOperatorStatus.Failed + }; + } + + nextId = doAfter.NextId; + } + + if (_entManager.TryGetComponent(owner, out var useDelay) && _entManager.System().IsDelayed((owner, useDelay)) || !blackboard.TryGetValue(TargetKey, out var moveTarget, _entManager) || !_entManager.TryGetComponent(moveTarget, out var targetXform)) @@ -31,6 +82,18 @@ public override HTNOperatorStatus Update(NPCBlackboard blackboard, float frameTi } _entManager.System().UserInteraction(owner, targetXform.Coordinates, moveTarget); + + // Detect doAfter, save it, and don't exit from this operator + if (doAfter != null && nextId != doAfter.NextId) + { + blackboard.SetValue(CurrentDoAfter, nextId); + return HTNOperatorStatus.Continuing; + } + + // We shouldn't arrive here if we start a doafter, so fail if we expected a doafter + if(ExpectDoAfter) + return HTNOperatorStatus.Failed; + return HTNOperatorStatus.Finished; } }