InteractWithOperator.cs 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899
  1. using Content.Server.Interaction;
  2. using Content.Shared.CombatMode;
  3. using Content.Shared.DoAfter;
  4. using Content.Shared.Timing;
  5. namespace Content.Server.NPC.HTN.PrimitiveTasks.Operators.Interactions;
  6. public sealed partial class InteractWithOperator : HTNOperator
  7. {
  8. [Dependency] private readonly IEntityManager _entManager = default!;
  9. private SharedDoAfterSystem _doAfterSystem = default!;
  10. public override void Initialize(IEntitySystemManager sysManager)
  11. {
  12. base.Initialize(sysManager);
  13. _doAfterSystem = sysManager.GetEntitySystem<SharedDoAfterSystem>();
  14. }
  15. /// <summary>
  16. /// Key that contains the target entity.
  17. /// </summary>
  18. [DataField(required: true)]
  19. public string TargetKey = default!;
  20. /// <summary>
  21. /// Exit with failure if doafter wasn't raised
  22. /// </summary>
  23. [DataField]
  24. public bool ExpectDoAfter = false;
  25. public string CurrentDoAfter = "CurrentInteractWithDoAfter";
  26. // Ensure that CurrentDoAfter doesn't exist as we enter this operator,
  27. // the code currently relies on the result of a TryGetValue
  28. public override void Startup(NPCBlackboard blackboard)
  29. {
  30. blackboard.Remove<ushort>(CurrentDoAfter);
  31. }
  32. // Not really sure if we should clean it up, I guess some operator could use it
  33. public override void TaskShutdown(NPCBlackboard blackboard, HTNOperatorStatus status)
  34. {
  35. blackboard.Remove<ushort>(CurrentDoAfter);
  36. }
  37. public override HTNOperatorStatus Update(NPCBlackboard blackboard, float frameTime)
  38. {
  39. var owner = blackboard.GetValue<EntityUid>(NPCBlackboard.Owner);
  40. // Handle ongoing doAfter, and store the doAfter.nextId so we can detect if we started one
  41. ushort nextId = 0;
  42. if (_entManager.TryGetComponent<DoAfterComponent>(owner, out var doAfter))
  43. {
  44. // if CurrentDoAfter contains something, we have an active doAfter
  45. if (blackboard.TryGetValue<ushort>(CurrentDoAfter, out var doAfterId, _entManager))
  46. {
  47. var status = _doAfterSystem.GetStatus(owner, doAfterId, null);
  48. return status switch
  49. {
  50. DoAfterStatus.Running => HTNOperatorStatus.Continuing,
  51. DoAfterStatus.Finished => HTNOperatorStatus.Finished,
  52. _ => HTNOperatorStatus.Failed
  53. };
  54. }
  55. nextId = doAfter.NextId;
  56. }
  57. if (_entManager.TryGetComponent<UseDelayComponent>(owner, out var useDelay) && _entManager.System<UseDelaySystem>().IsDelayed((owner, useDelay)) ||
  58. !blackboard.TryGetValue<EntityUid>(TargetKey, out var moveTarget, _entManager) ||
  59. !_entManager.TryGetComponent<TransformComponent>(moveTarget, out var targetXform))
  60. {
  61. return HTNOperatorStatus.Continuing;
  62. }
  63. if (_entManager.TryGetComponent<CombatModeComponent>(owner, out var combatMode))
  64. {
  65. _entManager.System<SharedCombatModeSystem>().SetInCombatMode(owner, false, combatMode);
  66. }
  67. _entManager.System<InteractionSystem>().UserInteraction(owner, targetXform.Coordinates, moveTarget);
  68. // Detect doAfter, save it, and don't exit from this operator
  69. if (doAfter != null && nextId != doAfter.NextId)
  70. {
  71. blackboard.SetValue(CurrentDoAfter, nextId);
  72. return HTNOperatorStatus.Continuing;
  73. }
  74. // We shouldn't arrive here if we start a doafter, so fail if we expected a doafter
  75. if(ExpectDoAfter)
  76. return HTNOperatorStatus.Failed;
  77. return HTNOperatorStatus.Finished;
  78. }
  79. }