BVB Source Codes

CRYENGINE Show BehaviorTreeNodes_AI.cpp Source code

Return Download CRYENGINE: download BehaviorTreeNodes_AI.cpp Source code - Download CRYENGINE Source code - Type:.cpp
  1. // Copyright 2001-2016 Crytek GmbH / Crytek Group. All rights reserved.
  2.  
  3. #include "StdAfx.h"
  4. #include "BehaviorTreeNodes_AI.h"
  5.  
  6. #include "AIActor.h" // Big one, but needed for timestamp collection
  7. #include "Puppet.h"  // Big one, but needed for the posture manager
  8. #include "AIBubblesSystem/AIBubblesSystem.h"
  9. #include "AIGroup.h"
  10. #include "Group/GroupManager.h"
  11. #include <CryAISystem/BehaviorTree/Action.h>
  12. #include <CryAISystem/BehaviorTree/Decorator.h>
  13. #include <CryAISystem/BehaviorTree/IBehaviorTree.h>
  14. #include <CrySystem/Timer.h>
  15. #include "Cover/CoverSystem.h"
  16. #include "GoalPipeXMLReader.h"
  17. #include <CryAISystem/IAIActor.h>
  18. #include <CryAISystem/IAgent.h>
  19. #include <CryAISystem/IMovementSystem.h>
  20. #include <CryAISystem/MovementRequest.h>
  21. #include <CryAISystem/MovementStyle.h>
  22. #include "PipeUser.h"                                // Big one, but needed for GetProxy and SetBehavior
  23. #include "TacticalPointSystem/TacticalPointSystem.h" // Big one, but needed for InitQueryContextFromActor
  24. #include "TargetSelection/TargetTrackManager.h"
  25. #include "BehaviorTree/BehaviorTreeNodes_Helicopter.h"
  26. #include <CryString/CryName.h>
  27. #include <CryGame/IGameFramework.h>
  28. #include "BehaviorTreeManager.h"
  29.  
  30. #include <../CryAction/ICryMannequin.h>
  31.  
  32. namespace
  33. {
  34. struct FireModeDictionary
  35. {
  36.         FireModeDictionary();
  37.         CXMLAttrReader<EFireMode> fireMode;
  38. };
  39.  
  40. FireModeDictionary::FireModeDictionary()
  41. {
  42.         fireMode.Add("Off", FIREMODE_OFF);
  43.         fireMode.Add("Burst", FIREMODE_BURST);
  44.         fireMode.Add("Continuous", FIREMODE_CONTINUOUS);
  45.         fireMode.Add("Forced", FIREMODE_FORCED);
  46.         fireMode.Add("Aim", FIREMODE_AIM);
  47.         fireMode.Add("Secondary", FIREMODE_SECONDARY);
  48.         fireMode.Add("SecondarySmoke", FIREMODE_SECONDARY_SMOKE);
  49.         fireMode.Add("Melee", FIREMODE_MELEE);
  50.         fireMode.Add("Kill", FIREMODE_KILL);
  51.         fireMode.Add("BurstWhileMoving", FIREMODE_BURST_WHILE_MOVING);
  52.         fireMode.Add("PanicSpread", FIREMODE_PANIC_SPREAD);
  53.         fireMode.Add("BurstDrawFire", FIREMODE_BURST_DRAWFIRE);
  54.         fireMode.Add("MeleeForced", FIREMODE_MELEE_FORCED);
  55.         fireMode.Add("BurstSnipe", FIREMODE_BURST_SNIPE);
  56.         fireMode.Add("AimSweep", FIREMODE_AIM_SWEEP);
  57.         fireMode.Add("BurstOnce", FIREMODE_BURST_ONCE);
  58. }
  59.  
  60. FireModeDictionary g_fireModeDictionary;
  61.  
  62. CPipeUser* GetPipeUser(const BehaviorTree::UpdateContext& context)
  63. {
  64.         assert(context.entity.GetAI());
  65.         return context.entity.GetAI()->CastToCPipeUser();
  66. }
  67.  
  68. CPuppet* GetPuppet(const BehaviorTree::UpdateContext& context)
  69. {
  70.         assert(context.entity.GetAI());
  71.         return context.entity.GetAI()->CastToCPuppet();
  72. }
  73.  
  74. CAIActor* GetAIActor(const BehaviorTree::UpdateContext& context)
  75. {
  76.         assert(context.entity.GetAI());
  77.         return context.entity.GetAI()->CastToCAIActor();
  78. }
  79.  
  80. const CTimeValue& GetFrameStartTime(const BehaviorTree::UpdateContext& context)
  81. {
  82.         return gEnv->pTimer->GetFrameStartTime();
  83. }
  84. }
  85.  
  86. namespace BehaviorTree
  87. {
  88. unsigned int TreeLocalGoalPipeCounter = 0;
  89.  
  90. class GoalPipe : public Action
  91. {
  92. public:
  93.         struct RuntimeData : public IGoalPipeListener
  94.         {
  95.                 EntityId entityToRemoveListenerFrom;
  96.                 int      goalPipeId;
  97.                 bool     goalPipeIsRunning;
  98.  
  99.                 RuntimeData()
  100.                         : entityToRemoveListenerFrom(0)
  101.                         , goalPipeId(0)
  102.                         , goalPipeIsRunning(false)
  103.                 {
  104.                 }
  105.  
  106.                 ~RuntimeData()
  107.                 {
  108.                         UnregisterGoalPipeListener();
  109.                 }
  110.  
  111.                 void UnregisterGoalPipeListener()
  112.                 {
  113.                         if (this->entityToRemoveListenerFrom != 0)
  114.                         {
  115.                                 assert(this->goalPipeId != 0);
  116.  
  117.                                 if (IEntity* entity = gEnv->pEntitySystem->GetEntity(this->entityToRemoveListenerFrom))
  118.                                 {
  119.                                         IAIObject* ai = entity->GetAI();
  120.                                         if (CPipeUser* pipeUser = ai ? ai->CastToCPipeUser() : NULL)
  121.                                         {
  122.                                                 pipeUser->UnRegisterGoalPipeListener(this, this->goalPipeId);
  123.                                         }
  124.                                 }
  125.  
  126.                                 this->entityToRemoveListenerFrom = 0;
  127.                         }
  128.                 }
  129.  
  130.                 // Overriding IGoalPipeListener
  131.                 virtual void OnGoalPipeEvent(IPipeUser* pPipeUser, EGoalPipeEvent event, int goalPipeId, bool& unregisterListenerAfterEvent)
  132.                 {
  133.                         if (event == ePN_Finished || event == ePN_Deselected)
  134.                         {
  135.                                 this->goalPipeIsRunning = false;
  136.                                 unregisterListenerAfterEvent = true;
  137.                                 this->entityToRemoveListenerFrom = 0;
  138.                         }
  139.                 }
  140.         };
  141.  
  142.         virtual LoadResult LoadFromXml(const XmlNodeRef& goalPipeXml, const LoadContext& context) override
  143.         {
  144.                 LoadName(goalPipeXml, context);
  145.  
  146.                 CGoalPipeXMLReader reader;
  147.                 reader.ParseGoalPipe(m_goalPipeName, goalPipeXml, CPipeManager::SilentlyReplaceDuplicate);
  148.  
  149.                 return LoadSuccess;
  150.         }
  151.  
  152. #ifdef USING_BEHAVIOR_TREE_NODE_CUSTOM_DEBUG_TEXT
  153.         virtual void GetCustomDebugText(const UpdateContext& updateContext, stack_string& debugText) const
  154.         {
  155.                 debugText = m_goalPipeName;
  156.         }
  157. #endif
  158.  
  159. protected:
  160.         virtual void OnInitialize(const UpdateContext& context) override
  161.         {
  162.                 FUNCTION_PROFILER(gEnv->pSystem, PROFILE_AI);
  163.  
  164.                 RuntimeData& runtimeData = GetRuntimeData<RuntimeData>(context);
  165.  
  166.                 runtimeData.goalPipeId = gEnv->pAISystem->AllocGoalPipeId();
  167.  
  168.                 IPipeUser& pipeUser = *GetPipeUser(context);
  169.                 pipeUser.SelectPipe(AIGOALPIPE_RUN_ONCE, m_goalPipeName, NULL, runtimeData.goalPipeId);
  170.                 pipeUser.RegisterGoalPipeListener(&runtimeData, runtimeData.goalPipeId, "GoalPipeBehaviorTreeNode");
  171.  
  172.                 runtimeData.entityToRemoveListenerFrom = context.entityId;
  173.  
  174.                 runtimeData.goalPipeIsRunning = true;
  175.         }
  176.  
  177.         virtual void OnTerminate(const UpdateContext& context) override
  178.         {
  179.                 FUNCTION_PROFILER(gEnv->pSystem, PROFILE_AI);
  180.  
  181.                 RuntimeData& runtimeData = GetRuntimeData<RuntimeData>(context);
  182.                 runtimeData.UnregisterGoalPipeListener();
  183.                 IPipeUser& pipeUser = *GetPipeUser(context);
  184.                 pipeUser.SelectPipe(AIGOALPIPE_LOOP, "_first_");
  185.         }
  186.  
  187.         virtual Status Update(const UpdateContext& context) override
  188.         {
  189.                 RuntimeData& runtimeData = GetRuntimeData<RuntimeData>(context);
  190.                 return runtimeData.goalPipeIsRunning ? Running : Success;
  191.         }
  192.  
  193. private:
  194.         void LoadName(const XmlNodeRef& goalPipeXml, const LoadContext& loadContext)
  195.         {
  196.                 m_goalPipeName = goalPipeXml->getAttr("name");
  197.  
  198.                 if (m_goalPipeName.empty())
  199.                 {
  200.                         m_goalPipeName.Format("%s%d_", loadContext.treeName, GetNodeID());
  201.                 }
  202.         }
  203.  
  204.         string m_goalPipeName;
  205. };
  206.  
  207. //////////////////////////////////////////////////////////////////////////
  208.  
  209. class LuaBehavior : public Action
  210. {
  211.         typedef Action BaseClass;
  212.  
  213. public:
  214.         struct RuntimeData : public IActorBehaviorListener
  215.         {
  216.                 EntityId entityToRemoveListenerFrom;
  217.                 bool     behaviorIsRunning;
  218.  
  219.                 RuntimeData()
  220.                         : entityToRemoveListenerFrom(0)
  221.                         , behaviorIsRunning(false)
  222.                 {
  223.                 }
  224.  
  225.                 ~RuntimeData()
  226.                 {
  227.                         UnregisterBehaviorListener();
  228.                 }
  229.  
  230.                 void UnregisterBehaviorListener()
  231.                 {
  232.                         if (this->entityToRemoveListenerFrom != 0)
  233.                         {
  234.                                 if (IEntity* entity = gEnv->pEntitySystem->GetEntity(this->entityToRemoveListenerFrom))
  235.                                 {
  236.                                         IAIObject* ai = entity->GetAI();
  237.                                         if (CPipeUser* pipeUser = ai ? ai->CastToCPipeUser() : NULL)
  238.                                         {
  239.                                                 pipeUser->UnregisterBehaviorListener(this);
  240.                                         }
  241.                                 }
  242.  
  243.                                 this->entityToRemoveListenerFrom = 0;
  244.                         }
  245.                 }
  246.  
  247.                 // Overriding IActorBehaviorListener
  248.                 virtual void BehaviorEvent(IAIObject* actor, EBehaviorEvent event) override
  249.                 {
  250.                         switch (event)
  251.                         {
  252.                         case BehaviorFinished:
  253.                         case BehaviorFailed:
  254.                         case BehaviorInterrupted:
  255.                                 this->behaviorIsRunning = false;
  256.                                 break;
  257.                         default:
  258.                                 break;
  259.                         }
  260.                 }
  261.  
  262.                 // Overriding IActorBehaviorListener
  263.                 virtual void BehaviorChanged(IAIObject* actor, const char* current, const char* previous) override
  264.                 {
  265.                 }
  266.         };
  267.  
  268.         virtual LoadResult LoadFromXml(const XmlNodeRef& node, const LoadContext& context) override
  269.         {
  270.                 IF_UNLIKELY (BaseClass::LoadFromXml(node, context) == LoadFailure)
  271.                         return LoadFailure;
  272.  
  273.                 m_behaviorName = node->getAttr("name");
  274.                 return LoadSuccess;
  275.         }
  276.  
  277. #ifdef USING_BEHAVIOR_TREE_NODE_CUSTOM_DEBUG_TEXT
  278.         virtual void GetCustomDebugText(const UpdateContext& updateContext, stack_string& debugText) const
  279.         {
  280.                 debugText += m_behaviorName;
  281.         }
  282. #endif
  283.  
  284. protected:
  285.         virtual void OnInitialize(const UpdateContext& context) override
  286.         {
  287.                 CPipeUser& pipeUser = *GetPipeUser(context);
  288.                 IAIActorProxy* proxy = pipeUser.GetProxy();
  289.  
  290.                 RuntimeData& runtimeData = GetRuntimeData<RuntimeData>(context);
  291.  
  292.                 if (proxy)
  293.                 {
  294.                         proxy->SetBehaviour(m_behaviorName);
  295.                         runtimeData.behaviorIsRunning = true;
  296.  
  297.                         pipeUser.RegisterBehaviorListener(&runtimeData);
  298.                         runtimeData.entityToRemoveListenerFrom = context.entityId;
  299.                 }
  300.                 else
  301.                 {
  302.                         runtimeData.behaviorIsRunning = false;
  303.                 }
  304.         }
  305.  
  306.         virtual void OnTerminate(const UpdateContext& context) override
  307.         {
  308.                 RuntimeData& runtimeData = GetRuntimeData<RuntimeData>(context);
  309.  
  310.                 runtimeData.UnregisterBehaviorListener();
  311.  
  312.                 IAIActorProxy* proxy = GetPipeUser(context)->GetProxy();
  313.                 if (proxy)
  314.                 {
  315.                         proxy->SetBehaviour("");
  316.                 }
  317.         }
  318.  
  319.         virtual Status Update(const UpdateContext& context) override
  320.         {
  321.                 RuntimeData& runtimeData = GetRuntimeData<RuntimeData>(context);
  322.                 return runtimeData.behaviorIsRunning ? Running : Success;
  323.         }
  324.  
  325. private:
  326.         string m_behaviorName;
  327. };
  328.  
  329. //////////////////////////////////////////////////////////////////////////
  330.  
  331. class Bubble : public Action
  332. {
  333. public:
  334.         struct RuntimeData
  335.         {
  336.         };
  337.  
  338.         Bubble()
  339.                 : m_duration(2.0)
  340.                 , m_balloonFlags(0)
  341.         {
  342.         }
  343.  
  344.         virtual Status Update(const UpdateContext& context)
  345.         {
  346.                 AIQueueBubbleMessage("Behavior Bubble", context.entityId, m_message, m_balloonFlags, m_duration, SAIBubbleRequest::eRT_PrototypeDialog);
  347.                 return Success;
  348.         }
  349.  
  350.         virtual LoadResult LoadFromXml(const XmlNodeRef& xml, const LoadContext& context)
  351.         {
  352.                 m_message = xml->getAttr("message");
  353.  
  354.                 m_duration = 2.0f;
  355.                 xml->getAttr("duration", m_duration);
  356.  
  357.                 bool balloon = true;
  358.                 bool log = true;
  359.  
  360.                 xml->getAttr("balloon", balloon);
  361.                 xml->getAttr("log", log);
  362.  
  363.                 m_balloonFlags = eBNS_None;
  364.  
  365.                 if (balloon) m_balloonFlags |= eBNS_Balloon;
  366.                 if (log) m_balloonFlags |= eBNS_Log;
  367.  
  368.                 return LoadSuccess;
  369.         }
  370.  
  371. private:
  372.         string m_message;
  373.         float  m_duration;
  374.         uint32 m_balloonFlags;
  375. };
  376.  
  377. //////////////////////////////////////////////////////////////////////////
  378.  
  379. class Move : public Action
  380. {
  381.         typedef Action BaseClass;
  382.  
  383. private:
  384.         enum DestinationType
  385.         {
  386.                 Target,
  387.                 Cover,
  388.                 ReferencePoint,
  389.                 LastOp,
  390.                 InitialPosition,
  391.         };
  392.  
  393.         struct Dictionaries
  394.         {
  395.                 CXMLAttrReader<DestinationType> to;
  396.  
  397.                 Dictionaries()
  398.                 {
  399.                         to.Reserve(4);
  400.                         to.Add("Target", Target);
  401.                         to.Add("Cover", Cover);
  402.                         to.Add("RefPoint", ReferencePoint);
  403.                         to.Add("LastOp", LastOp);
  404.                         to.Add("InitialPosition", InitialPosition);
  405.                 }
  406.         };
  407.  
  408.         static Dictionaries s_dictionaries;
  409.  
  410. public:
  411.         struct RuntimeData
  412.         {
  413.                 Vec3              destinationAtTimeOfMovementRequest;
  414.                 MovementRequestID movementRequestID;
  415.                 Status            pendingStatus;
  416.                 float             effectiveStopDistanceSq;
  417.  
  418.                 RuntimeData()
  419.                         : destinationAtTimeOfMovementRequest(ZERO)
  420.                         , movementRequestID(0)
  421.                         , pendingStatus(Running)
  422.                         , effectiveStopDistanceSq(0.0f)
  423.                 {
  424.                 }
  425.  
  426.                 ~RuntimeData()
  427.                 {
  428.                         ReleaseCurrentMovementRequest();
  429.                 }
  430.  
  431.                 void ReleaseCurrentMovementRequest()
  432.                 {
  433.                         if (this->movementRequestID)
  434.                         {
  435.                                 gEnv->pAISystem->GetMovementSystem()->CancelRequest(this->movementRequestID);
  436.                                 this->movementRequestID = MovementRequestID();
  437.                         }
  438.                 }
  439.  
  440.                 void MovementRequestCallback(const MovementRequestResult& result)
  441.                 {
  442.                         assert(this->movementRequestID == result.requestID);
  443.  
  444.                         this->movementRequestID = MovementRequestID();
  445.  
  446.                         if (result == MovementRequestResult::ReachedDestination)
  447.                         {
  448.                                 this->pendingStatus = Success;
  449.                         }
  450.                         else
  451.                         {
  452.                                 this->pendingStatus = Failure;
  453.                         }
  454.                 }
  455.         };
  456.  
  457.         Move()
  458.                 : m_stopWithinDistance(0.0f)
  459.                 , m_stopDistanceVariation(0.0f)
  460.                 , m_destination(Target)
  461.                 , m_fireMode(FIREMODE_OFF)
  462.                 , m_dangersFlags(eMNMDangers_None)
  463.                 , m_considerActorsAsPathObstacles(false)
  464.                 , m_lengthToTrimFromThePathEnd(0.0f)
  465.         {
  466.         }
  467.  
  468.         virtual LoadResult LoadFromXml(const XmlNodeRef& xml, const LoadContext& context) override
  469.         {
  470.                 IF_UNLIKELY (BaseClass::LoadFromXml(xml, context) == LoadFailure)
  471.                         return LoadFailure;
  472.  
  473.                 // Speed? Stance?
  474.                 m_movementStyle.ReadFromXml(xml);
  475.  
  476.                 // Destination? Target/Cover/ReferencePoint
  477.                 s_dictionaries.to.Get(xml, "to", m_destination, true);
  478.                 m_movementStyle.SetMovingToCover(m_destination == Cover);
  479.  
  480.                 xml->getAttr("stopWithinDistance", m_stopWithinDistance);
  481.                 if (m_stopWithinDistance > 0.0f)
  482.                         xml->getAttr("stopDistanceVariation", m_stopDistanceVariation);
  483.  
  484.                 g_fireModeDictionary.fireMode.Get(xml, "fireMode", m_fireMode);
  485.  
  486.                 bool avoidDangers = true;
  487.                 xml->getAttr("avoidDangers", avoidDangers);
  488.  
  489.                 SetupDangersFlagsForDestination(avoidDangers);
  490.  
  491.                 bool avoidGroupMates = true;
  492.                 xml->getAttr("avoidGroupMates", avoidGroupMates);
  493.                 if (avoidGroupMates)
  494.                 {
  495.                         m_dangersFlags |= eMNMDangers_GroupMates;
  496.                 }
  497.  
  498.                 xml->getAttr("considerActorsAsPathObstacles", m_considerActorsAsPathObstacles);
  499.                 xml->getAttr("lengthToTrimFromThePathEnd", m_lengthToTrimFromThePathEnd);
  500.  
  501.                 return LoadSuccess;
  502.         }
  503.  
  504.         virtual void OnInitialize(const UpdateContext& context) override
  505.         {
  506.                 RuntimeData& runtimeData = GetRuntimeData<RuntimeData>(context);
  507.  
  508.                 CPipeUser* pipeUser = GetPipeUser(context);
  509.                 IF_UNLIKELY (!pipeUser)
  510.                 {
  511.                         ErrorReporter(*this, context).LogError("Expected pipe user");
  512.                         return;
  513.                 }
  514.  
  515.                 if (m_fireMode != FIREMODE_OFF)
  516.                         pipeUser->SetFireMode(m_fireMode);
  517.  
  518.                 runtimeData.pendingStatus = Running;
  519.  
  520.                 const Vec3 destinationPosition = DestinationPositionFor(*pipeUser);
  521.  
  522.                 runtimeData.effectiveStopDistanceSq = square(m_stopWithinDistance + cry_random(0.0f, m_stopDistanceVariation));
  523.  
  524.                 if (Distance::Point_PointSq(pipeUser->GetPos(), destinationPosition) < runtimeData.effectiveStopDistanceSq)
  525.                 {
  526.                         runtimeData.pendingStatus = Success;
  527.                         return;
  528.                 }
  529.  
  530.                 RequestMovementTo(destinationPosition, context.entityId, runtimeData,
  531.                                   true); // First time we request a path.
  532.         }
  533.  
  534.         virtual void OnTerminate(const UpdateContext& context) override
  535.         {
  536.                 if (m_fireMode != FIREMODE_OFF)
  537.                 {
  538.                         GetPipeUser(context)->SetFireMode(FIREMODE_OFF);
  539.                 }
  540.  
  541.                 RuntimeData& runtimeData = GetRuntimeData<RuntimeData>(context);
  542.                 runtimeData.ReleaseCurrentMovementRequest();
  543.         }
  544.  
  545. #if defined(USING_BEHAVIOR_TREE_NODE_CUSTOM_DEBUG_TEXT) && defined(COMPILE_WITH_MOVEMENT_SYSTEM_DEBUG)
  546.         virtual void GetCustomDebugText(const UpdateContext& updateContext, stack_string& debugText) const override
  547.         {
  548.                 const RuntimeData& runtimeData = GetRuntimeData<RuntimeData>(updateContext);
  549.                 MovementRequestStatus status;
  550.                 gEnv->pAISystem->GetMovementSystem()->GetRequestStatus(runtimeData.movementRequestID, status);
  551.                 ConstructHumanReadableText(status, debugText);
  552.         }
  553. #endif
  554.  
  555. private:
  556.  
  557.         float           m_stopWithinDistance;
  558.         float           m_stopDistanceVariation;
  559.         MovementStyle   m_movementStyle;
  560.         DestinationType m_destination;
  561.         EFireMode       m_fireMode;
  562.         MNMDangersFlags m_dangersFlags;
  563.         bool            m_considerActorsAsPathObstacles;
  564.         float           m_lengthToTrimFromThePathEnd;
  565.  
  566.         virtual Status Update(const UpdateContext& context) override
  567.         {
  568.                 RuntimeData& runtimeData = GetRuntimeData<RuntimeData>(context);
  569.  
  570.                 if (runtimeData.pendingStatus != Running)
  571.                         return runtimeData.pendingStatus;
  572.  
  573.                 CPipeUser& pipeUser = *GetPipeUser(context);
  574.  
  575.                 if (m_destination == Target || m_destination == LastOp || m_destination == ReferencePoint)
  576.                 {
  577.                         ChaseTarget(pipeUser, context.entityId, runtimeData);
  578.                 }
  579.  
  580.                 const bool stopMovementWhenWithinCertainDistance = runtimeData.effectiveStopDistanceSq > 0.0f;
  581.  
  582.                 if (stopMovementWhenWithinCertainDistance)
  583.                 {
  584.                         if (GetSquaredDistanceToDestination(pipeUser, runtimeData) < runtimeData.effectiveStopDistanceSq)
  585.                         {
  586.                                 runtimeData.ReleaseCurrentMovementRequest();
  587.                                 RequestStop(context.entityId);
  588.                                 return Success;
  589.                         }
  590.                 }
  591.  
  592.                 return Running;
  593.         }
  594.  
  595.         void SetMovementStyle(MovementStyle movementStyle)
  596.         {
  597.                 m_movementStyle = movementStyle;
  598.         }
  599.  
  600.         Vec3 DestinationPositionFor(CPipeUser& pipeUser) const
  601.         {
  602.                 switch (m_destination)
  603.                 {
  604.                 case Target:
  605.                         {
  606.                                 if (IAIObject* target = pipeUser.GetAttentionTarget())
  607.                                 {
  608.                                         const Vec3 targetPosition = target->GetPosInNavigationMesh(pipeUser.GetNavigationTypeID());
  609.                                         Vec3 targetVelocity = target->GetVelocity();
  610.                                         targetVelocity.z = .0f;   // Don't consider z axe for the velocity since it could create problems when finding the location in the navigation mesh later
  611.                                         return targetPosition + targetVelocity * 0.5f;
  612.                                 }
  613.                                 else
  614.                                 {
  615.                                         AIQueueBubbleMessage("Move Node Destination Position",
  616.                                                              pipeUser.GetEntityID(),
  617.                                                              "Move node could set the destination as the target position.",
  618.                                                              eBNS_LogWarning | eBNS_Balloon);
  619.                                         return Vec3(ZERO);
  620.                                 }
  621.                         }
  622.  
  623.                 case Cover:
  624.                         {
  625.                                 return GetCoverRegisterLocation(pipeUser);
  626.                         }
  627.  
  628.                 case ReferencePoint:
  629.                         {
  630.                                 return pipeUser.GetRefPoint()->GetPos();
  631.                         }
  632.  
  633.                 case LastOp:
  634.                         {
  635.                                 CAIObject* lastOpAIObejct = pipeUser.GetLastOpResult();
  636.                                 if (lastOpAIObejct)
  637.                                 {
  638.                                         const Vec3 targetVelocity = lastOpAIObejct->GetVelocity();
  639.                                         const Vec3 targetPosition = lastOpAIObejct->GetPosInNavigationMesh(pipeUser.GetNavigationTypeID());
  640.                                         return targetPosition + targetVelocity * 0.5f;
  641.                                 }
  642.                                 else
  643.                                 {
  644.                                         assert(0);
  645.                                         return Vec3(ZERO);
  646.                                 }
  647.                         }
  648.  
  649.                 case InitialPosition:
  650.                         {
  651.                                 Vec3 initialPosition;
  652.                                 bool initialPositionIsValid = pipeUser.GetInitialPosition(initialPosition);
  653.                                 IF_UNLIKELY (!initialPositionIsValid)
  654.                                 {
  655.                                         return Vec3Constants<float>::fVec3_Zero;
  656.                                 }
  657.                                 return initialPosition;
  658.                         }
  659.  
  660.                 default:
  661.                         {
  662.                                 assert(0);
  663.                                 return Vec3Constants<float>::fVec3_Zero;
  664.                         }
  665.                 }
  666.         }
  667.  
  668.         Vec3 GetCoverRegisterLocation(const CPipeUser& pipeUser) const
  669.         {
  670.                 if (CoverID coverID = pipeUser.GetCoverRegister())
  671.                 {
  672.                         const float distanceToCover = pipeUser.GetParameters().distanceToCover;
  673.                         return gAIEnv.pCoverSystem->GetCoverLocation(coverID, distanceToCover);
  674.                 }
  675.                 else
  676.                 {
  677.                         assert(0);
  678.                         AIQueueBubbleMessage("MoveOp:CoverLocation", pipeUser.GetEntityID(), "MoveOp failed to get the cover location due to an invalid Cover ID in the cover register.", eBNS_LogWarning | eBNS_Balloon | eBNS_BlockingPopup);
  679.                         return Vec3Constants<float>::fVec3_Zero;
  680.                 }
  681.         }
  682.  
  683.         void RequestMovementTo(const Vec3& position, const EntityId entityID, RuntimeData& runtimeData, const bool firstRequest)
  684.         {
  685.                 assert(!runtimeData.movementRequestID);
  686.  
  687.                 MovementRequest movementRequest;
  688.                 movementRequest.entityID = entityID;
  689.                 movementRequest.destination = position;
  690.                 movementRequest.callback = functor(runtimeData, &RuntimeData::MovementRequestCallback);
  691.                 movementRequest.style = m_movementStyle;
  692.                 movementRequest.dangersFlags = m_dangersFlags;
  693.                 movementRequest.considerActorsAsPathObstacles = m_considerActorsAsPathObstacles;
  694.                 movementRequest.lengthToTrimFromThePathEnd = m_lengthToTrimFromThePathEnd;
  695.                 if (!firstRequest)
  696.                 {
  697.                         // While chasing we do not want to trigger a separate turn again while we were
  698.                         // already following an initial path.
  699.                         movementRequest.style.SetTurnTowardsMovementDirectionBeforeMoving(false);
  700.                 }
  701.  
  702.                 runtimeData.movementRequestID = gEnv->pAISystem->GetMovementSystem()->QueueRequest(movementRequest);
  703.  
  704.                 runtimeData.destinationAtTimeOfMovementRequest = position;
  705.         }
  706.  
  707.         void ChaseTarget(CPipeUser& pipeUser, const EntityId entityID, RuntimeData& runtimeData)
  708.         {
  709.                 const Vec3 targetPosition = DestinationPositionFor(pipeUser);
  710.  
  711.                 const float targetDeviation = targetPosition.GetSquaredDistance(runtimeData.destinationAtTimeOfMovementRequest);
  712.                 const float deviationThreshold = square(0.5f);
  713.  
  714.                 if (targetDeviation > deviationThreshold)
  715.                 {
  716.                         runtimeData.ReleaseCurrentMovementRequest();
  717.                         RequestMovementTo(targetPosition, entityID, runtimeData,
  718.                                           false); // No longer the first request.
  719.                 }
  720.         }
  721.  
  722.         float GetSquaredDistanceToDestination(CPipeUser& pipeUser, RuntimeData& runtimeData)
  723.         {
  724.                 const Vec3 destinationPosition = DestinationPositionFor(pipeUser);
  725.                 return destinationPosition.GetSquaredDistance(pipeUser.GetPos());
  726.         }
  727.  
  728.         void RequestStop(const EntityId entityID)
  729.         {
  730.                 MovementRequest movementRequest;
  731.                 movementRequest.entityID = entityID;
  732.                 movementRequest.type = MovementRequest::Stop;
  733.                 gEnv->pAISystem->GetMovementSystem()->QueueRequest(movementRequest);
  734.         }
  735.  
  736.         void SetupDangersFlagsForDestination(bool shouldAvoidDangers)
  737.         {
  738.                 if (!shouldAvoidDangers)
  739.                 {
  740.                         m_dangersFlags = eMNMDangers_None;
  741.                         return;
  742.                 }
  743.  
  744.                 switch (m_destination)
  745.                 {
  746.                 case Target:
  747.                         m_dangersFlags = eMNMDangers_Explosive;
  748.                         break;
  749.                 case Cover:
  750.                 case ReferencePoint:
  751.                 case LastOp:
  752.                 case InitialPosition:
  753.                         m_dangersFlags = eMNMDangers_AttentionTarget | eMNMDangers_Explosive;
  754.                         break;
  755.                 default:
  756.                         assert(0);
  757.                         m_dangersFlags = eMNMDangers_None;
  758.                         break;
  759.                 }
  760.         }
  761. };
  762.  
  763. Move::Dictionaries Move::s_dictionaries;
  764.  
  765. //////////////////////////////////////////////////////////////////////////
  766.  
  767. class QueryTPS : public Action
  768. {
  769.         typedef Action BaseClass;
  770.  
  771. public:
  772.         struct RuntimeData
  773.         {
  774.                 CTacticalPointQueryInstance queryInstance;
  775.                 bool                        queryProcessing;
  776.         };
  777.  
  778.         QueryTPS()
  779.                 : m_register(AI_REG_COVER)
  780.                 , m_queryID(0)
  781.         {
  782.         }
  783.  
  784.         struct Dictionaries
  785.         {
  786.                 CXMLAttrReader<EAIRegister> reg;
  787.  
  788.                 Dictionaries()
  789.                 {
  790.                         reg.Reserve(2);
  791.                         //reg.Add("LastOp",     AI_REG_LASTOP);
  792.                         reg.Add("RefPoint", AI_REG_REFPOINT);
  793.                         //reg.Add("AttTarget",  AI_REG_ATTENTIONTARGET);
  794.                         //reg.Add("Path",       AI_REG_PATH);
  795.                         reg.Add("Cover", AI_REG_COVER);
  796.                 }
  797.         };
  798.  
  799.         static Dictionaries s_dictionaries;
  800.  
  801.         virtual LoadResult LoadFromXml(const XmlNodeRef& xml, const LoadContext& context) override
  802.         {
  803.                 IF_UNLIKELY (BaseClass::LoadFromXml(xml, context) == LoadFailure)
  804.                         return LoadFailure;
  805.  
  806.                 const char* queryName = xml->getAttr("name");
  807.                 m_queryID = queryName ? gEnv->pAISystem->GetTacticalPointSystem()->GetQueryID(queryName) : TPSQueryID(0);
  808.                 if (m_queryID == 0)
  809.                 {
  810.                         gEnv->pLog->LogError("QueryTPS behavior tree node: Query '%s' does not exist (yet). Line %d.", queryName, xml->getLine());
  811.                         return LoadFailure;
  812.                 }
  813.  
  814. #ifdef USING_BEHAVIOR_TREE_NODE_CUSTOM_DEBUG_TEXT
  815.                 m_tpsQueryName = queryName;
  816. #endif
  817.  
  818.                 if (!s_dictionaries.reg.Get(xml, "register", m_register))
  819.                 {
  820.                         gEnv->pLog->LogError("QueryTPS behavior tree node: Missing 'register' attribute, line %d.", xml->getLine());
  821.                         return LoadFailure;
  822.                 }
  823.  
  824.                 return LoadSuccess;
  825.         }
  826.  
  827. #ifdef USING_BEHAVIOR_TREE_NODE_CUSTOM_DEBUG_TEXT
  828.         virtual void GetCustomDebugText(const UpdateContext& updateContext, stack_string& debugText) const
  829.         {
  830.                 debugText = m_tpsQueryName;
  831.         }
  832. #endif
  833.  
  834. protected:
  835.         virtual void OnInitialize(const UpdateContext& context) override
  836.         {
  837.                 CommitQuery(*GetPipeUser(context), context);
  838.         }
  839.  
  840.         virtual void OnTerminate(const UpdateContext& context) override
  841.         {
  842.                 CancelQuery(context);
  843.         }
  844.  
  845.         virtual Status Update(const UpdateContext& context) override
  846.         {
  847.                 RuntimeData& runtimeData = GetRuntimeData<RuntimeData>(context);
  848.  
  849.                 const ETacticalPointQueryState state = runtimeData.queryInstance.GetStatus();
  850.  
  851.                 switch (state)
  852.                 {
  853.                 case eTPSQS_InProgress:
  854.                         return Running;
  855.  
  856.                 case eTPSQS_Success:
  857.                         return HandleSuccess(context, runtimeData);
  858.  
  859.                 case eTPSQS_Fail:
  860.                         return Failure;
  861.  
  862.                 default:
  863.                         assert(false);
  864.                         return Failure;
  865.                 }
  866.         }
  867.  
  868. private:
  869.         void CommitQuery(CPipeUser& pipeUser, const UpdateContext& context)
  870.         {
  871.                 RuntimeData& runtimeData = GetRuntimeData<RuntimeData>(context);
  872.  
  873.                 QueryContext queryContext;
  874.                 InitQueryContextFromActor(&pipeUser, queryContext);
  875.                 runtimeData.queryInstance.SetQueryID(m_queryID);
  876.                 runtimeData.queryInstance.SetContext(queryContext);
  877.                 runtimeData.queryInstance.Execute(eTPQF_LockResults);
  878.                 runtimeData.queryProcessing = true;
  879.         }
  880.  
  881.         void CancelQuery(const UpdateContext& context)
  882.         {
  883.                 RuntimeData& runtimeData = GetRuntimeData<RuntimeData>(context);
  884.  
  885.                 if (runtimeData.queryProcessing)
  886.                 {
  887.                         runtimeData.queryInstance.UnlockResults();
  888.                         runtimeData.queryInstance.Cancel();
  889.                         runtimeData.queryProcessing = false;
  890.                 }
  891.         }
  892.  
  893.         Status HandleSuccess(const UpdateContext& context, RuntimeData& runtimeData)
  894.         {
  895.                 runtimeData.queryInstance.UnlockResults();
  896.                 assert(runtimeData.queryInstance.GetOptionUsed() >= 0);
  897.  
  898.                 CPipeUser& pipeUser = *GetPipeUser(context);
  899.  
  900.                 STacticalPointResult point = runtimeData.queryInstance.GetBestResult();
  901.                 assert(point.IsValid());
  902.  
  903.                 if (m_register == AI_REG_REFPOINT)
  904.                 {
  905.                         if (point.flags & eTPDF_AIObject)
  906.                         {
  907.                                 if (CAIObject* pAIObject = gAIEnv.pObjectContainer->GetAIObject(point.aiObjectId))
  908.                                 {
  909.                                         pipeUser.SetRefPointPos(pAIObject->GetPos(), pAIObject->GetEntityDir());
  910.                                         return Success;
  911.                                 }
  912.                                 else
  913.                                 {
  914.                                         return Failure;
  915.                                 }
  916.                         }
  917.                         else if (point.flags & eTPDF_CoverID)
  918.                         {
  919.                                 pipeUser.SetRefPointPos(point.vPos, Vec3Constants<float>::fVec3_OneY);
  920.                                 return Success;
  921.                         }
  922.  
  923.                         // we can expect a position. vObjDir may not be set if this is not a hidespot, but should be zero.
  924.                         pipeUser.SetRefPointPos(point.vPos, point.vObjDir);
  925.                         return Success;
  926.                 }
  927.                 else if (m_register == AI_REG_COVER)
  928.                 {
  929.                         assert(point.flags & eTPDF_CoverID);
  930.  
  931.                         assert(!gAIEnv.pCoverSystem->IsCoverOccupied(point.coverID) ||
  932.                                (gAIEnv.pCoverSystem->GetCoverOccupant(point.coverID) == pipeUser.GetAIObjectID()));
  933.  
  934.                         pipeUser.SetCoverRegister(point.coverID);
  935.                         return Success;
  936.                 }
  937.                 else
  938.                 {
  939.                         assert(false);
  940.                         return Failure;
  941.                 }
  942.         }
  943.  
  944.         EAIRegister m_register;
  945.         TPSQueryID  m_queryID;
  946.  
  947. #ifdef USING_BEHAVIOR_TREE_NODE_CUSTOM_DEBUG_TEXT
  948.         string m_tpsQueryName;
  949. #endif
  950. };
  951.  
  952. QueryTPS::Dictionaries QueryTPS::s_dictionaries;
  953.  
  954. //////////////////////////////////////////////////////////////////////////
  955.  
  956. // A gate that is open if a snippet of Lua code returns true,
  957. // and closed if the Lua code returns false.
  958. class LuaGate : public Decorator
  959. {
  960. public:
  961.         typedef Decorator BaseClass;
  962.  
  963.         struct RuntimeData
  964.         {
  965.                 bool gateIsOpen;
  966.  
  967.                 RuntimeData() : gateIsOpen(false) {}
  968.         };
  969.  
  970.         virtual LoadResult LoadFromXml(const XmlNodeRef& xml, const LoadContext& context) override
  971.         {
  972.                 const stack_string code = xml->getAttr("code");
  973.                 if (code.empty())
  974.                 {
  975.                         gEnv->pLog->LogError("LuaGate expected the 'code' attribute at line %d.", xml->getLine());
  976.                         return LoadFailure;
  977.                 }
  978.  
  979.                 m_scriptFunction = SmartScriptFunction(gEnv->pScriptSystem, gEnv->pScriptSystem->CompileBuffer(code.c_str(), code.length(), "LuaGate"));
  980.                 if (!m_scriptFunction)
  981.                 {
  982.                         ErrorReporter(*this, context).LogError("Failed to compile Lua code '%s'", code.c_str());
  983.                         return LoadFailure;
  984.                 }
  985.  
  986.                 return LoadChildFromXml(xml, context);
  987.         }
  988.  
  989. protected:
  990.         virtual void OnInitialize(const UpdateContext& context) override
  991.         {
  992.                 FUNCTION_PROFILER(gEnv->pSystem, PROFILE_AI);
  993.  
  994.                 assert(m_scriptFunction != NULL);
  995.  
  996.                 RuntimeData& runtimeData = GetRuntimeData<RuntimeData>(context);
  997.  
  998.                 runtimeData.gateIsOpen = false;
  999.  
  1000.                 if (IEntity* entity = gEnv->pEntitySystem->GetEntity(context.entityId))
  1001.                 {
  1002.                         gEnv->pScriptSystem->SetGlobalValue("entity", entity->GetScriptTable());
  1003.  
  1004.                         bool luaReturnValue = false;
  1005.                         Script::CallReturn(gEnv->pScriptSystem, m_scriptFunction, luaReturnValue);
  1006.                         if (luaReturnValue)
  1007.                                 runtimeData.gateIsOpen = true;
  1008.  
  1009.                         gEnv->pScriptSystem->SetGlobalToNull("entity");
  1010.  
  1011.                 }
  1012.         }
  1013.  
  1014.         virtual Status Update(const UpdateContext& context) override
  1015.         {
  1016.                 RuntimeData& runtimeData = GetRuntimeData<RuntimeData>(context);
  1017.  
  1018.                 if (runtimeData.gateIsOpen)
  1019.                         return BaseClass::Update(context);
  1020.                 else
  1021.                         return Failure;
  1022.         }
  1023.  
  1024. private:
  1025.         SmartScriptFunction m_scriptFunction;
  1026. };
  1027.  
  1028. //////////////////////////////////////////////////////////////////////////
  1029.  
  1030. class AdjustCoverStance : public Action
  1031. {
  1032. public:
  1033.         struct RuntimeData
  1034.         {
  1035.                 Timer timer;
  1036.         };
  1037.  
  1038.         AdjustCoverStance()
  1039.                 : m_duration(0.0f)
  1040.                 , m_variation(0.0f)
  1041.         {
  1042.         }
  1043.  
  1044.         virtual LoadResult LoadFromXml(const XmlNodeRef& xml, const LoadContext& context)
  1045.         {
  1046.                 const stack_string str = xml->getAttr("duration");
  1047.  
  1048.                 if (str == "continuous")
  1049.                         m_duration = -1.0;
  1050.                 else
  1051.                 {
  1052.                         xml->getAttr("duration", m_duration);
  1053.                         xml->getAttr("variation", m_variation);
  1054.                 }
  1055.  
  1056.                 return LoadSuccess;
  1057.         }
  1058.  
  1059.         virtual void OnInitialize(const UpdateContext& context)
  1060.         {
  1061.                 if (m_duration >= 0.0f)
  1062.                 {
  1063.                         RuntimeData& runtimeData = GetRuntimeData<RuntimeData>(context);
  1064.                         runtimeData.timer.Reset(m_duration, m_variation);
  1065.                 }
  1066.  
  1067.                 CPipeUser* pipeUser = GetPipeUser(context);
  1068.                 ClearCoverPosture(pipeUser);
  1069.         }
  1070.  
  1071.         virtual Status Update(const UpdateContext& context)
  1072.         {
  1073.                 CPipeUser& pipeUser = *GetPipeUser(context);
  1074.  
  1075.                 if (pipeUser.IsInCover())
  1076.                 {
  1077.                         RuntimeData& runtimeData = GetRuntimeData<RuntimeData>(context);
  1078.  
  1079.                         const CoverHeight coverHeight = pipeUser.CalculateEffectiveCoverHeight();
  1080.                         pipeUser.m_State.bodystate = (coverHeight == HighCover) ? STANCE_HIGH_COVER : STANCE_LOW_COVER;
  1081.                         return runtimeData.timer.Elapsed() ? Success : Running;
  1082.                 }
  1083.                 else
  1084.                 {
  1085.                         return Failure;
  1086.                 }
  1087.         }
  1088.  
  1089. #ifdef USING_BEHAVIOR_TREE_NODE_CUSTOM_DEBUG_TEXT
  1090.         virtual void GetCustomDebugText(const UpdateContext& updateContext, stack_string& debugText) const
  1091.         {
  1092.                 if (m_duration == -1.0f)
  1093.                 {
  1094.                         debugText.Format("continuous");
  1095.                 }
  1096.                 else
  1097.                 {
  1098.                         const RuntimeData& runtimeData = GetRuntimeData<RuntimeData>(updateContext);
  1099.                         debugText.Format("%0.1f (%0.1f)", runtimeData.timer.GetSecondsLeft(), m_duration);
  1100.                 }
  1101.         }
  1102. #endif
  1103.  
  1104. private:
  1105.         void ClearCoverPosture(CPipeUser* pipeUser)
  1106.         {
  1107.                 assert(pipeUser);
  1108.                 pipeUser->GetProxy()->ResetAGInput(AIAG_ACTION);
  1109.                 pipeUser->m_State.lean = 0;
  1110.                 pipeUser->m_State.peekOver = 0;
  1111.                 pipeUser->m_State.coverRequest.ClearCoverAction();
  1112.         }
  1113.  
  1114.         float m_duration;
  1115.         float m_variation;
  1116.         Timer m_timer;
  1117. };
  1118.  
  1119. //////////////////////////////////////////////////////////////////////////
  1120.  
  1121. class SetAlertness : public Action
  1122. {
  1123. public:
  1124.         typedef Action BaseClass;
  1125.  
  1126.         struct RuntimeData
  1127.         {
  1128.         };
  1129.  
  1130.         SetAlertness()
  1131.                 : m_alertness(0)
  1132.         {
  1133.         }
  1134.  
  1135.         virtual LoadResult LoadFromXml(const XmlNodeRef& xml, const LoadContext& context) override
  1136.         {
  1137.                 if (BaseClass::LoadFromXml(xml, context) == LoadFailure)
  1138.                         return LoadFailure;
  1139.  
  1140.                 xml->getAttr("value", m_alertness);
  1141.  
  1142.                 if (m_alertness >= 0 && m_alertness <= 2)
  1143.                 {
  1144.                         return LoadSuccess;
  1145.                 }
  1146.                 else
  1147.                 {
  1148.                         gEnv->pLog->LogError("Alertness '%d' on line %d is invalid. Can only be 0, 1 or 2.", m_alertness, xml->getLine());
  1149.                         return LoadFailure;
  1150.                 }
  1151.         }
  1152.  
  1153. protected:
  1154.         virtual Status Update(const UpdateContext& context) override
  1155.         {
  1156.                 IAIActorProxy* proxy = GetPipeUser(context)->GetProxy();
  1157.  
  1158.                 if (proxy)
  1159.                         proxy->SetAlertnessState(m_alertness);
  1160.  
  1161.                 return Success;
  1162.         }
  1163.  
  1164. private:
  1165.         int m_alertness;
  1166. };
  1167.  
  1168. //////////////////////////////////////////////////////////////////////////
  1169.  
  1170. class Communicate : public Action
  1171. {
  1172.         typedef Action BaseClass;
  1173. public:
  1174.         struct RuntimeData : public ICommunicationManager::ICommInstanceListener
  1175.         {
  1176.                 CTimeValue startTime;
  1177.                 CommPlayID playID;
  1178.                 bool       commFinished; // Set on communication end
  1179.  
  1180.                 RuntimeData()
  1181.                         : startTime(0.0f)
  1182.                         , playID(0)
  1183.                         , commFinished(false)
  1184.                 {
  1185.                 }
  1186.  
  1187.                 ~RuntimeData()
  1188.                 {
  1189.                         UnregisterListener();
  1190.                 }
  1191.  
  1192.                 void UnregisterListener()
  1193.                 {
  1194.                         if (this->playID)
  1195.                         {
  1196.                                 gEnv->pAISystem->GetCommunicationManager()->RemoveInstanceListener(this->playID);
  1197.                                 this->playID = CommPlayID(0);
  1198.                         }
  1199.                 }
  1200.  
  1201.                 void OnCommunicationEvent(
  1202.                   ICommunicationManager::ECommunicationEvent event,
  1203.                   EntityId actorID, const CommPlayID& _playID)
  1204.                 {
  1205.                         switch (event)
  1206.                         {
  1207.                         case ICommunicationManager::CommunicationCancelled:
  1208.                         case ICommunicationManager::CommunicationFinished:
  1209.                         case ICommunicationManager::CommunicationExpired:
  1210.                                 {
  1211.                                         if (this->playID == _playID)
  1212.                                         {
  1213.                                                 this->commFinished = true;
  1214.                                         }
  1215.                                         else
  1216.                                         {
  1217.                                                 AIWarning("Communicate behavior node received event for a communication not matching requested playID.");
  1218.                                         }
  1219.                                 }
  1220.                                 break;
  1221.                         default:
  1222.                                 break;
  1223.                         }
  1224.                 }
  1225.         };
  1226.  
  1227.         Communicate()
  1228.                 : m_channelID(0)
  1229.                 , m_commID(0)
  1230.                 , m_ordering(SCommunicationRequest::Unordered)
  1231.                 , m_expiry(0.0f)
  1232.                 , m_minSilence(-1.0f)
  1233.                 , m_ignoreSound(false)
  1234.                 , m_ignoreAnim(false)
  1235.                 , m_timeout(8.0f)
  1236.                 , m_waitUntilFinished(true)
  1237.         {
  1238.         }
  1239.  
  1240.         virtual LoadResult LoadFromXml(const XmlNodeRef& xml, const LoadContext& context) override
  1241.         {
  1242.                 IF_UNLIKELY (BaseClass::LoadFromXml(xml, context) == LoadFailure)
  1243.                         return LoadFailure;
  1244.  
  1245.                 ICommunicationManager* communicationManager = gEnv->pAISystem->GetCommunicationManager();
  1246.  
  1247.                 const char* commName;
  1248.                 if (xml->getAttr("name", &commName))
  1249.                 {
  1250.                         m_commID = communicationManager->GetCommunicationID(commName);
  1251.                         if (!communicationManager->GetCommunicationName(m_commID))
  1252.                         {
  1253.                                 ErrorReporter(*this, context).LogError("Unknown communication name '%s'", commName);
  1254.                                 m_commID = CommID(0);
  1255.                                 return LoadFailure;
  1256.                         }
  1257.                 }
  1258.                 else
  1259.                 {
  1260.                         ErrorReporter(*this, context).LogError("Attribute 'name' is missing or empty.");
  1261.                         return LoadFailure;
  1262.                 }
  1263.  
  1264.                 const char* channelName;
  1265.                 if (xml->getAttr("channel", &channelName))
  1266.                 {
  1267.                         m_channelID = communicationManager->GetChannelID(channelName);
  1268.                         if (!m_channelID)
  1269.                         {
  1270.                                 ErrorReporter(*this, context).LogError("Unknown channel name '%s'", channelName);
  1271.                                 return LoadFailure;
  1272.                         }
  1273.                 }
  1274.                 else
  1275.                 {
  1276.                         ErrorReporter(*this, context).LogError("Attribute 'name' is missing or empty.");
  1277.                         return LoadFailure;
  1278.                 }
  1279.  
  1280.                 if (xml->haveAttr("waitUntilFinished"))
  1281.                         xml->getAttr("waitUntilFinished", m_waitUntilFinished);
  1282.  
  1283.                 if (xml->haveAttr("timeout"))
  1284.                         xml->getAttr("timeout", m_timeout);
  1285.  
  1286.                 if (xml->haveAttr("expiry"))
  1287.                         xml->getAttr("expiry", m_expiry);
  1288.  
  1289.                 if (xml->haveAttr("minSilence"))
  1290.                         xml->getAttr("minSilence", m_minSilence);
  1291.  
  1292.                 if (xml->haveAttr("ignoreSound"))
  1293.                         xml->getAttr("ignoreSound", m_ignoreSound);
  1294.  
  1295.                 if (xml->haveAttr("ignoreAnim"))
  1296.                         xml->getAttr("ignoreAnim", m_ignoreAnim);
  1297.  
  1298.                 return LoadSuccess;
  1299.         }
  1300.  
  1301. protected:
  1302.         virtual void OnInitialize(const UpdateContext& context) override
  1303.         {
  1304.                 FUNCTION_PROFILER(gEnv->pSystem, PROFILE_AI);
  1305.  
  1306.                 RuntimeData& runtimeData = GetRuntimeData<RuntimeData>(context);
  1307.  
  1308.                 runtimeData.startTime = GetAISystem()->GetFrameStartTime();
  1309.                 runtimeData.commFinished = false;
  1310.  
  1311.                 ICommunicationManager& commManager = *gEnv->pAISystem->GetCommunicationManager();
  1312.  
  1313.                 SCommunicationRequest request;
  1314.                 request.channelID = m_channelID;
  1315.                 request.commID = m_commID;
  1316.                 request.contextExpiry = m_expiry;
  1317.                 request.minSilence = m_minSilence;
  1318.                 request.ordering = m_ordering;
  1319.                 request.skipCommAnimation = m_ignoreAnim;
  1320.                 request.skipCommSound = m_ignoreSound;
  1321.  
  1322.                 if (m_waitUntilFinished)
  1323.                         request.eventListener = &runtimeData;
  1324.  
  1325.                 IAIActorProxy* proxy = GetPipeUser(context)->GetProxy();
  1326.                 IF_UNLIKELY (!proxy)
  1327.                 {
  1328.                         ErrorReporter(*this, context).LogError("Communication failed to start, agent did not have a valid AI proxy.");
  1329.                         return;
  1330.                 }
  1331.  
  1332.                 request.configID = commManager.GetConfigID(proxy->GetCommunicationConfigName());
  1333.                 request.actorID = context.entityId;
  1334.  
  1335.                 runtimeData.playID = commManager.PlayCommunication(request);
  1336.  
  1337.                 if (!runtimeData.playID)
  1338.                 {
  1339.                         ErrorReporter(*this, context).LogWarning("Communication failed to start.");
  1340.                 }
  1341.         }
  1342.  
  1343.         virtual void OnTerminate(const UpdateContext& context) override
  1344.         {
  1345.                 RuntimeData& runtimeData = GetRuntimeData<RuntimeData>(context);
  1346.                 runtimeData.UnregisterListener();
  1347.         }
  1348.  
  1349.         virtual Status Update(const UpdateContext& context) override
  1350.         {
  1351.                 RuntimeData& runtimeData = GetRuntimeData<RuntimeData>(context);
  1352.  
  1353.                 // If we've received a callback, then return success
  1354.                 if (runtimeData.commFinished || !m_waitUntilFinished)
  1355.                 {
  1356.                         return Success;
  1357.                 }
  1358.  
  1359.                 // Time out if angle threshold isn't reached for some time (to avoid deadlocks)
  1360.                 float elapsedTime = (GetAISystem()->GetFrameStartTime() - runtimeData.startTime).GetSeconds();
  1361.                 if (elapsedTime > m_timeout)
  1362.                 {
  1363.                         ErrorReporter(*this, context).LogWarning("Communication timed out.");
  1364.                         return Success;
  1365.                 }
  1366.  
  1367.                 return Running;
  1368.         }
  1369.  
  1370. private:
  1371.  
  1372.         CommID                           m_commID;
  1373.         CommChannelID                    m_channelID;
  1374.         SCommunicationRequest::EOrdering m_ordering;
  1375.         float                            m_expiry;
  1376.         float                            m_minSilence;
  1377.         float                            m_timeout;
  1378.         bool                             m_ignoreSound;
  1379.         bool                             m_ignoreAnim;
  1380.         bool                             m_waitUntilFinished;
  1381. };
  1382.  
  1383. //////////////////////////////////////////////////////////////////////////
  1384.  
  1385. class Animate : public Action
  1386. {
  1387.         typedef Action BaseClass;
  1388.  
  1389. public:
  1390.         enum PlayMode
  1391.         {
  1392.                 PlayOnce = 0,
  1393.                 InfiniteLoop
  1394.         };
  1395.  
  1396.         struct RuntimeData
  1397.         {
  1398.                 bool signalWasSet;
  1399.  
  1400.                 RuntimeData() : signalWasSet(false) {}
  1401.         };
  1402.  
  1403.         struct ConfigurationData
  1404.         {
  1405.                 string   m_name;
  1406.                 PlayMode m_playMode;
  1407.                 bool     m_urgent;
  1408.                 bool     m_setBodyDirectionTowardsAttentionTarget;
  1409.  
  1410.                 ConfigurationData()
  1411.                         : m_name("")
  1412.                         , m_playMode(PlayOnce)
  1413.                         , m_urgent(true)
  1414.                         , m_setBodyDirectionTowardsAttentionTarget(false)
  1415.                 {
  1416.                 }
  1417.  
  1418.                 LoadResult LoadFromXml(const XmlNodeRef& xml, const LoadContext& context)
  1419.                 {
  1420.                         m_name = xml->getAttr("name");
  1421.                         IF_UNLIKELY (m_name.empty())
  1422.                         {
  1423.                                 gEnv->pLog->LogError("Empty or missing 'name' attribute for Animate node at line %d.", xml->getLine());
  1424.                                 return LoadFailure;
  1425.                         }
  1426.  
  1427.                         xml->getAttr("urgent", m_urgent);
  1428.  
  1429.                         bool loop = false;
  1430.                         xml->getAttr("loop", loop);
  1431.                         m_playMode = loop ? InfiniteLoop : PlayOnce;
  1432.  
  1433.                         xml->getAttr("setBodyDirectionTowardsAttentionTarget", m_setBodyDirectionTowardsAttentionTarget);
  1434.  
  1435.                         return LoadSuccess;
  1436.                 }
  1437.         };
  1438.  
  1439.         virtual LoadResult LoadFromXml(const XmlNodeRef& xml, const LoadContext& context) override
  1440.         {
  1441.                 IF_UNLIKELY (BaseClass::LoadFromXml(xml, context) == LoadFailure)
  1442.                         return LoadFailure;
  1443.  
  1444.                 return m_configurationData.LoadFromXml(xml, context);
  1445.         }
  1446.  
  1447. #ifdef USING_BEHAVIOR_TREE_NODE_CUSTOM_DEBUG_TEXT
  1448.         virtual void GetCustomDebugText(const UpdateContext& updateContext, stack_string& debugText) const override
  1449.         {
  1450.                 debugText = m_configurationData.m_name;
  1451.         }
  1452. #endif
  1453.  
  1454. protected:
  1455.         virtual void OnInitialize(const UpdateContext& context) override
  1456.         {
  1457.                 RuntimeData& runtimeData = GetRuntimeData<RuntimeData>(context);
  1458.  
  1459.                 CPipeUser* pipeUser = GetPipeUser(context);
  1460.                 IAIActorProxy* proxy = pipeUser->GetProxy();
  1461.                 runtimeData.signalWasSet = proxy->SetAGInput(GetAGInputMode(), m_configurationData.m_name, m_configurationData.m_urgent);
  1462.  
  1463.                 assert(runtimeData.signalWasSet);
  1464.                 IF_UNLIKELY (!runtimeData.signalWasSet)
  1465.                         gEnv->pLog->LogError("Animate behavior tree node failed call to SetAGInput(%i, %s).", GetAGInputMode(), m_configurationData.m_name.c_str());
  1466.  
  1467.                 if (m_configurationData.m_setBodyDirectionTowardsAttentionTarget)
  1468.                 {
  1469.                         if (IAIObject* target = pipeUser->GetAttentionTarget())
  1470.                         {
  1471.                                 pipeUser->SetBodyTargetDir((target->GetPos() - pipeUser->GetPos()).GetNormalizedSafe());
  1472.                         }
  1473.                 }
  1474.         }
  1475.  
  1476.         virtual void OnTerminate(const UpdateContext& context) override
  1477.         {
  1478.                 CPipeUser* pipeUser = GetPipeUser(context);
  1479.  
  1480.                 if (m_configurationData.m_setBodyDirectionTowardsAttentionTarget)
  1481.                 {
  1482.                         pipeUser->ResetBodyTargetDir();
  1483.                 }
  1484.  
  1485.                 IAIActorProxy* proxy = pipeUser->GetProxy();
  1486.                 proxy->ResetAGInput(GetAGInputMode());
  1487.  
  1488.                 switch (m_configurationData.m_playMode)
  1489.                 {
  1490.                 case PlayOnce:
  1491.                         proxy->SetAGInput(AIAG_SIGNAL, "none", true);
  1492.                         break;
  1493.  
  1494.                 case InfiniteLoop:
  1495.                         proxy->SetAGInput(AIAG_ACTION, "idle", true);
  1496.                         break;
  1497.                 }
  1498.         }
  1499.  
  1500.         virtual Status Update(const UpdateContext& context) override
  1501.         {
  1502.                 RuntimeData& runtimeData = GetRuntimeData<RuntimeData>(context);
  1503.                 IF_UNLIKELY (!runtimeData.signalWasSet)
  1504.                         return Success;
  1505.  
  1506.                 if (m_configurationData.m_playMode == PlayOnce)
  1507.                 {
  1508.                         IAIActorProxy* proxy = GetPipeUser(context)->GetProxy();
  1509.                         if (proxy->IsSignalAnimationPlayed(m_configurationData.m_name))
  1510.                                 return Success;
  1511.                 }
  1512.  
  1513.                 return Running;
  1514.         }
  1515.  
  1516. private:
  1517.         EAIAGInput GetAGInputMode() const
  1518.         {
  1519.                 switch (m_configurationData.m_playMode)
  1520.                 {
  1521.                 case PlayOnce:
  1522.                         return AIAG_SIGNAL;
  1523.  
  1524.                 case InfiniteLoop:
  1525.                         return AIAG_ACTION;
  1526.  
  1527.                 default:
  1528.                         break;
  1529.                 }
  1530.  
  1531.                 // We should never get here!
  1532.                 assert(false);
  1533.                 return AIAG_SIGNAL;
  1534.         }
  1535.  
  1536. private:
  1537.         ConfigurationData m_configurationData;
  1538. };
  1539.  
  1540. //////////////////////////////////////////////////////////////////////////
  1541.  
  1542. class Signal : public Action
  1543. {
  1544.         typedef Action BaseClass;
  1545.  
  1546. private:
  1547.         struct Dictionaries
  1548.         {
  1549.                 CXMLAttrReader<ESignalFilter> filters;
  1550.  
  1551.                 Dictionaries()
  1552.                 {
  1553.                         filters.Reserve(2);
  1554.                         filters.Add("Sender", SIGNALFILTER_SENDER);
  1555.                         filters.Add("Group", SIGNALFILTER_GROUPONLY);
  1556.                         filters.Add("GroupExcludingSender", SIGNALFILTER_GROUPONLY_EXCEPT);
  1557.                 }
  1558.         };
  1559.  
  1560.         static Dictionaries s_signalDictionaries;
  1561.  
  1562. public:
  1563.         struct RuntimeData
  1564.         {
  1565.         };
  1566.  
  1567.         Signal()
  1568.                 : m_filter(SIGNALFILTER_SENDER)
  1569.         {
  1570.         }
  1571.  
  1572.         virtual LoadResult LoadFromXml(const XmlNodeRef& xml, const LoadContext& context) override
  1573.         {
  1574.                 IF_UNLIKELY (BaseClass::LoadFromXml(xml, context) == LoadFailure)
  1575.                         return LoadFailure;
  1576.  
  1577.                 m_signalName = xml->getAttr("name");
  1578.                 s_signalDictionaries.filters.Get(xml, "filter", m_filter);
  1579.                 return LoadSuccess;
  1580.         }
  1581.  
  1582. #ifdef USING_BEHAVIOR_TREE_NODE_CUSTOM_DEBUG_TEXT
  1583.         virtual void GetCustomDebugText(const UpdateContext& updateContext, stack_string& debugText) const override
  1584.         {
  1585.                 debugText = m_signalName;
  1586.         }
  1587. #endif
  1588.  
  1589. protected:
  1590.         virtual void OnInitialize(const UpdateContext& context) override
  1591.         {
  1592.                 SendSignal(context);
  1593.         }
  1594.  
  1595.         virtual Status Update(const UpdateContext& context) override
  1596.         {
  1597.                 return Success;
  1598.         }
  1599.  
  1600.         void SendSignal(const UpdateContext& context)
  1601.         {
  1602.                 if (CPipeUser* pipeUser = GetPipeUser(context))
  1603.                 {
  1604.                         GetAISystem()->SendSignal(m_filter, 1, m_signalName.c_str(), pipeUser,
  1605.                                                   NULL, CCrc32::Compute(m_signalName.c_str()));
  1606.                 }
  1607.                 else
  1608.                 {
  1609.                         ErrorReporter(*this, context).LogError("Expected agent to be pipe user but it wasn't.");
  1610.                 }
  1611.         }
  1612.  
  1613. private:
  1614.         string        m_signalName;
  1615.         ESignalFilter m_filter;
  1616. };
  1617.  
  1618. Signal::Dictionaries Signal::s_signalDictionaries;
  1619.  
  1620. //////////////////////////////////////////////////////////////////////////
  1621.  
  1622. class SendTransitionSignal : public Signal
  1623. {
  1624. public:
  1625.         virtual Status Update(const UpdateContext& context) override
  1626.         {
  1627.                 return Running;
  1628.         }
  1629. };
  1630.  
  1631. //////////////////////////////////////////////////////////////////////////
  1632.  
  1633. struct Dictionaries
  1634. {
  1635.         CXMLAttrReader<EStance> stances;
  1636.  
  1637.         Dictionaries()
  1638.         {
  1639.                 stances.Reserve(4);
  1640.                 stances.Add("Stand", STANCE_STAND);
  1641.                 stances.Add("Crouch", STANCE_CROUCH);
  1642.                 stances.Add("Relaxed", STANCE_RELAXED);
  1643.                 stances.Add("Alerted", STANCE_ALERTED);
  1644.         }
  1645. };
  1646.  
  1647. Dictionaries s_stanceDictionary;
  1648.  
  1649. class Stance : public Action
  1650. {
  1651. public:
  1652.         struct RuntimeData
  1653.         {
  1654.         };
  1655.  
  1656.         Stance()
  1657.                 : m_stance(STANCE_STAND)
  1658.                 , m_stanceToUseIfSlopeIsTooSteep(STANCE_STAND)
  1659.                 , m_allowedSlopeNormalDeviationFromUpInRadians(0.0f)
  1660.         {
  1661.         }
  1662.  
  1663.         virtual LoadResult LoadFromXml(const XmlNodeRef& xml, const LoadContext& context) override
  1664.         {
  1665.                 s_stanceDictionary.stances.Get(xml, "name", m_stance);
  1666.  
  1667.                 float degrees = 90.0f;
  1668.                 xml->getAttr("allowedSlopeNormalDeviationFromUpInDegrees", degrees);
  1669.                 m_allowedSlopeNormalDeviationFromUpInRadians = DEG2RAD(degrees);
  1670.  
  1671.                 s_stanceDictionary.stances.Get(xml, "stanceToUseIfSlopeIsTooSteep", m_stanceToUseIfSlopeIsTooSteep);
  1672.  
  1673.                 return LoadSuccess;
  1674.         }
  1675.  
  1676. protected:
  1677.         virtual Status Update(const UpdateContext& context) override
  1678.         {
  1679.                 EStance slopeVerifiedStance = m_stance;
  1680.  
  1681.                 if (IEntity* entity = gEnv->pEntitySystem->GetEntity(context.entityId))
  1682.                 {
  1683.                         if (IPhysicalEntity* physicalEntity = entity->GetPhysics())
  1684.                         {
  1685.                                 const Vec3& up = Vec3Constants<float>::fVec3_OneZ;
  1686.  
  1687.                                 Vec3 groundNormal = up;
  1688.  
  1689.                                 if (physicalEntity && physicalEntity->GetType() == PE_LIVING)
  1690.                                 {
  1691.                                         pe_status_living status;
  1692.                                         if (physicalEntity->GetStatus(&status) > 0)
  1693.                                         {
  1694.                                                 if (!status.groundSlope.IsZero() && status.groundSlope.IsValid())
  1695.                                                 {
  1696.                                                         groundNormal = status.groundSlope;
  1697.                                                         groundNormal.NormalizeSafe(up);
  1698.                                                 }
  1699.                                         }
  1700.                                 }
  1701.  
  1702.                                 if (acosf(clamp_tpl(groundNormal.Dot(up), -1.0f, +1.0f)) > m_allowedSlopeNormalDeviationFromUpInRadians)
  1703.                                 {
  1704.                                         slopeVerifiedStance = m_stanceToUseIfSlopeIsTooSteep;
  1705.                                 }
  1706.                         }
  1707.                 }
  1708.  
  1709.                 CPipeUser* pipeUser = GetPipeUser(context);
  1710.                 pipeUser->m_State.bodystate = slopeVerifiedStance;
  1711.                 return Success;
  1712.         }
  1713.  
  1714. private:
  1715.         EStance m_stance;
  1716.         EStance m_stanceToUseIfSlopeIsTooSteep;
  1717.         float   m_allowedSlopeNormalDeviationFromUpInRadians;
  1718. };
  1719.  
  1720. //////////////////////////////////////////////////////////////////////////
  1721.  
  1722. class LuaWrapper : public Decorator
  1723. {
  1724.         typedef Decorator BaseClass;
  1725.  
  1726. public:
  1727.         struct RuntimeData
  1728.         {
  1729.                 EntityId    entityId;
  1730.                 bool        executeExitScriptIfDestructed;
  1731.                 LuaWrapper* node;
  1732.  
  1733.                 RuntimeData()
  1734.                         : entityId(0)
  1735.                         , executeExitScriptIfDestructed(false)
  1736.                         , node(NULL)
  1737.                 {
  1738.                 }
  1739.  
  1740.                 ~RuntimeData()
  1741.                 {
  1742.                         if (this->executeExitScriptIfDestructed && this->node)
  1743.                         {
  1744.                                 this->node->ExecuteExitScript(*this);
  1745.  
  1746.                                 this->node = NULL;
  1747.                                 this->entityId = 0;
  1748.                                 this->executeExitScriptIfDestructed = false;
  1749.                         }
  1750.                 }
  1751.         };
  1752.  
  1753.         virtual LoadResult LoadFromXml(const XmlNodeRef& xml, const LoadContext& context) override
  1754.         {
  1755.                 stack_string enterCode = xml->getAttr("onEnter");
  1756.                 stack_string exitCode = xml->getAttr("onExit");
  1757.  
  1758.                 if (!enterCode.empty())
  1759.                         m_enterScriptFunction.reset(gEnv->pScriptSystem, gEnv->pScriptSystem->CompileBuffer(enterCode.c_str(), enterCode.length(), "LuaWrapper - enter"));
  1760.  
  1761.                 if (!exitCode.empty())
  1762.                         m_exitScriptFunction.reset(gEnv->pScriptSystem, gEnv->pScriptSystem->CompileBuffer(exitCode.c_str(), exitCode.length(), "LuaWrapper - exit"));
  1763.  
  1764.                 return LoadChildFromXml(xml, context);
  1765.         }
  1766.  
  1767.         void ExecuteEnterScript(RuntimeData& runtimeData)
  1768.         {
  1769.                 ExecuteScript(m_enterScriptFunction, runtimeData.entityId);
  1770.  
  1771.                 runtimeData.entityId = runtimeData.entityId;
  1772.                 runtimeData.executeExitScriptIfDestructed = true;
  1773.         }
  1774.  
  1775.         void ExecuteExitScript(RuntimeData& runtimeData)
  1776.         {
  1777.                 ExecuteScript(m_exitScriptFunction, runtimeData.entityId);
  1778.  
  1779.                 runtimeData.executeExitScriptIfDestructed = false;
  1780.         }
  1781.  
  1782. protected:
  1783.         virtual void OnInitialize(const UpdateContext& context) override
  1784.         {
  1785.                 BaseClass::OnInitialize(context);
  1786.  
  1787.                 RuntimeData& runtimeData = GetRuntimeData<RuntimeData>(context);
  1788.                 runtimeData.node = this;
  1789.                 runtimeData.entityId = context.entityId;
  1790.                 ExecuteEnterScript(runtimeData);
  1791.         }
  1792.  
  1793.         virtual void OnTerminate(const UpdateContext& context) override
  1794.         {
  1795.                 BaseClass::OnTerminate(context);
  1796.  
  1797.                 RuntimeData& runtimeData = GetRuntimeData<RuntimeData>(context);
  1798.                 ExecuteExitScript(runtimeData);
  1799.         }
  1800.  
  1801. private:
  1802.         void ExecuteScript(SmartScriptFunction scriptFunction, EntityId entityId)
  1803.         {
  1804.                 if (scriptFunction)
  1805.                 {
  1806.                         IEntity* entity = gEnv->pEntitySystem->GetEntity(entityId);
  1807.                         IF_UNLIKELY (!entity)
  1808.                         {
  1809.                                 return;
  1810.                         }
  1811.  
  1812.                         IScriptSystem* scriptSystem = gEnv->pScriptSystem;
  1813.                         scriptSystem->SetGlobalValue("entity", entity->GetScriptTable());
  1814.                         Script::Call(scriptSystem, scriptFunction);
  1815.                         scriptSystem->SetGlobalToNull("entity");
  1816.                 }
  1817.         }
  1818.  
  1819.         SmartScriptFunction m_enterScriptFunction;
  1820.         SmartScriptFunction m_exitScriptFunction;
  1821. };
  1822.  
  1823. //////////////////////////////////////////////////////////////////////////
  1824.  
  1825. class ExecuteLua : public Action
  1826. {
  1827. public:
  1828.         struct RuntimeData
  1829.         {
  1830.         };
  1831.  
  1832.         virtual LoadResult LoadFromXml(const XmlNodeRef& xml, const LoadContext& context) override
  1833.         {
  1834.                 IF_UNLIKELY (Action::LoadFromXml(xml, context) == LoadFailure)
  1835.                         return LoadFailure;
  1836.  
  1837.                 const stack_string code = xml->getAttr("code");
  1838.                 IF_UNLIKELY (code.empty())
  1839.                 {
  1840.                         gEnv->pLog->LogError("ExecuteLua node on line %d must have some Lua code in the 'code' attribute.", xml->getLine());
  1841.                         return LoadFailure;
  1842.                 }
  1843.  
  1844.                 m_scriptFunction.reset(gEnv->pScriptSystem, gEnv->pScriptSystem->CompileBuffer(code.c_str(), code.length(), "ExecuteLua behavior tree node"));
  1845.                 return m_scriptFunction ? LoadSuccess : LoadFailure;
  1846.         }
  1847.  
  1848. protected:
  1849.         virtual Status Update(const UpdateContext& context) override
  1850.         {
  1851.                 FUNCTION_PROFILER(gEnv->pSystem, PROFILE_AI);
  1852.                 ExecuteScript(m_scriptFunction, context.entityId);
  1853.                 return Success;
  1854.         }
  1855.  
  1856. private:
  1857.         void ExecuteScript(SmartScriptFunction scriptFunction, const EntityId entityId) const
  1858.         {
  1859.                 IEntity* entity = gEnv->pEntitySystem->GetEntity(entityId);
  1860.                 IF_UNLIKELY (!entity)
  1861.                         return;
  1862.  
  1863.                 IScriptSystem* scriptSystem = gEnv->pScriptSystem;
  1864.                 scriptSystem->SetGlobalValue("entity", entity->GetScriptTable());
  1865.                 Script::Call(scriptSystem, scriptFunction);
  1866.                 scriptSystem->SetGlobalToNull("entity");
  1867.         }
  1868.  
  1869.         SmartScriptFunction m_scriptFunction;
  1870. };
  1871.  
  1872. //////////////////////////////////////////////////////////////////////////
  1873.  
  1874. // Executes Lua code and translates the return value of that code
  1875. // from true/false to success/failure. It can then be used to build
  1876. // preconditions in the modular behavior tree.
  1877. class AssertLua : public Action
  1878. {
  1879.         typedef Action BaseClass;
  1880.  
  1881. public:
  1882.         struct RuntimeData
  1883.         {
  1884.         };
  1885.  
  1886.         virtual LoadResult LoadFromXml(const XmlNodeRef& xml, const LoadContext& context) override
  1887.         {
  1888.                 IF_UNLIKELY (BaseClass::LoadFromXml(xml, context) == LoadFailure)
  1889.                         return LoadFailure;
  1890.  
  1891.                 const stack_string code = xml->getAttr("code");
  1892.                 IF_UNLIKELY (code.empty())
  1893.                 {
  1894.                         ErrorReporter(*this, context).LogError("Missing or empty 'code' attribute.");
  1895.                         return LoadFailure;
  1896.                 }
  1897.  
  1898.                 m_scriptFunction.reset(gEnv->pScriptSystem, gEnv->pScriptSystem->CompileBuffer(code.c_str(), code.length(), "AssertLua behavior tree node"));
  1899.                 IF_UNLIKELY (!m_scriptFunction)
  1900.                 {
  1901.                         ErrorReporter(*this, context).LogError("Failed to compile Lua code '%s'.", code.c_str());
  1902.                         return LoadFailure;
  1903.                 }
  1904.  
  1905.                 return LoadSuccess;
  1906.         }
  1907.  
  1908. protected:
  1909.         virtual Status Update(const UpdateContext& context) override
  1910.         {
  1911.                 FUNCTION_PROFILER(gEnv->pSystem, PROFILE_AI);
  1912.  
  1913.                 IEntity* entity = gEnv->pEntitySystem->GetEntity(context.entityId);
  1914.                 IF_UNLIKELY (!entity)
  1915.                         return Failure;
  1916.  
  1917.                 bool luaReturnValue = false;
  1918.                 gEnv->pScriptSystem->SetGlobalValue("entity", entity->GetScriptTable());
  1919.                 Script::CallReturn(gEnv->pScriptSystem, m_scriptFunction, luaReturnValue);
  1920.                 gEnv->pScriptSystem->SetGlobalToNull("entity");
  1921.  
  1922.                 return luaReturnValue ? Success : Failure;
  1923.         }
  1924.  
  1925. private:
  1926.         SmartScriptFunction m_scriptFunction;
  1927. };
  1928.  
  1929. //////////////////////////////////////////////////////////////////////////
  1930.  
  1931. class GroupScope : public Decorator
  1932. {
  1933. public:
  1934.         typedef Decorator BaseClass;
  1935.  
  1936.         struct RuntimeData
  1937.         {
  1938.                 EntityId     entityIdUsedToAquireToken;
  1939.                 GroupScopeID scopeID;
  1940.                 bool         gateIsOpen;
  1941.  
  1942.                 RuntimeData()
  1943.                         : entityIdUsedToAquireToken(0)
  1944.                         , scopeID(0)
  1945.                         , gateIsOpen(false)
  1946.                 {
  1947.                 }
  1948.  
  1949.                 ~RuntimeData()
  1950.                 {
  1951.                         ReleaseGroupScope();
  1952.                 }
  1953.  
  1954.                 void ReleaseGroupScope()
  1955.                 {
  1956.                         if (this->entityIdUsedToAquireToken != 0)
  1957.                         {
  1958.                                 IEntity* entity = gEnv->pEntitySystem->GetEntity(this->entityIdUsedToAquireToken);
  1959.                                 if (entity)
  1960.                                 {
  1961.                                         const CAIActor* aiActor = CastToCAIActorSafe(entity->GetAI());
  1962.                                         if (aiActor)
  1963.                                         {
  1964.                                                 CAIGroup* group = GetAISystem()->GetAIGroup(aiActor->GetGroupId());
  1965.                                                 if (group)
  1966.                                                         group->LeaveGroupScope(aiActor, this->scopeID);
  1967.  
  1968.                                                 this->entityIdUsedToAquireToken = 0;
  1969.                                         }
  1970.                                 }
  1971.                         }
  1972.                 }
  1973.         };
  1974.  
  1975.         GroupScope()
  1976.                 : m_scopeID(0)
  1977.                 , m_allowedConcurrentUsers(1u)
  1978.         {}
  1979.  
  1980.         virtual LoadResult LoadFromXml(const XmlNodeRef& xml, const LoadContext& context) override
  1981.         {
  1982.                 const stack_string scopeName = xml->getAttr("name");
  1983.  
  1984.                 if (scopeName.empty())
  1985.                         return LoadFailure;
  1986.  
  1987.                 m_scopeID = CAIGroup::GetGroupScopeId(scopeName.c_str());
  1988.  
  1989. #ifdef USING_BEHAVIOR_TREE_NODE_CUSTOM_DEBUG_TEXT
  1990.                 m_scopeName = scopeName.c_str();
  1991. #endif
  1992.  
  1993.                 xml->getAttr("allowedConcurrentUsers", m_allowedConcurrentUsers);
  1994.  
  1995.                 return LoadChildFromXml(xml, context);
  1996.         }
  1997.  
  1998. protected:
  1999.  
  2000.         virtual void OnInitialize(const UpdateContext& context) override
  2001.         {
  2002.                 RuntimeData& runtimeData = GetRuntimeData<RuntimeData>(context);
  2003.  
  2004.                 runtimeData.entityIdUsedToAquireToken = 0;
  2005.                 runtimeData.scopeID = m_scopeID;
  2006.                 runtimeData.gateIsOpen = false;
  2007.  
  2008.                 if (IEntity* pEntity = gEnv->pEntitySystem->GetEntity(context.entityId))
  2009.                 {
  2010.                         if (const CAIActor* pActor = CastToCAIActorSafe(pEntity->GetAI()))
  2011.                         {
  2012.                                 if (EnterGroupScope(*pActor, runtimeData))
  2013.                                 {
  2014.                                         runtimeData.gateIsOpen = true;
  2015.                                 }
  2016.                         }
  2017.                 }
  2018.         }
  2019.  
  2020.         virtual void OnTerminate(const UpdateContext& context) override
  2021.         {
  2022.                 BaseClass::OnTerminate(context);
  2023.  
  2024.                 RuntimeData& runtimeData = GetRuntimeData<RuntimeData>(context);
  2025.                 runtimeData.ReleaseGroupScope();
  2026.         }
  2027.  
  2028.         virtual Status Update(const UpdateContext& context) override
  2029.         {
  2030.                 RuntimeData& runtimeData = GetRuntimeData<RuntimeData>(context);
  2031.  
  2032.                 if (runtimeData.gateIsOpen)
  2033.                         return BaseClass::Update(context);
  2034.                 else
  2035.                         return Failure;
  2036.         }
  2037.  
  2038. #ifdef USING_BEHAVIOR_TREE_NODE_CUSTOM_DEBUG_TEXT
  2039.         virtual void GetCustomDebugText(const UpdateContext& updateContext, stack_string& debugText) const
  2040.         {
  2041.                 debugText.Format("%s", m_scopeName.c_str());
  2042.         }
  2043. #endif
  2044.  
  2045. private:
  2046.  
  2047.         bool EnterGroupScope(const CAIActor& actor, RuntimeData& runtimeData)
  2048.         {
  2049.                 CAIGroup* pGroup = GetAISystem()->GetAIGroup(actor.GetGroupId());
  2050.                 assert(pGroup);
  2051.                 if (pGroup->EnterGroupScope(&actor, m_scopeID, m_allowedConcurrentUsers))
  2052.                 {
  2053.                         runtimeData.entityIdUsedToAquireToken = actor.GetEntityID();
  2054.                         return true;
  2055.                 }
  2056.                 return false;
  2057.         }
  2058.  
  2059.         GroupScopeID m_scopeID;
  2060.         uint32       m_allowedConcurrentUsers;
  2061.  
  2062. #ifdef USING_BEHAVIOR_TREE_NODE_CUSTOM_DEBUG_TEXT
  2063.         string m_scopeName;
  2064. #endif
  2065. };
  2066.  
  2067. //////////////////////////////////////////////////////////////////////////
  2068.  
  2069. class Look : public Action
  2070. {
  2071.         typedef Action BaseClass;
  2072.  
  2073. public:
  2074.         struct RuntimeData
  2075.         {
  2076.                 std::shared_ptr<Vec3> lookTarget;
  2077.         };
  2078.  
  2079.         Look() : m_targetType(AttentionTarget)
  2080.         {
  2081.         }
  2082.  
  2083.         virtual LoadResult LoadFromXml(const XmlNodeRef& xml, const LoadContext& context) override
  2084.         {
  2085.                 IF_UNLIKELY (BaseClass::LoadFromXml(xml, context) == LoadFailure)
  2086.                         return LoadFailure;
  2087.  
  2088.                 const stack_string str = xml->getAttr("at");
  2089.                 if (str == "ClosestGroupMember")
  2090.                         m_targetType = ClosestGroupMember;
  2091.                 else if (str == "RefPoint")
  2092.                         m_targetType = ReferencePoint;
  2093.                 else
  2094.                         m_targetType = AttentionTarget;
  2095.  
  2096.                 return LoadSuccess;
  2097.         }
  2098.  
  2099. protected:
  2100.         virtual void OnInitialize(const UpdateContext& context) override
  2101.         {
  2102.                 GetRuntimeData<RuntimeData>(context).lookTarget = GetPipeUser(context)->CreateLookTarget();
  2103.         }
  2104.  
  2105.         virtual void OnTerminate(const UpdateContext& context) override
  2106.         {
  2107.                 RuntimeData& runtimeData = GetRuntimeData<RuntimeData>(context);
  2108.                 runtimeData.lookTarget.reset();
  2109.         }
  2110.  
  2111.         virtual Status Update(const UpdateContext& context) override
  2112.         {
  2113.                 RuntimeData& runtimeData = GetRuntimeData<RuntimeData>(context);
  2114.  
  2115.                 assert(runtimeData.lookTarget.get());
  2116.  
  2117.                 CPipeUser& pipeUser = *GetPipeUser(context);
  2118.  
  2119.                 if (m_targetType == AttentionTarget)
  2120.                 {
  2121.                         if (IAIObject* target = pipeUser.GetAttentionTarget())
  2122.                         {
  2123.                                 *runtimeData.lookTarget = target->GetPos();
  2124.                         }
  2125.                 }
  2126.                 else if (m_targetType == ClosestGroupMember)
  2127.                 {
  2128.                         const Group& group = gAIEnv.pGroupManager->GetGroup(pipeUser.GetGroupId());
  2129.                         const Group::Members& members = group.GetMembers();
  2130.                         Group::Members::const_iterator it = members.begin();
  2131.                         Group::Members::const_iterator end = members.end();
  2132.                         float closestDistSq = std::numeric_limits<float>::max();
  2133.                         tAIObjectID closestID = INVALID_AIOBJECTID;
  2134.                         Vec3 closestPos(ZERO);
  2135.                         const Vec3& myPosition = pipeUser.GetPos();
  2136.                         const tAIObjectID myAIObjectID = pipeUser.GetAIObjectID();
  2137.                         for (; it != end; ++it)
  2138.                         {
  2139.                                 const tAIObjectID memberID = *it;
  2140.                                 if (memberID != myAIObjectID)
  2141.                                 {
  2142.                                         IAIObject* member = GetAISystem()->GetAIObjectManager()->GetAIObject(memberID);
  2143.                                         if (member)
  2144.                                         {
  2145.                                                 const Vec3& memberPos = member->GetPos();
  2146.                                                 const float distSq = myPosition.GetSquaredDistance(memberPos);
  2147.                                                 if (distSq < closestDistSq)
  2148.                                                 {
  2149.                                                         closestID = memberID;
  2150.                                                         closestDistSq = distSq;
  2151.                                                         closestPos = memberPos;
  2152.                                                 }
  2153.                                         }
  2154.                                 }
  2155.                         }
  2156.  
  2157.                         if (closestID)
  2158.                                 *runtimeData.lookTarget = closestPos;
  2159.                         else
  2160.                                 *runtimeData.lookTarget = Vec3(ZERO);
  2161.                 }
  2162.                 else if (m_targetType == ReferencePoint)
  2163.                 {
  2164.                         if (IAIObject* rerefencePoint = pipeUser.GetRefPoint())
  2165.                         {
  2166.                                 *runtimeData.lookTarget = rerefencePoint->GetPos();
  2167.                         }
  2168.                 }
  2169.  
  2170.                 return Running;
  2171.         }
  2172.  
  2173. private:
  2174.         enum At
  2175.         {
  2176.                 AttentionTarget,
  2177.                 ClosestGroupMember,
  2178.                 ReferencePoint,
  2179.         };
  2180.  
  2181.         At m_targetType;
  2182. };
  2183.  
  2184. //////////////////////////////////////////////////////////////////////////
  2185.  
  2186. class Aim : public Action
  2187. {
  2188.         typedef Action BaseClass;
  2189.  
  2190. public:
  2191.         struct RuntimeData
  2192.         {
  2193.                 CStrongRef<CAIObject> fireTarget;
  2194.                 CTimeValue            startTime;
  2195.                 float                 timeSpentWithCorrectDirection;
  2196.  
  2197.                 RuntimeData()
  2198.                         : startTime(0.0f)
  2199.                         , timeSpentWithCorrectDirection(0.0f)
  2200.                 {
  2201.                 }
  2202.  
  2203.                 ~RuntimeData()
  2204.                 {
  2205.                         if (fireTarget)
  2206.                                 fireTarget.Release();
  2207.                 }
  2208.         };
  2209.  
  2210.         Aim()
  2211.                 : m_angleThresholdCosine(0.0f)
  2212.                 , m_durationOnceWithinThreshold(0.0f)   // -1 means "aim forever"
  2213.                 , m_aimAtReferencePoint(false)
  2214.         {
  2215.         }
  2216.  
  2217.         virtual LoadResult LoadFromXml(const XmlNodeRef& xml, const LoadContext& context) override
  2218.         {
  2219.                 IF_UNLIKELY (BaseClass::LoadFromXml(xml, context) == LoadFailure)
  2220.                         return LoadFailure;
  2221.  
  2222.                 float angleThresholdInDegrees = 30.0f;
  2223.                 xml->getAttr("angleThreshold", angleThresholdInDegrees);
  2224.                 m_angleThresholdCosine = cosf(DEG2RAD(angleThresholdInDegrees));
  2225.  
  2226.                 const stack_string at = xml->getAttr("at");
  2227.                 if (at == "RefPoint")
  2228.                 {
  2229.                         m_aimAtReferencePoint = true;
  2230.                 }
  2231.  
  2232.                 const stack_string str = xml->getAttr("durationOnceWithinThreshold");
  2233.                 if (str == "forever")
  2234.                 {
  2235.                         m_durationOnceWithinThreshold = -1.0f;
  2236.                 }
  2237.                 else
  2238.                 {
  2239.                         m_durationOnceWithinThreshold = 0.2f;
  2240.                         xml->getAttr("durationOnceWithinThreshold", m_durationOnceWithinThreshold);
  2241.                 }
  2242.  
  2243.                 return LoadSuccess;
  2244.         }
  2245.  
  2246. protected:
  2247.         virtual void OnInitialize(const UpdateContext& context) override
  2248.         {
  2249.                 RuntimeData& runtimeData = GetRuntimeData<RuntimeData>(context);
  2250.  
  2251.                 CPipeUser& pipeUser = *GetPipeUser(context);
  2252.  
  2253.                 Vec3 fireTargetPosition(ZERO);
  2254.  
  2255.                 if (m_aimAtReferencePoint)
  2256.                 {
  2257.                         CAIObject* referencePoint = pipeUser.GetRefPoint();
  2258.                         IF_UNLIKELY (!referencePoint)
  2259.                         {
  2260.                                 return;
  2261.                         }
  2262.  
  2263.                         fireTargetPosition = referencePoint->GetPos();
  2264.                 }
  2265.                 else if (IAIObject* target = pipeUser.GetAttentionTarget())
  2266.                 {
  2267.                         fireTargetPosition = target->GetPos();
  2268.                 }
  2269.                 else
  2270.                 {
  2271.                         return;
  2272.                 }
  2273.  
  2274.                 gAIEnv.pAIObjectManager->CreateDummyObject(runtimeData.fireTarget);
  2275.                 runtimeData.fireTarget->SetPos(fireTargetPosition);
  2276.                 pipeUser.SetFireTarget(runtimeData.fireTarget);
  2277.                 pipeUser.SetFireMode(FIREMODE_AIM);
  2278.                 runtimeData.startTime = gEnv->pTimer->GetFrameStartTime();
  2279.                 runtimeData.timeSpentWithCorrectDirection = 0.0f;
  2280.         }
  2281.  
  2282.         virtual void OnTerminate(const UpdateContext& context) override
  2283.         {
  2284.                 RuntimeData& runtimeData = GetRuntimeData<RuntimeData>(context);
  2285.  
  2286.                 if (runtimeData.fireTarget)
  2287.                         runtimeData.fireTarget.Release();
  2288.  
  2289.                 CPipeUser& pipeUser = *GetPipeUser(context);
  2290.  
  2291.                 pipeUser.SetFireTarget(NILREF);
  2292.                 pipeUser.SetFireMode(FIREMODE_OFF);
  2293.         }
  2294.  
  2295.         virtual Status Update(const UpdateContext& context) override
  2296.         {
  2297.                 RuntimeData& runtimeData = GetRuntimeData<RuntimeData>(context);
  2298.  
  2299.                 IF_UNLIKELY (!runtimeData.fireTarget)
  2300.                         return Success;
  2301.                 CAIObject* fireTargetAIObject = runtimeData.fireTarget.GetAIObject();
  2302.                 IF_UNLIKELY (fireTargetAIObject == NULL)
  2303.                 {
  2304.                         ErrorReporter(*this, context).LogError("Expected fire target!");
  2305.                         CRY_ASSERT_MESSAGE(false, "Behavior Tree node Aim suddenly lost its fire target!!");
  2306.                         return Success;
  2307.                 }
  2308.  
  2309.                 const bool aimForever = m_durationOnceWithinThreshold < 0.0f;
  2310.                 if (aimForever)
  2311.                         return Running;
  2312.  
  2313.                 CPipeUser& pipeUser = *GetPipeUser(context);
  2314.                 const SAIBodyInfo& bodyInfo = pipeUser.QueryBodyInfo();
  2315.  
  2316.                 const Vec3 desiredDirection = (fireTargetAIObject->GetPos() - bodyInfo.vFirePos).GetNormalized();
  2317.                 const Vec3 currentDirection = bodyInfo.vFireDir;
  2318.  
  2319.                 // Wait until we aim in the desired direction
  2320.                 const float dotProduct = currentDirection.Dot(desiredDirection);
  2321.                 if (dotProduct > m_angleThresholdCosine)
  2322.                 {
  2323.                         const float timeSpentWithCorrectDirection = runtimeData.timeSpentWithCorrectDirection + gEnv->pTimer->GetFrameTime();
  2324.                         runtimeData.timeSpentWithCorrectDirection = timeSpentWithCorrectDirection;
  2325.                         if (timeSpentWithCorrectDirection > m_durationOnceWithinThreshold)
  2326.                                 return Success;
  2327.                 }
  2328.  
  2329.                 const CTimeValue& now = gEnv->pTimer->GetFrameStartTime();
  2330.                 if (now > runtimeData.startTime + CTimeValue(8.0f))
  2331.                 {
  2332.                         gEnv->pLog->LogWarning("Agent '%s' failed to aim towards %f %f %f. Timed out...", pipeUser.GetName(), fireTargetAIObject->GetPos().x, fireTargetAIObject->GetPos().y, fireTargetAIObject->GetPos().z);
  2333.                         return Success;
  2334.                 }
  2335.  
  2336.                 return Running;
  2337.         }
  2338.  
  2339. private:
  2340.         float m_angleThresholdCosine;
  2341.         float m_durationOnceWithinThreshold;   // -1 means "aim forever"
  2342.         bool  m_aimAtReferencePoint;
  2343. };
  2344.  
  2345. //////////////////////////////////////////////////////////////////////////
  2346.  
  2347. class AimAroundWhileUsingAMachingGun : public Action
  2348. {
  2349.         typedef Action BaseClass;
  2350.  
  2351. public:
  2352.         struct RuntimeData
  2353.         {
  2354.                 CStrongRef<CAIObject> fireTarget;
  2355.                 CTimeValue            lastUpdateTime;
  2356.                 Vec3                  initialDirection;
  2357.                 Vec3                  mountedWeaponPivot;
  2358.  
  2359.                 RuntimeData()
  2360.                         : lastUpdateTime(0.0f)
  2361.                         , initialDirection(ZERO)
  2362.                         , mountedWeaponPivot(ZERO)
  2363.                 {
  2364.                 }
  2365.         };
  2366.  
  2367.         AimAroundWhileUsingAMachingGun()
  2368.                 : m_maxAngleRange(.0f)
  2369.                 , m_minSecondsBeweenUpdates(.0f)
  2370.         {
  2371.         }
  2372.  
  2373.         virtual LoadResult LoadFromXml(const XmlNodeRef& xml, const LoadContext& context) override
  2374.         {
  2375.                 IF_UNLIKELY (BaseClass::LoadFromXml(xml, context) == LoadFailure)
  2376.                         return LoadFailure;
  2377.  
  2378.                 float maxAngleRange = 30.0f;
  2379.                 xml->getAttr("maxAngleRange", maxAngleRange);
  2380.                 m_maxAngleRange = DEG2RAD(maxAngleRange);
  2381.  
  2382.                 m_minSecondsBeweenUpdates = 2;
  2383.                 xml->getAttr("minSecondsBeweenUpdates", m_minSecondsBeweenUpdates);
  2384.  
  2385.                 bool useReferencePointForInitialDirectionAndPivotPosition = true;
  2386.                 if (!xml->getAttr("useReferencePointForInitialDirectionAndPivotPosition", useReferencePointForInitialDirectionAndPivotPosition) ||
  2387.                     useReferencePointForInitialDirectionAndPivotPosition == false)
  2388.                 {
  2389.                         // This is currently not used but it forces the readability of the behavior of the node.
  2390.                         // It forces to understand that the reference point is used to store the pivot position and the inizial direction
  2391.                         // of the machine gun
  2392.                         ErrorReporter(*this, context).LogError("Attribute 'useReferencePointForInitialDirectionAndPivotPosition' is missing or different"
  2393.                                                                " than 1 (1 is currently the only accepted value)");
  2394.                 }
  2395.  
  2396.                 return LoadSuccess;
  2397.         }
  2398.  
  2399. protected:
  2400.         virtual void OnInitialize(const UpdateContext& context) override
  2401.         {
  2402.                 RuntimeData& runtimeData = GetRuntimeData<RuntimeData>(context);
  2403.  
  2404.                 CPipeUser* pipeUser = GetPipeUser(context);
  2405.  
  2406.                 IF_UNLIKELY (!pipeUser)
  2407.                 {
  2408.                         ErrorReporter(*this, context).LogError("Agent must be a pipe user but isn't.");
  2409.                         return;
  2410.                 }
  2411.  
  2412.                 CAIObject* pRefPoint = pipeUser->GetRefPoint();
  2413.  
  2414.                 if (pRefPoint)
  2415.                 {
  2416.                         runtimeData.initialDirection = pRefPoint->GetEntityDir();
  2417.                         runtimeData.mountedWeaponPivot = pRefPoint->GetPos();
  2418.                 }
  2419.                 else
  2420.                 {
  2421.                         runtimeData.initialDirection = pipeUser->GetEntityDir();
  2422.                         runtimeData.mountedWeaponPivot = pipeUser->GetPos();
  2423.                 }
  2424.  
  2425.                 runtimeData.initialDirection.Normalize();
  2426.  
  2427.                 gAIEnv.pAIObjectManager->CreateDummyObject(runtimeData.fireTarget);
  2428.                 pipeUser->SetFireTarget(runtimeData.fireTarget);
  2429.                 pipeUser->SetFireMode(FIREMODE_AIM);
  2430.  
  2431.                 UpdateAimingPosition(runtimeData);
  2432.                 runtimeData.lastUpdateTime = gEnv->pTimer->GetFrameStartTime();
  2433.         }
  2434.  
  2435.         virtual void OnTerminate(const UpdateContext& context) override
  2436.         {
  2437.                 RuntimeData& runtimeData = GetRuntimeData<RuntimeData>(context);
  2438.  
  2439.                 if (runtimeData.fireTarget)
  2440.                         runtimeData.fireTarget.Release();
  2441.  
  2442.                 CPipeUser* pipeUser = GetPipeUser(context);
  2443.  
  2444.                 if (pipeUser)
  2445.                 {
  2446.                         pipeUser->SetFireTarget(NILREF);
  2447.                         pipeUser->SetFireMode(FIREMODE_OFF);
  2448.                 }
  2449.         }
  2450.  
  2451.         virtual Status Update(const UpdateContext& context) override
  2452.         {
  2453.                 RuntimeData& runtimeData = GetRuntimeData<RuntimeData>(context);
  2454.  
  2455.                 IF_UNLIKELY (!runtimeData.fireTarget)
  2456.                         return Success;
  2457.  
  2458.                 const CTimeValue now = gEnv->pTimer->GetFrameStartTime();
  2459.                 const float elapsedSecondsFromPreviousUpdate = now.GetDifferenceInSeconds(runtimeData.lastUpdateTime);
  2460.                 if (elapsedSecondsFromPreviousUpdate > m_minSecondsBeweenUpdates)
  2461.                 {
  2462.                         UpdateAimingPosition(runtimeData);
  2463.                         runtimeData.lastUpdateTime = now;
  2464.                 }
  2465.  
  2466.                 return Running;
  2467.         }
  2468.  
  2469. private:
  2470.  
  2471.         void UpdateAimingPosition(RuntimeData& runtimeData)
  2472.         {
  2473.                 const float offSetForInizialAimingPosition = 3.0f;
  2474.  
  2475.                 Vec3 newFireTargetPos = runtimeData.mountedWeaponPivot + runtimeData.initialDirection * offSetForInizialAimingPosition;
  2476.                 const float rotationAngle = cry_random(-m_maxAngleRange, m_maxAngleRange);
  2477.                 Vec3 zAxis(0, 0, 1);
  2478.                 newFireTargetPos = newFireTargetPos.GetRotated(runtimeData.mountedWeaponPivot, zAxis, cos_tpl(rotationAngle), sin_tpl(rotationAngle));
  2479.                 runtimeData.fireTarget->SetPos(newFireTargetPos);
  2480.         }
  2481.  
  2482.         float m_maxAngleRange;
  2483.         float m_minSecondsBeweenUpdates;
  2484. };
  2485.  
  2486. //////////////////////////////////////////////////////////////////////////
  2487.  
  2488. class TurnBody : public Action
  2489. {
  2490.         typedef Action BaseClass;
  2491.  
  2492. public:
  2493.         struct RuntimeData
  2494.         {
  2495.                 Vec3  desiredBodyDirection;
  2496.                 float timeSpentAligning;
  2497.                 float correctBodyDirectionTime;
  2498.  
  2499.                 RuntimeData()
  2500.                         : desiredBodyDirection(ZERO)
  2501.                         , timeSpentAligning(0.0f)
  2502.                         , correctBodyDirectionTime(0.0f)
  2503.                 {
  2504.                 }
  2505.         };
  2506.  
  2507.         TurnBody()
  2508.                 : m_turnTarget(TurnTarget_Invalid)
  2509.                 , m_alignWithTarget(false)
  2510.                 , m_stopWithinAngleCosined(cosf(DEG2RAD(17.0f)))   // Backwards compatibility.
  2511.                 , m_randomMinAngle(-1.0f)
  2512.                 , m_randomMaxAngle(-1.0f)
  2513.                 , m_randomTurnRightChance(-1.0f)
  2514.         {
  2515.         }
  2516.  
  2517.         virtual LoadResult LoadFromXml(const XmlNodeRef& xml, const LoadContext& context) override
  2518.         {
  2519.                 IF_UNLIKELY (BaseClass::LoadFromXml(xml, context) == LoadFailure)
  2520.                         return LoadFailure;
  2521.  
  2522.                 m_alignWithTarget = false;
  2523.                 m_turnTarget = TurnTarget_Invalid;
  2524.                 s_turnBodyDictionary.turnTarget.Get(xml, "towards", m_turnTarget);
  2525.                 TurnTarget alignTurnTarget = TurnTarget_Invalid;
  2526.                 s_turnBodyDictionary.turnTarget.Get(xml, "alignWith", alignTurnTarget);
  2527.                 if (m_turnTarget == TurnTarget_Invalid)
  2528.                 {
  2529.                         m_turnTarget = alignTurnTarget;
  2530.                         if (alignTurnTarget != TurnTarget_Invalid)
  2531.                         {
  2532.                                 m_alignWithTarget = true;
  2533.                         }
  2534.                 }
  2535.  
  2536.                 float stopWithinAngleDegrees;
  2537.                 if (xml->getAttr("stopWithinAngle", stopWithinAngleDegrees))
  2538.                 {
  2539.                         if ((stopWithinAngleDegrees < 0.0f) || (stopWithinAngleDegrees > 180.0f))
  2540.                         {
  2541.                                 ErrorReporter(*this, context).LogError("stopWithinAngle should be in the range of [0.0 .. 180.0].");
  2542.                                 return LoadFailure;
  2543.                         }
  2544.                         m_stopWithinAngleCosined = cosf(DEG2RAD(stopWithinAngleDegrees));
  2545.                 }
  2546.  
  2547.                 // The turning randomization can be applied on any kind of target.
  2548.                 m_randomMinAngle = -1.0f;
  2549.                 m_randomMaxAngle = -1.0f;
  2550.                 m_randomTurnRightChance = -1.0f;
  2551.                 float angleDegrees = 0.0f;
  2552.                 if (xml->getAttr("randomMinAngle", angleDegrees))
  2553.                 {
  2554.                         if ((angleDegrees < 0.0f) || (angleDegrees > 180.0f))
  2555.                         {
  2556.                                 ErrorReporter(*this, context).LogError("Min. random angle should be in the range of [0.0 .. 180.0].");
  2557.                                 return LoadFailure;
  2558.                         }
  2559.                         m_randomMinAngle = DEG2RAD(angleDegrees);
  2560.                 }
  2561.                 angleDegrees = 0.0f;
  2562.                 if (xml->getAttr("randomMaxAngle", angleDegrees))
  2563.                 {
  2564.                         if ((angleDegrees < 0.0f) || (angleDegrees > 180.0f))
  2565.                         {
  2566.                                 ErrorReporter(*this, context).LogError("Max. random angle should be in the range of [0.0 .. 180.0].");
  2567.                                 return LoadFailure;
  2568.                         }
  2569.                         m_randomMaxAngle = DEG2RAD(angleDegrees);
  2570.                 }
  2571.                 if ((m_randomMinAngle >= 0.0f) || (m_randomMaxAngle >= 0.0f))
  2572.                 {
  2573.                         if (m_randomMinAngle < 0.0f)
  2574.                         {
  2575.                                 m_randomMinAngle = 0.0f;
  2576.                         }
  2577.                         if (m_randomMaxAngle < 0.0f)
  2578.                         {
  2579.                                 m_randomMaxAngle = gf_PI;
  2580.                         }
  2581.                         if (m_randomMinAngle > m_randomMaxAngle)
  2582.                         {
  2583.                                 ErrorReporter(*this, context).LogError("Min. and max. random angles are swapped.");
  2584.                                 return LoadFailure;
  2585.                         }
  2586.  
  2587.                         m_randomTurnRightChance = 0.5f;
  2588.                         if (xml->getAttr("randomTurnRightChance", m_randomTurnRightChance))
  2589.                         {
  2590.                                 if ((m_randomTurnRightChance < 0.0f) || (m_randomTurnRightChance > 1.0f))
  2591.                                 {
  2592.                                         ErrorReporter(*this, context).LogError("randomTurnRightChance should be in the range of [0.0 .. 1.0].");
  2593.                                         return LoadFailure;
  2594.                                 }
  2595.                         }
  2596.  
  2597.                         if (m_turnTarget == TurnTarget_Invalid)
  2598.                         {
  2599.                                 // We will turn in a completely random direction.
  2600.                                 m_turnTarget = TurnTarget_Random;
  2601.                         }
  2602.                 }
  2603.  
  2604.                 if (m_turnTarget == TurnTarget_Invalid)
  2605.                 {
  2606.                         ErrorReporter(*this, context).LogError("Target is missing");
  2607.                 }
  2608.  
  2609.                 return LoadSuccess;
  2610.         }
  2611.  
  2612. protected:
  2613.         virtual void OnInitialize(const UpdateContext& context) override
  2614.         {
  2615.                 CPipeUser* pipeUser = GetPipeUser(context);
  2616.  
  2617.                 Vec3 desiredBodyDirection(ZERO);
  2618.                 switch (m_turnTarget)
  2619.                 {
  2620.                 case TurnTarget_Invalid:
  2621.                 default:
  2622.                         // We should never get here!
  2623.                         assert(false);
  2624.                         break;
  2625.  
  2626.                 case TurnTarget_Random:
  2627.                         desiredBodyDirection = pipeUser->GetEntityDir();
  2628.                         break;
  2629.  
  2630.                 case TurnTarget_AttentionTarget:
  2631.                         if (IAIObject* target = pipeUser->GetAttentionTarget())
  2632.                         {
  2633.                                 if (m_alignWithTarget)
  2634.                                 {
  2635.                                         desiredBodyDirection = pipeUser->GetEntityDir();
  2636.                                 }
  2637.                                 else
  2638.                                 {
  2639.                                         desiredBodyDirection = target->GetPos() - pipeUser->GetPhysicsPos();
  2640.                                 }
  2641.                                 desiredBodyDirection.z = 0.0f;
  2642.                                 desiredBodyDirection.Normalize();
  2643.                         }
  2644.                         break;
  2645.  
  2646.                 case TurnTarget_RefPoint:
  2647.                         CAIObject* refPointObject = pipeUser->GetRefPoint();
  2648.                         if (refPointObject != NULL)
  2649.                         {
  2650.                                 if (m_alignWithTarget)
  2651.                                 {
  2652.                                         desiredBodyDirection = refPointObject->GetEntityDir();
  2653.                                 }
  2654.                                 else
  2655.                                 {
  2656.                                         desiredBodyDirection = refPointObject->GetPos() - pipeUser->GetPhysicsPos();
  2657.                                 }
  2658.                                 desiredBodyDirection.z = 0.0f;
  2659.                                 desiredBodyDirection.Normalize();
  2660.                         }
  2661.                         break;
  2662.                 }
  2663.  
  2664.                 desiredBodyDirection = ApplyRandomTurnOnNormalXYPlane(desiredBodyDirection);
  2665.  
  2666.                 if (!desiredBodyDirection.IsZero())
  2667.                 {
  2668.                         pipeUser->SetBodyTargetDir(desiredBodyDirection);
  2669.                 }
  2670.  
  2671.                 RuntimeData& runtimeData = GetRuntimeData<RuntimeData>(context);
  2672.  
  2673.                 runtimeData.desiredBodyDirection = desiredBodyDirection;
  2674.                 runtimeData.timeSpentAligning = 0.0f;
  2675.         }
  2676.  
  2677.         virtual void OnTerminate(const UpdateContext& context) override
  2678.         {
  2679.                 GetPipeUser(context)->ResetBodyTargetDir();
  2680.         }
  2681.  
  2682.         virtual Status Update(const UpdateContext& context) override
  2683.         {
  2684.                 RuntimeData& runtimeData = GetRuntimeData<RuntimeData>(context);
  2685.  
  2686.                 if (runtimeData.desiredBodyDirection.IsZero())
  2687.                 {
  2688.                         ErrorReporter(*this, context).LogWarning("Desired body direction is invalid.");
  2689.                         return Success;
  2690.                 }
  2691.  
  2692.                 CPipeUser& pipeUser = *GetPipeUser(context);
  2693.  
  2694.                 // If animation body direction is within the angle threshold,
  2695.                 // wait for some time and then mark the agent as ready to move
  2696.                 const Vec3 actualBodyDir = pipeUser.GetBodyInfo().vAnimBodyDir;
  2697.                 const bool turnedTowardsDesiredDirection = (actualBodyDir.Dot(runtimeData.desiredBodyDirection) > m_stopWithinAngleCosined);
  2698.                 if (turnedTowardsDesiredDirection)
  2699.                         runtimeData.correctBodyDirectionTime += gEnv->pTimer->GetFrameTime();
  2700.                 else
  2701.                         runtimeData.correctBodyDirectionTime = 0.0f;
  2702.  
  2703.                 const float timeSpentAligning = runtimeData.timeSpentAligning + gEnv->pTimer->GetFrameTime();
  2704.                 runtimeData.timeSpentAligning = timeSpentAligning;
  2705.  
  2706.                 if (runtimeData.correctBodyDirectionTime > 0.2f)
  2707.                         return Success;
  2708.  
  2709.                 const float timeout = 8.0f;
  2710.                 if (timeSpentAligning > timeout)
  2711.                 {
  2712.                         ErrorReporter(*this, context).LogWarning(
  2713.                           "Failed to turn in direction %f %f %f within %f seconds. Proceeding anyway.",
  2714.                           runtimeData.desiredBodyDirection.x, runtimeData.desiredBodyDirection.y, runtimeData.desiredBodyDirection.z, timeout);
  2715.                         return Success;
  2716.                 }
  2717.  
  2718.                 return Running;
  2719.         }
  2720.  
  2721. private:
  2722.  
  2723.         Vec3 ApplyRandomTurnOnNormalXYPlane(const Vec3& initialNormal) const
  2724.         {
  2725.                 if ((m_randomMinAngle < 0.0f) || (m_randomMaxAngle <= 0.0f))
  2726.                 {
  2727.                         return initialNormal;
  2728.                 }
  2729.  
  2730.                 float randomAngle = cry_random(m_randomMinAngle, m_randomMaxAngle);
  2731.                 if (cry_random(0.0f, 1.0f) < m_randomTurnRightChance)
  2732.                 {
  2733.                         randomAngle = -randomAngle;
  2734.                 }
  2735.  
  2736.                 float sinAngle, cosAngle;
  2737.                 sincos_tpl(randomAngle, &sinAngle, &cosAngle);
  2738.  
  2739.                 Vec3 randomizedNormal = Vec3(
  2740.                   (initialNormal.x * cosAngle) - (initialNormal.y * sinAngle),
  2741.                   (initialNormal.y * cosAngle) + (initialNormal.x * sinAngle),
  2742.                   0.0f);
  2743.                 randomizedNormal.Normalize();
  2744.  
  2745.                 return randomizedNormal;
  2746.         }
  2747.  
  2748. private:
  2749.         enum TurnTarget
  2750.         {
  2751.                 TurnTarget_Invalid = 0,
  2752.                 TurnTarget_Random,
  2753.                 TurnTarget_AttentionTarget,
  2754.                 TurnTarget_RefPoint
  2755.         };
  2756.  
  2757.         struct TurnBodyDictionary
  2758.         {
  2759.                 CXMLAttrReader<TurnBody::TurnTarget> turnTarget;
  2760.  
  2761.                 TurnBodyDictionary()
  2762.                 {
  2763.                         turnTarget.Reserve(2);
  2764.                         turnTarget.Add("Target", TurnTarget_AttentionTarget);     // Name is a bit confusing but also used elsewhere.
  2765.                         turnTarget.Add("RefPoint", TurnTarget_RefPoint);
  2766.                 }
  2767.         };
  2768.  
  2769.         static TurnBodyDictionary s_turnBodyDictionary;
  2770.  
  2771. private:
  2772.         TurnTarget m_turnTarget;
  2773.  
  2774.         // If true then we should align with the target (take on the same rotation); false
  2775.         // if we should rotate towards it.
  2776.         bool m_alignWithTarget;
  2777.  
  2778.         // If we are within this threshold angle then we can stop the rotation (in radians)
  2779.         // in the range of [0.0f .. gf_PI]. This can be used to prevent rotations when
  2780.         // we already 'close enough' to the target angle. The value is already cosined.
  2781.         float m_stopWithinAngleCosined;
  2782.  
  2783.         // -1.0f if there is no randomization limit (otherwise should be in the range of
  2784.         // [0.0f .. gf_PI]).
  2785.         float m_randomMinAngle;
  2786.         float m_randomMaxAngle;
  2787.  
  2788.         // The chance to do a rightwards random turn in the range of [0.0f .. 1.0f],
  2789.         // with 0.0f = always turn left, 1.0f = always turn right (-1.0f if there
  2790.         // is no randomization).
  2791.         float m_randomTurnRightChance;
  2792. };
  2793.  
  2794. BehaviorTree::TurnBody::TurnBodyDictionary BehaviorTree::TurnBody::s_turnBodyDictionary;
  2795.  
  2796. //////////////////////////////////////////////////////////////////////////
  2797.  
  2798. class ClearTargets : public Action
  2799. {
  2800. public:
  2801.         struct RuntimeData
  2802.         {
  2803.         };
  2804.  
  2805. protected:
  2806.         virtual Status Update(const UpdateContext& context) override
  2807.         {
  2808.                 CPipeUser& pipeUser = *GetPipeUser(context);
  2809.                 gAIEnv.pTargetTrackManager->ResetAgent(pipeUser.GetAIObjectID());
  2810.  
  2811.                 pipeUser.GetProxy()->ResendTargetSignalsNextFrame();
  2812.  
  2813.                 return Success;
  2814.         }
  2815. };
  2816.  
  2817. //////////////////////////////////////////////////////////////////////////
  2818.  
  2819. class StopMovement : public Action
  2820. {
  2821.         typedef Action BaseClass;
  2822.  
  2823. public:
  2824.         struct RuntimeData
  2825.         {
  2826.                 MovementRequestID movementRequestID;
  2827.                 uint32            motionIdleScopeID;
  2828.                 FragmentID        motionIdleFragmentID;
  2829.                 bool              hasStopped;
  2830.  
  2831.                 RuntimeData()
  2832.                         : movementRequestID(0)
  2833.                         , motionIdleScopeID(SCOPE_ID_INVALID)
  2834.                         , motionIdleFragmentID(FRAGMENT_ID_INVALID)
  2835.                         , hasStopped(false)
  2836.                 {
  2837.                 }
  2838.  
  2839.                 ~RuntimeData()
  2840.                 {
  2841.                         CancelMovementRequest();
  2842.                 }
  2843.  
  2844.                 void MovementRequestCallback(const MovementRequestResult& result)
  2845.                 {
  2846.                         this->hasStopped = true;
  2847.                 }
  2848.  
  2849.                 void CancelMovementRequest()
  2850.                 {
  2851.                         if (this->movementRequestID)
  2852.                         {
  2853.                                 gEnv->pAISystem->GetMovementSystem()->CancelRequest(this->movementRequestID);
  2854.                                 this->movementRequestID = 0;
  2855.                         }
  2856.                 }
  2857.         };
  2858.  
  2859.         StopMovement()
  2860.                 : m_waitUntilStopped(false)
  2861.                 , m_waitUntilIdleAnimation(false)
  2862.         {
  2863.         }
  2864.  
  2865.         virtual LoadResult LoadFromXml(const XmlNodeRef& xml, const LoadContext& context) override
  2866.         {
  2867.                 IF_UNLIKELY (BaseClass::LoadFromXml(xml, context) == LoadFailure)
  2868.                         return LoadFailure;
  2869.  
  2870.                 m_waitUntilStopped = false;
  2871.                 xml->getAttr("waitUntilStopped", m_waitUntilStopped);
  2872.  
  2873.                 m_waitUntilIdleAnimation = false;
  2874.                 xml->getAttr("waitUntilIdleAnimation", m_waitUntilIdleAnimation);
  2875.  
  2876.                 return LoadSuccess;
  2877.         }
  2878.  
  2879. protected:
  2880.         virtual void OnInitialize(const UpdateContext& context) override
  2881.         {
  2882.                 RuntimeData& runtimeData = GetRuntimeData<RuntimeData>(context);
  2883.  
  2884.                 MovementRequest movementRequest;
  2885.                 movementRequest.entityID = context.entityId;
  2886.                 movementRequest.type = MovementRequest::Stop;
  2887.  
  2888.                 if (m_waitUntilStopped)
  2889.                 {
  2890.                         movementRequest.callback = functor(runtimeData, &RuntimeData::MovementRequestCallback);
  2891.                         runtimeData.movementRequestID = gEnv->pAISystem->GetMovementSystem()->QueueRequest(movementRequest);
  2892.                 }
  2893.                 else
  2894.                 {
  2895.                         gEnv->pAISystem->GetMovementSystem()->QueueRequest(movementRequest);
  2896.                 }
  2897.  
  2898.                 runtimeData.hasStopped = false;
  2899.  
  2900.                 if (m_waitUntilIdleAnimation &&
  2901.                     ((runtimeData.motionIdleScopeID == SCOPE_ID_INVALID) || (runtimeData.motionIdleFragmentID == FRAGMENT_ID_INVALID)))
  2902.                 {
  2903.                         m_waitUntilIdleAnimation = LinkWithMannequin(context.entityId, runtimeData);
  2904.                 }
  2905.         }
  2906.  
  2907.         virtual void OnTerminate(const UpdateContext& context) override
  2908.         {
  2909.                 RuntimeData& runtimeData = GetRuntimeData<RuntimeData>(context);
  2910.                 runtimeData.CancelMovementRequest();
  2911.         }
  2912.  
  2913.         virtual Status Update(const UpdateContext& context) override
  2914.         {
  2915.                 RuntimeData& runtimeData = GetRuntimeData<RuntimeData>(context);
  2916.  
  2917.                 bool waitingForIdleAni = false;
  2918.                 if (m_waitUntilIdleAnimation)
  2919.                 {
  2920.                         waitingForIdleAni = !IsIdleFragmentRunning(context, runtimeData);
  2921.                 }
  2922.  
  2923.                 bool waitingForStopped = false;
  2924.                 if (m_waitUntilStopped)
  2925.                 {
  2926.                         waitingForStopped = !runtimeData.hasStopped;
  2927.                 }
  2928.  
  2929.                 if (waitingForStopped || waitingForIdleAni)
  2930.                 {
  2931.                         return Running;
  2932.                 }
  2933.  
  2934.                 return Success;
  2935.         }
  2936.  
  2937. private:
  2938.         IActionController* GetActionController(const EntityId entityID) const
  2939.         {
  2940. #if !defined(SYS_ENV_AS_STRUCT)
  2941.                 assert(gEnv != NULL);
  2942. #endif
  2943.                 assert(gEnv->pGameFramework != NULL);
  2944.  
  2945.                 IGameFramework* gameFramework = gEnv->pGameFramework;
  2946.                 IF_UNLIKELY (gameFramework == NULL)
  2947.                 {
  2948.                         return NULL;
  2949.                 }
  2950.  
  2951.                 IEntity* entity = gEnv->pEntitySystem->GetEntity(entityID);
  2952.                 if (entity == NULL)
  2953.                 {
  2954.                         assert(false);
  2955.                         return NULL;
  2956.                 }
  2957.  
  2958.                 IMannequin& mannequinInterface = gameFramework->GetMannequinInterface();
  2959.                 return mannequinInterface.FindActionController(*entity);
  2960.         }
  2961.  
  2962.         bool IsIdleFragmentRunning(const UpdateContext& context, RuntimeData& runtimeData) const
  2963.         {
  2964.                 IF_UNLIKELY (runtimeData.motionIdleScopeID == SCOPE_ID_INVALID)
  2965.                 {
  2966.                         return false;
  2967.                 }
  2968.  
  2969.                 IActionController* a