BVB Source Codes

CRYENGINE Show PipeUser.cpp Source code

Return Download CRYENGINE: download PipeUser.cpp Source code - Download CRYENGINE Source code - Type:.cpp
  1. // Copyright 2001-2016 Crytek GmbH / Crytek Group. All rights reserved.
  2.  
  3. /********************************************************************
  4.    -------------------------------------------------------------------------
  5.    File name:   PipeUser.cpp
  6.    $Id$
  7.    Description:
  8.  
  9.    -------------------------------------------------------------------------
  10.    History:
  11.    -
  12.  
  13.  *********************************************************************/
  14. #include "StdAfx.h"
  15. #include "CAISystem.h"
  16. #include <CrySystem/ISystem.h>
  17. #include <CrySystem/IConsole.h>
  18. #include <CrySystem/ITimer.h>
  19. #include "GoalOp.h"
  20. #include "PipeUser.h"
  21. #include "Puppet.h"
  22. #include "Leader.h"
  23. #include "AIActions.h"
  24. #include "PathFollower.h"
  25. #include "SmartPathFollower.h"
  26. #include <CryNetwork/ISerialize.h>
  27. #include "ObjectContainer.h"
  28. #include "CodeCoverageTracker.h"
  29. #include "TargetSelection/TargetTrackManager.h"
  30.  
  31. #include "Cover/CoverSystem.h"
  32.  
  33. #include "DebugDrawContext.h"
  34.  
  35. #include "Navigation/NavigationSystem/NavigationSystem.h"
  36. #include <CryAISystem/MovementStyle.h>
  37.  
  38. #pragma warning(push)
  39. #pragma warning(disable:4355) // 'this': used in base member initializer list
  40.  
  41. CPipeUser::CPipeUser()
  42.         : m_fTimePassed(0)
  43.         , m_adjustingAim(false)
  44.         , m_inCover(false)
  45.         , m_movingToCover(false)
  46.         , m_movingInCover(false)
  47.         , m_pPathFollower(0)
  48.         , m_bPathfinderConsidersPathTargetDirection(true)
  49.         , m_vLastMoveDir(ZERO)
  50.         , m_bKeepMoving(false)
  51.         , m_nPathDecision(PATHFINDER_NOPATH)
  52.         , m_queuedPathId(0)
  53.         , m_bFirstUpdate(true)
  54.         , m_bBlocked(false)
  55.         , m_pCurrentGoalPipe(NULL)
  56.         , m_fireMode(FIREMODE_OFF)
  57.         , m_fireModeUpdated(false)
  58.         , m_bLooseAttention(false)
  59.         , m_IsSteering(false)
  60. #ifdef _DEBUG
  61.         , m_DEBUGmovementReason(AIMORE_UNKNOWN)
  62. #endif
  63.         , m_AttTargetPersistenceTimeout(0.0f)
  64.         , m_AttTargetThreat(AITHREAT_NONE)
  65.         , m_AttTargetExposureThreat(AITHREAT_NONE)
  66.         , m_AttTargetType(AITARGET_NONE)
  67.         , m_bPathToFollowIsSpline(false)
  68.         , m_lastLiveTargetPos(ZERO)
  69.         , m_timeSinceLastLiveTarget(-1.0f)
  70.         , m_refShape(0)
  71.         , m_looseAttentionId(0)
  72.         , m_aimState(AI_AIM_NONE)
  73.         , m_pActorTargetRequest(0)
  74. #ifdef _DEBUG
  75.         , m_DEBUGUseTargetPointRequest(ZERO)
  76. #endif
  77.         , m_PathDestinationPos(ZERO)
  78.         , m_eNavSOMethod(nSOmNone)
  79.         , m_idLastUsedSmartObject(0)
  80.         , m_actorTargetReqId(1)
  81.         , m_spreadFireTime(0.0f)
  82.         , m_lastExecutedGoalop(eGO_LAST)
  83.         , m_paused(0)
  84.         , m_bEnableUpdateLookTarget(true)
  85.         , m_regCoverID(0)
  86.         , m_adjustpath(0)
  87.         , m_pipeExecuting(false)
  88.         , m_cutPathAtSmartObject(true)
  89.         , m_considerActorsAsPathObstacles(false)
  90.         , m_movementActorAdapter(*this)
  91.         , m_bLastActionSucceed(false)
  92. {
  93.         CCCPOINT(CPipeUser_CPipeUser);
  94.  
  95.         _fastcast_CPipeUser = true;
  96.  
  97.         // (MATT) SetName could be called to ensure we're consistent, rather than the code above {2009/02/03}
  98.  
  99.         m_CurrentHideObject.m_HideSmartObject.pChainedUserEvent = NULL;
  100.         m_CurrentHideObject.m_HideSmartObject.pChainedObjectEvent = NULL;
  101.  
  102.         m_callbacksForPipeuser.queuePathRequestFunction = functor(*this, &CPipeUser::RequestPathTo);
  103.         m_callbacksForPipeuser.checkOnPathfinderStateFunction = functor(*this, &CPipeUser::GetPathfinderState);
  104.         m_callbacksForPipeuser.getPathFollowerFunction = functor(*this, &CPipeUser::GetPathFollower);
  105.         m_callbacksForPipeuser.getPathFunction = functor(*this, &CPipeUser::GetINavPath);
  106. }
  107. #pragma warning(pop)
  108.  
  109. static bool bNotifyListenersLock = false;
  110.  
  111. CPipeUser::~CPipeUser(void)
  112. {
  113.         CCCPOINT(CPipeUser_Destructor);
  114.  
  115.         // (MATT) Can't a call to Reset be included here? {2009/02/04}
  116.  
  117.         if (m_pCurrentGoalPipe)
  118.         {
  119.                 ResetCurrentPipe(true);
  120.         }
  121.  
  122.         m_coverUsageInfoState.Reset();
  123.  
  124.         while (!m_mapGoalPipeListeners.empty())
  125.                 UnRegisterGoalPipeListener(m_mapGoalPipeListeners.begin()->second.first, m_mapGoalPipeListeners.begin()->first);
  126.  
  127.         // Delete special AI objects, and reset array.
  128.         for (unsigned i = 0; i < COUNT_AISPECIAL; ++i)
  129.                 m_refSpecialObjects[i].Release();
  130.  
  131.         SAFE_RELEASE(m_pPathFollower);
  132.         SAFE_DELETE(m_pActorTargetRequest);
  133.  
  134.         gAIEnv.pMovementSystem->UnregisterEntity(GetEntityID());
  135. }
  136.  
  137. void CPipeUser::Event(unsigned short int eType, SAIEVENT* pAIEvent)
  138. {
  139.         CAIActor::Event(eType, pAIEvent);
  140.  
  141.         switch (eType)
  142.         {
  143.         case AIEVENT_CLEAR:
  144.                 {
  145.                         CCCPOINT(CPuppet_Event_Clear);
  146.  
  147.                         ClearActiveGoals();
  148.                         m_bLooseAttention = false;
  149.                         GetAISystem()->FreeFormationPoint(GetWeakRef(this));
  150.                         SetAttentionTarget(NILREF);
  151.                         m_bBlocked = false;
  152.                 }
  153.                 break;
  154.         case AIEVENT_CLEARACTIVEGOALS:
  155.                 ClearActiveGoals();
  156.                 m_bBlocked = false;
  157.                 break;
  158.         case AIEVENT_AGENTDIED:
  159.                 SetNavSOFailureStates();
  160.                 if (m_inCover || m_movingToCover)
  161.                 {
  162.                         SetCoverRegister(CoverID());
  163.                         m_coverUser.SetCoverID(CoverID());
  164.                         m_inCover = m_movingToCover = false;
  165.                 }
  166.  
  167.                 m_Path.Clear("Agent Died");
  168.                 break;
  169.         case AIEVENT_ADJUSTPATH:
  170.                 m_adjustpath = pAIEvent->nType;
  171.                 break;
  172.         }
  173. }
  174.  
  175. void CPipeUser::ParseParameters(const AIObjectParams& params, bool bParseMovementParams)
  176. {
  177.         CAIActor::ParseParameters(params, bParseMovementParams);
  178.  
  179.         // Reset the path follower parameters
  180.         if (m_pPathFollower)
  181.         {
  182.                 PathFollowerParams pathFollowerParams;
  183.                 GetPathFollowerParams(pathFollowerParams);
  184.  
  185.                 m_pPathFollower->SetParams(pathFollowerParams);
  186.                 m_pPathFollower->Reset();
  187.         }
  188. }
  189.  
  190. void CPipeUser::CreateRefPoint()
  191. {
  192.         if (m_refRefPoint.IsSet() && m_refRefPoint.GetAIObject())
  193.                 return;
  194.  
  195.         gAIEnv.pAIObjectManager->CreateDummyObject(m_refRefPoint, string(GetName()) + "_RefPoint", STP_REFPOINT);
  196.         CAIObject* pRefPoint = m_refRefPoint.GetAIObject();
  197.         assert(pRefPoint);
  198.  
  199.         if (pRefPoint)
  200.         {
  201.                 pRefPoint->SetPos(GetPos(), GetMoveDir());
  202.         }
  203. }
  204.  
  205. void CPipeUser::CreateLookAtTarget()
  206. {
  207.         if (m_refLookAtTarget.IsSet() && m_refLookAtTarget.GetAIObject())
  208.         {
  209.                 return;
  210.         }
  211.  
  212.         gAIEnv.pAIObjectManager->CreateDummyObject(m_refLookAtTarget, string(GetName()) + "_LookAtTarget", STP_LOOKAT);
  213.         CAIObject* pLookAtTarget = m_refLookAtTarget.GetAIObject();
  214.         pLookAtTarget->SetPos(GetPos() + GetMoveDir());
  215. }
  216.  
  217. //
  218. //
  219. void CPipeUser::Reset(EObjectResetType type)
  220. {
  221.         CCCPOINT(CPipeUser_Reset);
  222.  
  223.         m_notAllowedSubpipes.clear();
  224.         SelectPipe(0, "_first_", NILREF, 0, true);
  225.         m_Path.Clear("CPipeUser::Reset m_Path");
  226.  
  227.         CAIActor::Reset(type);
  228.  
  229.         ClearPath("Reset");
  230.  
  231.         m_adjustingAim = false;
  232.  
  233.         m_bLastNearForbiddenEdge = false;
  234.  
  235.         m_coverUser.Reset();
  236.         m_movingToCover = false;
  237.         m_movingInCover = false;
  238.         m_inCover = false;
  239.  
  240.         SetAttentionTarget(NILREF);
  241.         m_PathDestinationPos.zero();
  242.         m_refPathFindTarget.Reset();
  243.         m_IsSteering = false;
  244.         m_fireMode = FIREMODE_OFF;
  245.         SetFireTarget(NILREF);
  246.         m_fireModeUpdated = false;
  247.         m_outOfAmmoSent = false;
  248.         m_lowAmmoSent = false;
  249.         m_wasReloading = false;
  250.         m_actorTargetReqId = 1;
  251.  
  252.         ResetLookAt();
  253.         ResetBodyTargetDir();
  254.         ResetDesiredBodyDirectionAtTarget();
  255.         ResetMovementContext();
  256.  
  257.         ResetCoverBlacklist();
  258.         m_regCoverID = CoverID();
  259.  
  260.         m_coverUsageInfoState.Reset();
  261.  
  262.         m_aimState = AI_AIM_NONE;
  263.  
  264.         m_posLookAtSmartObject.zero();
  265.  
  266.         m_eNavSOMethod = nSOmNone;
  267.         m_pendingNavSOStates.Clear();
  268.         m_currentNavSOStates.Clear();
  269.  
  270.         m_CurrentNodeNavType = IAISystem::NAV_UNSET;
  271.         m_idLastUsedSmartObject = 0;
  272.         ClearInvalidatedSOLinks();
  273.  
  274.         m_CurrentHideObject.m_HideSmartObject.Clear();
  275.         m_bFirstUpdate = true;
  276.  
  277.         m_lastLiveTargetPos.zero();
  278.         m_timeSinceLastLiveTarget = -1.0f;
  279.         m_spreadFireTime = 0.0f;
  280.  
  281.         m_recentUnreachableHideObjects.clear();
  282.  
  283.         m_bPathToFollowIsSpline = false;
  284.  
  285.         m_refShapeName.clear();
  286.         m_refShape = 0;
  287.  
  288.         m_paused = 0;
  289.         m_bEnableUpdateLookTarget = true;
  290.  
  291.         SAFE_DELETE(m_pActorTargetRequest);
  292.  
  293.         // Delete special AI objects, and reset array.
  294.         for (unsigned i = 0; i < COUNT_AISPECIAL; ++i)
  295.                 m_refSpecialObjects[i].Release();
  296.  
  297.         m_adjustpath = 0;
  298.         m_pipeExecuting = false;
  299.  
  300.         m_pathAdjustmentObstacles.Reset();
  301.  
  302. #ifdef _DEBUG
  303.         m_DEBUGCanTargetPointBeReached.clear();
  304.         m_DEBUGUseTargetPointRequest.zero();
  305. #endif
  306.         switch (type)
  307.         {
  308.         case AIOBJRESET_INIT:
  309.                 gAIEnv.pMovementSystem->RegisterEntity(GetEntityID(), m_callbacksForPipeuser, m_movementActorAdapter);
  310.                 break;
  311.         case AIOBJRESET_SHUTDOWN:
  312.                 gAIEnv.pMovementSystem->UnregisterEntity(GetEntityID());
  313.                 break;
  314.         default:
  315.                 assert(0);
  316.                 break;
  317.         }
  318. }
  319.  
  320. void CPipeUser::SetName(const char* pName)
  321. {
  322.         CCCPOINT(CPipeUser_SetName);
  323.  
  324.         CAIObject::SetName(pName);
  325.         char name[256];
  326.  
  327.         CAIObject* pRefPoint = m_refRefPoint.GetAIObject();
  328.         if (pRefPoint)
  329.         {
  330.                 cry_sprintf(name, "%s_RefPoint", pName);
  331.                 pRefPoint->SetName(name);
  332.         }
  333.  
  334.         CAIObject* pLookAtTarget = m_refLookAtTarget.GetAIObject();
  335.         if (pLookAtTarget)
  336.         {
  337.                 cry_sprintf(name, "%s_LookAtTarget", pName);
  338.                 pLookAtTarget->SetName(name);
  339.         }
  340. }
  341.  
  342. //
  343. //---------------------------------------------------------------------------------------------------------
  344. bool CPipeUser::ProcessBranchGoal(QGoal& Goal, bool& blocking)
  345. {
  346.         if (Goal.op != eGO_BRANCH)
  347.                 return false;
  348.  
  349.         blocking = Goal.bBlocking;
  350.  
  351.         bool bNot = (Goal.params.nValue & NOT) != 0;
  352.  
  353.         if (GetBranchCondition(Goal) ^ bNot)
  354.         {
  355.                 // string labels are already converted to integer relative offsets
  356.                 // TODO: cut the string version of Jump in a few weeks
  357.                 if (Goal.params.str.empty())
  358.                         blocking |= m_pCurrentGoalPipe->Jump(Goal.params.nValueAux);
  359.                 else
  360.                         blocking |= m_pCurrentGoalPipe->Jump(Goal.params.str);
  361.         }
  362.  
  363.         return true;
  364. }
  365.  
  366. //
  367. //---------------------------------------------------------------------------------------------------------
  368. bool CPipeUser::GetBranchCondition(QGoal& Goal)
  369. {
  370.         int branchType = Goal.params.nValue & (~NOT);
  371.  
  372.         // Fetch attention target, because it's used in many cases
  373.         CAIObject* pAttentionTarget = m_refAttentionTarget.GetAIObject();
  374.  
  375.         switch (branchType)
  376.         {
  377.         case IF_RANDOM:
  378.                 {
  379.                         if (cry_random(0.0f, 1.0f) <= Goal.params.fValue)
  380.                                 return true;
  381.                 }
  382.                 break;
  383.         case IF_NO_PATH:
  384.                 {
  385.                         if (m_nPathDecision == PATHFINDER_NOPATH)
  386.                                 return true;
  387.                 }
  388.                 break;
  389.         case IF_PATH_STILL_FINDING:
  390.                 {
  391.                         if (m_nPathDecision == PATHFINDER_STILLFINDING)
  392.                                 return true;
  393.                 }
  394.                 break;
  395.         case IF_IS_HIDDEN:  // branch if already at hide spot
  396.                 {
  397.                         if (!m_CurrentHideObject.IsValid())
  398.                                 return false;
  399.                         Vec3 diff(m_CurrentHideObject.GetLastHidePos() - GetPos());
  400.                         diff.z = 0.f;
  401.                         if (diff.len2() < Goal.params.fValue * Goal.params.fValue)
  402.                                 return true;
  403.                 }
  404.                 break;
  405.         case IF_CAN_HIDE: // branch if hide spot was found
  406.                 {
  407.                         if (m_CurrentHideObject.IsValid())
  408.                                 return true;
  409.                 }
  410.                 break;
  411.         case IF_CANNOT_HIDE:
  412.                 {
  413.                         if (!m_CurrentHideObject.IsValid())
  414.                                 return true;
  415.                 }
  416.                 break;
  417.         case IF_STANCE_IS:  // branch if stance is equal to params.fValue
  418.                 {
  419.                         if (m_State.bodystate == Goal.params.fValue)
  420.                                 return true;
  421.                 }
  422.                 break;
  423.         case IF_HAS_FIRED:  // jumps if the PipeUser just fired - fire flag passed to actor
  424.                 {
  425.                         if (m_State.fire)
  426.                                 return true;
  427.                 }
  428.                 break;
  429.         case IF_FIRE_IS:  // branch if last "firecmd" argument was equal to params.fValue
  430.                 {
  431.                         bool state = Goal.params.fValue > 0.5f;
  432.                         if (AllowedToFire() == state)
  433.                                 return true;
  434.                 }
  435.                 break;
  436.         case IF_NO_LASTOP:
  437.                 {
  438.                         if (m_refLastOpResult.IsNil() || !m_refLastOpResult.GetAIObject())
  439.                                 return true;
  440.                 }
  441.                 break;
  442.         case IF_SEES_LASTOP:
  443.                 {
  444.                         CAIObject* pLastOpResult = m_refLastOpResult.GetAIObject();
  445.                         if (pLastOpResult && GetAISystem()->CheckObjectsVisibility(this, pLastOpResult, Goal.params.fValue))
  446.                                 return true;
  447.                 }
  448.                 break;
  449.         case IF_SEES_TARGET:
  450.                 {
  451.                         if (Goal.params.fValueAux >= 0.0f)
  452.                         {
  453.                                 if (pAttentionTarget)
  454.                                 {
  455.                                         CCCPOINT(CPipeUser_GetBranchCondition_IF_SEES_TARGET);
  456.                                         SAIBodyInfo bi;
  457.  
  458.                                         if (GetProxy() && GetProxy()->QueryBodyInfo(SAIBodyInfoQuery((EStance)(int)Goal.params.fValueAux, 0.0f, 0.0f, false), bi))
  459.                                         {
  460.                                                 const Vec3& pos = bi.vEyePos;
  461.                                                 Vec3 dir = pAttentionTarget->GetPos() - pos;
  462.                                                 if (dir.GetLengthSquared() > sqr(Goal.params.fValue))
  463.                                                         dir.SetLength(Goal.params.fValue);
  464.  
  465.                                                 if (CanSee(pAttentionTarget->GetVisionID()))
  466.                                                         return true;
  467.                                         }
  468.                                 }
  469.                         }
  470.                         {
  471.                                 if (pAttentionTarget && GetAISystem()->CheckObjectsVisibility(this, pAttentionTarget, Goal.params.fValue))
  472.                                         return true;
  473.                         }
  474.                 }
  475.                 break;
  476.         case IF_TARGET_LOST_TIME_MORE:
  477.                 {
  478.                         CPuppet* pPuppet = CastToCPuppet();
  479.                         if (pPuppet && pPuppet->m_targetLostTime > Goal.params.fValue)
  480.                                 return true;
  481.                 }
  482.                 break;
  483.  
  484.         case IF_TARGET_LOST_TIME_LESS:
  485.                 {
  486.                         CPuppet* pPuppet = CastToCPuppet();
  487.                         if (pPuppet && pPuppet->m_targetLostTime <= Goal.params.fValue)
  488.                                 return true;
  489.                 }
  490.                 break;
  491.         case IF_EXPOSED_TO_TARGET:
  492.                 {
  493.                         if (pAttentionTarget)
  494.                         {
  495.                                 CCCPOINT(CPipeUser_GetBranchCondition_IF_EXPOSED_TO_TARGET);
  496.                                 Vec3 pos = GetPos();
  497.                                 SAIBodyInfo bi;
  498.                                 if (GetProxy() && GetProxy()->QueryBodyInfo(SAIBodyInfoQuery(STANCE_CROUCH, 0.0f, 0.0f, false), bi))
  499.                                         pos = bi.vEyePos;
  500.  
  501.                                 Vec3 dir(pAttentionTarget->GetPos() - pos);
  502.                                 dir.SetLength(Goal.params.fValue);
  503.                                 float dist;
  504.                                 bool exposed = !IntersectSweptSphere(0, dist, Lineseg(pos, pos + dir), Goal.params.fValueAux, AICE_ALL);
  505.                                 if (exposed)
  506.                                         return true;
  507.                         }
  508.                 }
  509.                 break;
  510.         case IF_CAN_SHOOT_TARGET_PRONED:
  511.                 {
  512.                         CCCPOINT(CPipeUser_GetbranchCondition_IF_CAN_SHOOT_TARGET_PRONED);
  513.  
  514.                         CPuppet* pPuppet = CastToCPuppet();
  515.                         if (pPuppet->CanFireInStance(STANCE_PRONE))
  516.                                 return true;
  517.                 }
  518.                 break;
  519.         case IF_CAN_SHOOT_TARGET_CROUCHED:
  520.                 {
  521.                         CCCPOINT(CPipeUser_GetbranchCondition_IF_CAN_SHOOT_TARGET_CROUCHED);
  522.  
  523.                         CPuppet* pPuppet = CastToCPuppet();
  524.                         if (pPuppet->CanFireInStance(STANCE_CROUCH))
  525.                                 return true;
  526.                 }
  527.                 break;
  528.         case IF_CAN_SHOOT_TARGET_STANDING:
  529.                 {
  530.                         CCCPOINT(CPipeUser_GetbranchCondition_IF_CAN_SHOOT_TARGET_STANDING);
  531.  
  532.                         CPuppet* pPuppet = CastToCPuppet();
  533.                         if (pPuppet->CanFireInStance(STANCE_STAND))
  534.                                 return true;
  535.                 }
  536.                 break;
  537.         case IF_CAN_SHOOT_TARGET:
  538.                 {
  539.                         Vec3 pos, dir;
  540.                         CPuppet* pPuppet = CastToCPuppet();
  541.                         bool aimOK = GetAimState() != AI_AIM_OBSTRUCTED;
  542.                         if (pAttentionTarget && pPuppet && pPuppet->GetFirecommandHandler() &&
  543.                             aimOK &&
  544.                             pPuppet->CanAimWithoutObstruction(pAttentionTarget->GetPos()) &&
  545.                             pPuppet->GetFirecommandHandler()->ValidateFireDirection(pAttentionTarget->GetPos() - GetFirePos(), false))
  546.                         {
  547.                                 CCCPOINT(CPipeUser_GetBranchCondition_IF_CAN_SHOOT_TARGET);
  548.                                 return true;
  549.                         }
  550.                 }
  551.                 break;
  552.         case IF_CAN_MELEE:
  553.                 {
  554.                         SAIWeaponInfo weaponInfo;
  555.                         GetProxy()->QueryWeaponInfo(weaponInfo);
  556.                         if (weaponInfo.canMelee)
  557.                                 return true;
  558.                 }
  559.                 break;
  560.         case IF_TARGET_DIST_LESS:
  561.         case IF_TARGET_DIST_GREATER:
  562.         case IF_TARGET_IN_RANGE:
  563.         case IF_TARGET_OUT_OF_RANGE:
  564.                 {
  565.                         CCCPOINT(CPipeUser_GetBranchCondition_IF_TARGET_A);
  566.                         if (pAttentionTarget)
  567.                         {
  568.                                 const Vec3& vPos = GetPos();
  569.                                 const Vec3& vTargetPos = pAttentionTarget->GetPos();
  570.                                 float fDist = Distance::Point_Point(vPos, vTargetPos);
  571.                                 if (branchType == IF_TARGET_DIST_LESS)
  572.                                 {
  573.                                         return (fDist <= Goal.params.fValue);
  574.                                 }
  575.                                 if (branchType == IF_TARGET_DIST_GREATER)
  576.                                 {
  577.                                         return (fDist > Goal.params.fValue);
  578.                                 }
  579.                                 if (branchType == IF_TARGET_IN_RANGE)
  580.                                 {
  581.                                         return (fDist <= m_Parameters.m_fAttackRange);
  582.                                 }
  583.                                 if (branchType == IF_TARGET_OUT_OF_RANGE)
  584.                                 {
  585.                                         return (fDist > m_Parameters.m_fAttackRange);
  586.                                 }
  587.                         }
  588.                 }
  589.                 break;
  590.         case IF_TARGET_MOVED_SINCE_START:
  591.         case IF_TARGET_MOVED:
  592.                 {
  593.                         CGoalPipe* pLastPipe(m_pCurrentGoalPipe->GetLastSubpipe());
  594.                         if (!pLastPipe) // this should NEVER happen
  595.                         {
  596.                                 AIError("CPipeUser::ProcessBranchGoal can get pipe. User: %s", GetName());
  597.                                 return true;
  598.                         }
  599.  
  600.                         if (pAttentionTarget)
  601.                         {
  602.                                 CCCPOINT(CPipeUser_GetBranchCondition_IF_TARGET_MOVED);
  603.                                 bool ret = Distance::Point_Point(pLastPipe->GetAttTargetPosAtStart(), pAttentionTarget->GetPos()) > Goal.params.fValue;
  604.                                 if (branchType == IF_TARGET_MOVED)
  605.                                         pLastPipe->SetAttTargetPosAtStart(pAttentionTarget->GetPos());
  606.                                 return ret;
  607.                         }
  608.                 }
  609.                 break;
  610.         case IF_NO_ENEMY_TARGET:
  611.                 {
  612.                         CCCPOINT(CPipeUser_GetBranchCondition_IF_NO_ENEMY_TARGET);
  613.                         if (!pAttentionTarget || !IsHostile(pAttentionTarget))
  614.                                 return true;
  615.                 }
  616.                 break;
  617.         case IF_PATH_LONGER:  // branch if current path is longer than params.fValue
  618.                 {
  619.                         float dbgPathLength(m_Path.GetPathLength(false));
  620.                         if (dbgPathLength > Goal.params.fValue)
  621.                                 return true;
  622.                 }
  623.                 break;
  624.         case IF_PATH_SHORTER:
  625.                 {
  626.                         float dbgPathLength(m_Path.GetPathLength(false));
  627.                         if (dbgPathLength <= Goal.params.fValue)
  628.                                 return true;
  629.                 }
  630.                 break;
  631.         case IF_PATH_LONGER_RELATIVE: // branch if current path is longer than (params.fValue) times the distance to destination
  632.                 {
  633.                         Vec3 pathDest(m_Path.GetParams().end);
  634.                         float pathLength = m_Path.GetPathLength(false);
  635.                         float dist = Distance::Point_Point(GetPos(), pathDest);
  636.                         if (pathLength >= dist * Goal.params.fValue)
  637.                                 return true;
  638.                 }
  639.                 break;
  640.         case IF_NAV_WAYPOINT_HUMAN:   // branch if current navigation graph is waypoint
  641.                 {
  642.                         int nBuilding;
  643.                         IAISystem::ENavigationType navType = gAIEnv.pNavigation->CheckNavigationType(GetPos(), nBuilding, m_movementAbility.pathfindingProperties.navCapMask);
  644.                         if (navType == IAISystem::NAV_WAYPOINT_HUMAN)
  645.                                 return true;
  646.                 }
  647.                 break;
  648.         case IF_NAV_TRIANGULAR:   // branch if current navigation graph is triangular
  649.                 {
  650.                         int nBuilding;
  651.                         IAISystem::ENavigationType navType = gAIEnv.pNavigation->CheckNavigationType(GetPos(), nBuilding, m_movementAbility.pathfindingProperties.navCapMask);
  652.                         if (navType == IAISystem::NAV_TRIANGULAR)
  653.                                 return true;
  654.                 }
  655.         case IF_COVER_COMPROMISED:
  656.         case IF_COVER_NOT_COMPROMISED:  // jumps if the current cover cannot be used for hiding or if the hide spots does not exists.
  657.                 {
  658.                         CCCPOINT(CPipeUser_GetBranchCondition_IF_COVER_COMPROMISED);
  659.                         bool bCompromised = true;
  660.                         if (pAttentionTarget)
  661.                                 bCompromised = m_CurrentHideObject.IsCompromised(this, pAttentionTarget->GetPos());
  662.  
  663.                         bool bResult = bCompromised;
  664.                         if (Goal.params.nValue == IF_COVER_NOT_COMPROMISED)
  665.                                 bResult = !bResult;
  666.  
  667.                         if (bResult)
  668.                                 return true;
  669.                 }
  670.                 break;
  671.         case IF_COVER_FIRE_ENABLED: // branch if cover firemode is  enabled
  672.                 {
  673.                         CPuppet* pPuppet = CastToCPuppet();
  674.                         if (pPuppet)
  675.                                 return !pPuppet->IsCoverFireEnabled();
  676.                 }
  677.                 break;
  678.         case IF_COVER_SOFT:
  679.                 {
  680.                         bool isEmptyCover = m_CurrentHideObject.IsCoverPathComplete() && m_CurrentHideObject.GetCoverWidth(true) < 0.1f;
  681.                         bool soft = !m_CurrentHideObject.IsObjectCollidable() || isEmptyCover;
  682.                         if (soft)
  683.                                 return true;
  684.                 }
  685.                 break;
  686.         case IF_COVER_NOT_SOFT:
  687.                 {
  688.                         bool isEmptyCover = m_CurrentHideObject.IsCoverPathComplete() && m_CurrentHideObject.GetCoverWidth(true) < 0.1f;
  689.                         bool soft = !m_CurrentHideObject.IsObjectCollidable() || isEmptyCover;
  690.                         if (soft)
  691.                                 return true;
  692.                 }
  693.                 break;
  694.  
  695.         case IF_LASTOP_FAILED:
  696.                 {
  697.                         if (m_pCurrentGoalPipe && m_pCurrentGoalPipe->GetLastResult() == eGOR_FAILED)
  698.                                 return true;
  699.                 }
  700.                 break;
  701.  
  702.         case IF_LASTOP_SUCCEED:
  703.                 {
  704.                         if (m_pCurrentGoalPipe && m_pCurrentGoalPipe->GetLastResult() == eGOR_SUCCEEDED)
  705.                                 return true;
  706.                 }
  707.                 break;
  708.  
  709.         case IF_LASTOP_DIST_LESS:
  710.                 {
  711.                         CAIObject* pLastOpResult = m_refLastOpResult.GetAIObject();
  712.                         if (pLastOpResult && (Distance::Point_Point(GetPos(), pLastOpResult->GetPos()) < Goal.params.fValue))
  713.                         {
  714.                                 return true;
  715.                         }
  716.                 }
  717.                 break;
  718.  
  719.         case IF_LASTOP_DIST_LESS_ALONG_PATH:
  720.                 {
  721.                         CAIObject* pLastOpResult = m_refLastOpResult.GetAIObject();
  722.                         if (pLastOpResult && (m_nPathDecision == PATHFINDER_PATHFOUND))
  723.                         {
  724.                                 CPuppet* pPuppet = CastToCPuppet();
  725.                                 if (pPuppet)
  726.                                 {
  727.                                         const Vec3& vMyPos = GetPos();
  728.                                         float dist = m_movementAbility.b3DMove ? Distance::Point_Point(vMyPos, pLastOpResult->GetPos())
  729.                                                      : Distance::Point_Point2D(vMyPos, pLastOpResult->GetPos());
  730.                                         float distPath = pPuppet->GetDistanceAlongPath(pLastOpResult->GetPos(), true);
  731.                                         if (dist < distPath)
  732.                                         {
  733.                                                 dist = distPath;
  734.                                         }
  735.                                         if (dist < Goal.params.fValue)
  736.                                         {
  737.                                                 return true;
  738.                                         }
  739.                                 }
  740.                         }
  741.                 }
  742.                 break;
  743.  
  744.         case BRANCH_ALWAYS: // branches always
  745.                 return true;
  746.                 break;
  747.  
  748.         case IF_ACTIVE_GOALS_HIDE:
  749.                 if (!m_vActiveGoals.empty() || !m_CurrentHideObject.IsValid())
  750.                         return true;
  751.                 break;
  752.  
  753.         default://IF_ACTIVE_GOALS
  754.                 if (!m_vActiveGoals.empty())
  755.                         return true;
  756.                 break;
  757.         }
  758.  
  759.         return false;
  760. }
  761.  
  762. void CPipeUser::Update(EObjectUpdate type)
  763. {
  764.         IAIActorProxy* pAIActorProxy = GetProxy();
  765.  
  766.         if (!CastToCPuppet())
  767.         {
  768.                 if (!IsEnabled())
  769.                 {
  770.                         AIWarning("CPipeUser::Update: Trying to update disabled Puppet: %s", GetName());
  771.                         AIAssert(0);
  772.                         return;
  773.                 }
  774.  
  775.                 // There should never be Pipe Users without proxies.
  776.                 if (!pAIActorProxy)
  777.                 {
  778.                         AIWarning("CPipeUser::Update: Pipe User does not have proxy: %s", GetName());
  779.                         AIAssert(0);
  780.                         return;
  781.                 }
  782.                 // There should never be Pipe Users without physics.
  783.                 if (!GetPhysics())
  784.                 {
  785.                         AIWarning("CPipeUser::Update: Pipe User does not have physics: %s", GetName());
  786.                         AIAssert(0);
  787.                         return;
  788.                 }
  789.                 // dead Pipe Users should never be updated
  790.                 if (pAIActorProxy->IsDead())
  791.                 {
  792.                         AIWarning("CPipeUser::Update: Trying to update dead Pipe User: %s ", GetName());
  793.                         AIAssert(0);
  794.                         return;
  795.                 }
  796.         }
  797.  
  798.         CAIActor::Update(type);
  799.  
  800.         Vec3 pos = GetPhysicsPos();
  801.  
  802.         if (m_refAttentionTarget.IsValid() && m_coverUser.GetCoverID())
  803.         {
  804.                 if (type == AIUPDATE_FULL)
  805.                 {
  806.                         CAIObject* attTarget = m_refAttentionTarget.GetAIObject();
  807.  
  808.                         if (attTarget)
  809.                         {
  810.                                 Vec3 eyes[8];
  811.                                 const uint32 MaxEyeCount = std::min<uint32>(gAIEnv.CVars.CoverMaxEyeCount, CRY_ARRAY_COUNT(eyes));
  812.  
  813.                                 uint32 eyeCount = GetCoverEyes(attTarget, attTarget->GetPos(), eyes, MaxEyeCount);
  814.  
  815.                                 const bool coverWasNoLongerValidBeforeUpdate = m_coverUser.IsCompromised() || m_coverUser.IsFarFromCoverLocation();
  816.  
  817.                                 if (m_movingToCover || m_movingInCover)
  818.                                         m_coverUser.UpdateWhileMoving(m_fTimePassed, pos, &eyes[0], eyeCount);
  819.                                 else if (m_inCover)
  820.                                         m_coverUser.Update(m_fTimePassed, pos, &eyes[0], eyeCount, m_Parameters.effectiveCoverHeight);
  821.  
  822.                                 const bool coverIsNoLongerValidAfterUpdate = m_coverUser.IsCompromised() || m_coverUser.IsFarFromCoverLocation();
  823.  
  824.                                 if (coverIsNoLongerValidAfterUpdate && !coverWasNoLongerValidBeforeUpdate)
  825.                                 {
  826.                                         //          if (gAIEnv.CVars.DebugDrawCover && (locationEffectiveHeight < minEffectiveCoverHeight))
  827.                                         //          {
  828.                                         //            #ifdef CRYAISYSTEM_DEBUG
  829.                                         //            GetAISystem()->AddDebugCone(GetCoverLocation() + (CoverUp * locationEffectiveHeight), -CoverUp, 0.15f,
  830.                                         //              locationEffectiveHeight, Col_Red,       3.0f);
  831.                                         //            #endif
  832.                                         //          }
  833.  
  834.                                         SetCoverCompromised();
  835.                                 }
  836.                                 else
  837.                                 {
  838.                                         //          if ((m_inCover || m_movingInCover) && !m_adjustingAim)
  839.                                         //          {
  840.                                         //            float effectiveHeight = m_coverUser.GetEffectiveHeight();
  841.                                         //
  842.                                         //            if (effectiveHeight >= m_Parameters.effectiveHighCoverHeight)
  843.                                         //              SetSignal(1, "OnHighCover", 0, 0, gAIEnv.SignalCRCs.m_nOnHighCover);
  844.                                         //            else
  845.                                         //              SetSignal(1, "OnLowCover", 0, 0, gAIEnv.SignalCRCs.m_nOnLowCover);
  846.                                         //          }
  847.                                 }
  848.                         }
  849.                 }
  850.         }
  851.  
  852.         if ((m_inCover || m_movingInCover) && m_coverUser.GetCoverID())
  853.         {
  854.                 m_coverUser.UpdateNormal(pos);
  855.  
  856.                 const Vec3& coverNormal = m_coverUser.GetCoverNormal();
  857.                 const Vec3& coverPos = m_coverUser.GetCoverLocation();
  858.                 SetBodyTargetDir(-coverNormal); // TODO: Remove this if old cover alignment method is not needed anymore
  859.                 m_State.coverRequest.SetCoverLocation(coverPos, -coverNormal);
  860.         }
  861.  
  862.         UpdateCoverBlacklist(gEnv->pTimer->GetFrameTime());
  863.  
  864.         CAIObject* pAttentionTarget = m_refAttentionTarget.GetAIObject();
  865.  
  866.         if (type == AIUPDATE_FULL)
  867.         {
  868.                 if (m_CurrentHideObject.IsValid())
  869.                 {
  870.                         m_CurrentHideObject.Update(this);
  871.  
  872.                         if (pAttentionTarget && m_CurrentHideObject.IsCompromised(this, pAttentionTarget->GetPos()))
  873.                                 SetCoverCompromised();
  874.                 }
  875.  
  876.                 // Update some special objects if they have been recently used.
  877.  
  878.                 Vec3 vProbTargetPos = ZERO;
  879.  
  880.                 CAIObject* pSpecialAIObject = m_refSpecialObjects[AISPECIAL_PROBTARGET_IN_TERRITORY].GetAIObject();
  881.                 if (pSpecialAIObject && pSpecialAIObject->m_bTouched)
  882.                 {
  883.                         pSpecialAIObject->m_bTouched = false;
  884.                         if (vProbTargetPos.IsZero())
  885.                                 vProbTargetPos = GetProbableTargetPosition();
  886.                         Vec3 vPos = vProbTargetPos;
  887.                         // Clamp the point to the territory shape.
  888.                         if (SShape* pShape = GetTerritoryShape())
  889.                                 pShape->ConstrainPointInsideShape(vPos, true);
  890.  
  891.                         pSpecialAIObject->SetPos(vPos);
  892.                 }
  893.  
  894.                 pSpecialAIObject = m_refSpecialObjects[AISPECIAL_PROBTARGET_IN_REFSHAPE].GetAIObject();
  895.                 if (pSpecialAIObject && pSpecialAIObject->m_bTouched)
  896.                 {
  897.                         pSpecialAIObject->m_bTouched = false;
  898.                         if (vProbTargetPos.IsZero())
  899.                                 vProbTargetPos = GetProbableTargetPosition();
  900.                         Vec3 vPos = vProbTargetPos;
  901.                         // Clamp the point to ref shape
  902.                         if (SShape* pShape = GetRefShape())
  903.                                 pShape->ConstrainPointInsideShape(vPos, true);
  904.  
  905.                         pSpecialAIObject->SetPos(vPos);
  906.                 }
  907.  
  908.                 pSpecialAIObject = m_refSpecialObjects[AISPECIAL_PROBTARGET_IN_TERRITORY_AND_REFSHAPE].GetAIObject();
  909.                 if (pSpecialAIObject && pSpecialAIObject->m_bTouched)
  910.                 {
  911.                         pSpecialAIObject->m_bTouched = false;
  912.                         if (vProbTargetPos.IsZero())
  913.                                 vProbTargetPos = GetProbableTargetPosition();
  914.                         Vec3 vPos = vProbTargetPos;
  915.                         // Clamp the point to ref shape
  916.                         if (SShape* pShape = GetRefShape())
  917.                                 pShape->ConstrainPointInsideShape(vPos, true);
  918.                         // Clamp the point to the territory shape.
  919.                         if (SShape* pShape = GetTerritoryShape())
  920.                                 pShape->ConstrainPointInsideShape(vPos, true);
  921.  
  922.                         pSpecialAIObject->SetPos(vPos);
  923.                 }
  924.  
  925.                 pSpecialAIObject = m_refSpecialObjects[AISPECIAL_ATTTARGET_IN_REFSHAPE].GetAIObject();
  926.  
  927.                 if (pSpecialAIObject && pSpecialAIObject->m_bTouched)
  928.                 {
  929.                         pSpecialAIObject->m_bTouched = false;
  930.                         if (pAttentionTarget)
  931.                         {
  932.                                 Vec3 vPos = pAttentionTarget->GetPos();
  933.                                 // Clamp the point to ref shape
  934.                                 if (SShape* pShape = GetRefShape())
  935.                                         pShape->ConstrainPointInsideShape(vPos, true);
  936.                                 // Update pos
  937.                                 pSpecialAIObject->SetPos(vPos);
  938.                         }
  939.                         else
  940.                         {
  941.                                 pSpecialAIObject->SetPos(GetPos());
  942.                         }
  943.                 }
  944.  
  945.                 pSpecialAIObject = m_refSpecialObjects[AISPECIAL_ATTTARGET_IN_TERRITORY].GetAIObject();
  946.                 if (pSpecialAIObject && pSpecialAIObject->m_bTouched)
  947.                 {
  948.                         pSpecialAIObject->m_bTouched = false;
  949.                         if (pAttentionTarget)
  950.                         {
  951.                                 Vec3 vPos = pAttentionTarget->GetPos();
  952.                                 // Clamp the point to ref shape
  953.                                 if (SShape* pShape = GetTerritoryShape())
  954.                                         pShape->ConstrainPointInsideShape(vPos, true);
  955.                                 // Update pos
  956.                                 pSpecialAIObject->SetPos(vPos);
  957.                         }
  958.                         else
  959.                         {
  960.                                 pSpecialAIObject->SetPos(GetPos());
  961.                         }
  962.                 }
  963.  
  964.                 pSpecialAIObject = m_refSpecialObjects[AISPECIAL_ATTTARGET_IN_TERRITORY_AND_REFSHAPE].GetAIObject();
  965.                 if (pSpecialAIObject && pSpecialAIObject->m_bTouched)
  966.                 {
  967.                         pSpecialAIObject->m_bTouched = false;
  968.                         if (pAttentionTarget)
  969.                         {
  970.                                 Vec3 vPos = pAttentionTarget->GetPos();
  971.                                 // Clamp the point to ref shape
  972.                                 if (SShape* pShape = GetRefShape())
  973.                                         pShape->ConstrainPointInsideShape(vPos, true);
  974.                                 // Clamp the point to the territory shape.
  975.                                 if (SShape* pShape = GetTerritoryShape())
  976.                                         pShape->ConstrainPointInsideShape(vPos, true);
  977.  
  978.                                 pSpecialAIObject->SetPos(vPos);
  979.                         }
  980.                         else
  981.                         {
  982.                                 pSpecialAIObject->SetPos(GetPos());
  983.                         }
  984.                 }
  985.         }
  986.  
  987.         // make sure to update direction when entity is not moved
  988.         const SAIBodyInfo& bodyInfo = GetBodyInfo();
  989.  
  990.         SetPos(bodyInfo.vEyePos);
  991.         SetBodyDir(bodyInfo.GetBodyDir());
  992.         SetEntityDir(bodyInfo.vEntityDir);
  993.         SetMoveDir(bodyInfo.vMoveDir);
  994.         SetViewDir(bodyInfo.GetEyeDir());
  995.  
  996.         // Handle navigational smart object start and end states before executing goalpipes.
  997.         if (m_eNavSOMethod == nSOmSignalAnimation || m_eNavSOMethod == nSOmActionAnimation)
  998.         {
  999.                 if (m_currentNavSOStates.IsEmpty())
  1000.                 {
  1001.                         if (m_State.curActorTargetPhase == eATP_Started || m_State.curActorTargetPhase == eATP_StartedAndFinished)
  1002.                         {
  1003.                                 // Copy the set state to the currently used state.
  1004.                                 m_currentNavSOStates = m_pendingNavSOStates;
  1005.                                 m_pendingNavSOStates.Clear();
  1006.  
  1007.                                 // keep track of last used smart object
  1008.                                 m_idLastUsedSmartObject = m_currentNavSOStates.objectEntId;
  1009.  
  1010.                                 SetSignal(1, "OnEnterNavSO");
  1011.                         }
  1012.                 }
  1013.  
  1014.                 if (m_State.curActorTargetPhase == eATP_StartedAndFinished || m_State.curActorTargetPhase == eATP_Finished)
  1015.                 {
  1016.                         // modify smart object states
  1017.                         IEntity* pObjectEntity = gEnv->pEntitySystem->GetEntity(m_currentNavSOStates.objectEntId);
  1018.                         gAIEnv.pSmartObjectManager->ModifySmartObjectStates(GetEntity(), m_currentNavSOStates.sAnimationDoneUserStates);
  1019.                         if (pObjectEntity)
  1020.                                 gAIEnv.pSmartObjectManager->ModifySmartObjectStates(pObjectEntity, m_currentNavSOStates.sAnimationDoneObjectStates);
  1021.  
  1022.                         m_currentNavSOStates.Clear();
  1023.                         m_eNavSOMethod = nSOmNone;
  1024.  
  1025.                         SetSignal(1, "OnLeaveNavSO");
  1026.                 }
  1027.         }
  1028.  
  1029.         if (!CastToCPuppet())
  1030.         {
  1031.                 //m_State.Reset();
  1032.  
  1033.                 if (type != AIUPDATE_FULL)
  1034.                 {
  1035.                         //if approaching then always update
  1036.                         for (size_t i = 0; i < m_vActiveGoals.size(); i++)
  1037.                         {
  1038.                                 QGoal& Goal = m_vActiveGoals[i];
  1039.                                 Goal.pGoalOp->ExecuteDry(this);
  1040.                         }
  1041.                 }
  1042.                 else
  1043.                 {
  1044.                         GetStateFromActiveGoals(m_State);
  1045.  
  1046.                         m_lightLevel = GetAISystem()->GetLightManager()->GetLightLevelAt(GetPos(), this, &m_usingCombatLight);
  1047.                 }
  1048.  
  1049.                 HandleNavSOFailure();
  1050.                 SyncActorTargetPhaseWithAIProxy();
  1051.  
  1052.                 m_State.vBodyTargetDir = m_vBodyTargetDir;
  1053.                 m_State.vDesiredBodyDirectionAtTarget = m_vDesiredBodyDirectionAtTarget;
  1054.                 m_State.movementContext = m_movementContext;
  1055.  
  1056.                 CAIObject* pAttTarget = m_refAttentionTarget.GetAIObject();
  1057.                 if (pAttTarget && pAttTarget->IsEnabled())
  1058.                 {
  1059.                         if (CanSee(pAttTarget->GetVisionID()))
  1060.                         {
  1061.                                 m_AttTargetType = m_State.eTargetType = AITARGET_VISUAL;
  1062.                                 m_State.nTargetType = pAttTarget->GetType();
  1063.                                 m_State.bTargetEnabled = true;
  1064.                         }
  1065.                         else
  1066.                         {
  1067.                                 switch (m_State.eTargetType)
  1068.                                 {
  1069.                                 case AITARGET_VISUAL:
  1070.                                         m_AttTargetThreat = m_State.eTargetThreat = AITHREAT_AGGRESSIVE;
  1071.                                         m_AttTargetType = m_State.eTargetType = AITARGET_MEMORY;
  1072.                                         m_State.nTargetType = pAttTarget->GetType();
  1073.                                         m_State.bTargetEnabled = true;
  1074.                                         m_stimulusStartTime = GetAISystem()->GetFrameStartTimeSeconds();
  1075.                                         break;
  1076.  
  1077.                                 case AITARGET_MEMORY:
  1078.                                 case AITARGET_SOUND:
  1079.                                         if (GetAISystem()->GetFrameStartTimeSeconds() - m_stimulusStartTime >= 5.f)
  1080.                                         {
  1081.                                                 m_State.nTargetType = -1;
  1082.                                                 m_State.bTargetEnabled = false;
  1083.                                                 m_State.eTargetThreat = AITHREAT_NONE;
  1084.                                                 m_AttTargetType = m_State.eTargetType = AITARGET_NONE;
  1085.  
  1086.                                                 SetAttentionTarget(NILREF);
  1087.                                         }
  1088.                                         break;
  1089.                                 }
  1090.                         }
  1091.                 }
  1092.                 else
  1093.                 {
  1094.                         if ((m_State.nTargetType != -1) ||
  1095.                             m_State.bTargetEnabled ||
  1096.                             (m_State.eTargetThreat != AITHREAT_NONE) ||
  1097.                             (m_State.eTargetType != AITARGET_NONE))
  1098.                         {
  1099.                                 SetAttentionTarget(NILREF);
  1100.                         }
  1101.  
  1102.                         m_State.nTargetType = -1;
  1103.                         m_State.bTargetEnabled = false;
  1104.                         m_State.eTargetThreat = AITHREAT_NONE;
  1105.                         m_State.eTargetType = AITARGET_NONE;
  1106.                 }
  1107.  
  1108.                 //--------------------------------------------------------
  1109.                 // Update the look logic, unless AI is paused for things like communications.
  1110.                 if (m_bEnableUpdateLookTarget)
  1111.                 {
  1112.                         if (!m_paused)
  1113.                         {
  1114.                                 UpdateLookTarget(pAttentionTarget);
  1115.                         }
  1116.                 }
  1117.                 else
  1118.                 {
  1119.                         m_State.vLookTargetPos.zero();
  1120.                 }
  1121.         }
  1122. }
  1123.  
  1124. bool CPipeUser::IsAdjustingAim() const
  1125. {
  1126.         return m_adjustingAim;
  1127. }
  1128.  
  1129. void CPipeUser::SetAdjustingAim(bool adjustingAim)
  1130. {
  1131.         m_adjustingAim = adjustingAim;
  1132. }
  1133.  
  1134. bool CPipeUser::IsInCover() const
  1135. {
  1136.         return m_inCover;
  1137. }
  1138.  
  1139. bool CPipeUser::IsMovingToCover() const
  1140. {
  1141.         return m_movingToCover;
  1142. }
  1143.  
  1144. void CPipeUser::SetMovingToCover(bool movingToCover)
  1145. {
  1146.         if (m_movingToCover != movingToCover)
  1147.         {
  1148.                 if (movingToCover)
  1149.                         SetSignal(1, "OnMovingToCover", 0, 0, gAIEnv.SignalCRCs.m_nOnMovingToCover);
  1150.  
  1151.                 m_movingToCover = movingToCover;
  1152.         }
  1153. }
  1154.  
  1155. bool CPipeUser::IsMovingInCover() const
  1156. {
  1157.         return m_movingInCover;
  1158. }
  1159.  
  1160. void CPipeUser::SetMovingInCover(bool movingInCover)
  1161. {
  1162.         if (m_movingInCover != movingInCover)
  1163.         {
  1164.                 if (movingInCover)
  1165.                         SetSignal(1, "OnMovingInCover", 0, 0, gAIEnv.SignalCRCs.m_nOnMovingInCover);
  1166.  
  1167.                 m_movingInCover = movingInCover;
  1168.         }
  1169. }
  1170.  
  1171. void CPipeUser::SetInCover(bool inCover)
  1172. {
  1173.         assert(!inCover || m_coverUser.GetCoverID());
  1174.  
  1175.         if (m_inCover != inCover)
  1176.         {
  1177.                 if (inCover)
  1178.                 {
  1179.                         SetSignal(1, "OnEnterCover", 0, 0, gAIEnv.SignalCRCs.m_nOnEnterCover);
  1180.                 }
  1181.                 else
  1182.                 {
  1183.                         SetCoverID(CoverID());
  1184.                         ResetBodyTargetDir();
  1185.                         SetSignal(1, "OnLeaveCover", 0, 0, gAIEnv.SignalCRCs.m_nOnLeaveCover);
  1186.                 }
  1187.  
  1188.                 m_inCover = inCover;
  1189.         }
  1190. }
  1191.  
  1192. void CPipeUser::SetCoverCompromised()
  1193. {
  1194.         if (m_inCover || m_movingToCover)
  1195.         {
  1196.                 SetSignal(1, "OnCoverCompromised", 0, 0, gAIEnv.SignalCRCs.m_nOnCoverCompromised);
  1197.  
  1198.                 if (CoverID coverID = m_coverUser.GetCoverID())
  1199.                         SetCoverBlacklisted(coverID, true, 10.0f);
  1200.  
  1201.                 SetInCover(false);
  1202.  
  1203.                 m_coverUser.SetCoverID(CoverID());
  1204.         }
  1205. }
  1206.  
  1207. //
  1208. //---------------------------------------------------------------------------------------------------------
  1209. bool CPipeUser::IsCoverCompromised() const
  1210. {
  1211.         if (gAIEnv.CVars.CoverSystem)
  1212.         {
  1213.                 return m_coverUser.IsCompromised();
  1214.         }
  1215.         else
  1216.         {
  1217.                 CAIObject* pAttentionTarget = m_refAttentionTarget.GetAIObject();
  1218.                 if (!pAttentionTarget)
  1219.                         return false;
  1220.  
  1221.                 if (m_CurrentHideObject.IsValid())
  1222.                         return m_CurrentHideObject.IsCompromised(this, pAttentionTarget->GetPos());
  1223.  
  1224.                 return true;
  1225.         }
  1226. }
  1227.  
  1228. //
  1229. //---------------------------------------------------------------------------------------------------------
  1230. bool CPipeUser::IsTakingCover(float distanceThreshold) const
  1231. {
  1232.         if (IsInCover())
  1233.                 return true;
  1234.  
  1235.         if ((distanceThreshold > 0.0f) && (IsMovingToCover()))
  1236.                 return m_State.fDistanceToPathEnd < distanceThreshold;
  1237.  
  1238.         return false;
  1239. }
  1240.  
  1241. void CPipeUser::SetCoverID(const CoverID& coverID)
  1242. {
  1243.         if (coverID)
  1244.         {
  1245.                 CoverUser::Params params;
  1246.                 params.distanceToCover = m_Parameters.distanceToCover;
  1247.                 params.inCoverRadius = m_Parameters.inCoverRadius;
  1248.                 params.userID = GetAIObjectID();
  1249.  
  1250.                 m_coverUser.SetParams(params);
  1251.         }
  1252.  
  1253.         m_coverUser.SetCoverID(coverID);
  1254. }
  1255.  
  1256. const CoverID& CPipeUser::GetCoverID() const
  1257. {
  1258.         return m_coverUser.GetCoverID();
  1259. }
  1260.  
  1261. Vec3 CPipeUser::GetCoverLocation() const
  1262. {
  1263.         return m_coverUser.GetCoverLocation();
  1264. }
  1265.  
  1266. inline bool HasPointInRangeSq(const Vec3* points, uint32 pointCount, const Vec3& pos, float rangeSq)
  1267. {
  1268.         for (uint32 i = 0; i < pointCount; ++i)
  1269.         {
  1270.                 if (Distance::Point_PointSq(points[i], pos) < rangeSq)
  1271.                         return true;
  1272.         }
  1273.  
  1274.         return false;
  1275. }
  1276.  
  1277. uint32 CPipeUser::GetCoverEyes(CAIObject* targetEnemy, const Vec3& enemyTargetLocation, Vec3* eyes, uint32 maxCount) const
  1278. {
  1279.         uint32 eyeCount = 0;
  1280.         if (!enemyTargetLocation.IsZero())
  1281.                 eyes[eyeCount++] = enemyTargetLocation;
  1282.  
  1283.         bool prediction = gAIEnv.CVars.CoverPredictTarget > 0.001f;
  1284.  
  1285.         if (!targetEnemy)
  1286.                 return eyeCount;
  1287.  
  1288.         const float RangeThresholdSq = sqr(0.5f);
  1289.  
  1290.         if (prediction && (eyeCount < maxCount) && targetEnemy->IsAgent())
  1291.         {
  1292.                 Vec3 targetVelocity = targetEnemy->GetVelocity();
  1293.                 Vec3 futureLocation = eyes[eyeCount - 1] + targetVelocity * gAIEnv.CVars.CoverPredictTarget;
  1294.  
  1295.                 if (!HasPointInRangeSq(eyes, eyeCount, futureLocation, RangeThresholdSq))
  1296.                 {
  1297.                         eyes[eyeCount] = futureLocation;
  1298.                         ++eyeCount;
  1299.                 }
  1300.         }
  1301.  
  1302.         if (eyeCount < maxCount)
  1303.         {
  1304.                 if (const CPuppet* puppet = CastToCPuppet())
  1305.                 {
  1306.                         tAIObjectID targetID = targetEnemy->GetAIObjectID();
  1307.                         tAIObjectID targetAssociationID = targetEnemy->GetAssociation().GetObjectID();
  1308.  
  1309.                         const uint32 MaxTargets = 8;
  1310.                         tAIObjectID targets[MaxTargets];
  1311.  
  1312.                         uint32 targetCount = puppet->GetBestTargets(targets, MaxTargets);
  1313.  
  1314.                         for (uint32 i = 0; i < targetCount; ++i)
  1315.                         {
  1316.                                 tAIObjectID nextTargetID = targets[i];
  1317.                                 if (nextTargetID != targetID && nextTargetID != targetAssociationID)
  1318.                                 {
  1319.                                         if (IAIObject* nextTargetObject = gAIEnv.pObjectContainer->GetAIObject(nextTargetID))
  1320.                                         {
  1321.                                                 if (CanSee(nextTargetObject->GetVisionID()))
  1322.                                                 {
  1323.                                                         Vec3 location = nextTargetObject->GetPos();
  1324.  
  1325.                                                         if (!HasPointInRangeSq(eyes, eyeCount, location, RangeThresholdSq))
  1326.                                                         {
  1327.                                                                 eyes[eyeCount] = location;
  1328.                                                                 ++eyeCount;
  1329.                                                         }
  1330.  
  1331.                                                         if (prediction && (eyeCount < maxCount) && nextTargetObject->IsAgent())
  1332.                                                         {
  1333.                                                                 Vec3 targetVelocity = nextTargetObject->GetVelocity();
  1334.                                                                 Vec3 futureLocation = eyes[eyeCount - 1] + targetVelocity * gAIEnv.CVars.CoverPredictTarget;
  1335.  
  1336.                                                                 if (!HasPointInRangeSq(eyes, eyeCount, futureLocation, RangeThresholdSq))
  1337.                                                                 {
  1338.                                                                         eyes[eyeCount] = futureLocation;
  1339.                                                                         ++eyeCount;
  1340.                                                                 }
  1341.                                                         }
  1342.                                                 }
  1343.                                         }
  1344.                                 }
  1345.  
  1346.                                 if (eyeCount >= maxCount)
  1347.                                         break;
  1348.                         }
  1349.                 }
  1350.         }
  1351.  
  1352.         return eyeCount;
  1353. }
  1354.  
  1355. void CPipeUser::UpdateCoverBlacklist(float updateTime)
  1356. {
  1357.         CoverBlacklist::iterator it = m_coverBlacklist.begin();
  1358.         CoverBlacklist::iterator end = m_coverBlacklist.end();
  1359.  
  1360.         for (; it != end; )
  1361.         {
  1362.                 float& time = it->second;
  1363.                 time -= updateTime;
  1364.  
  1365.                 if (time > 0.0f)
  1366.                 {
  1367.                         ++it;
  1368.                         continue;
  1369.                 }
  1370.  
  1371.                 m_coverBlacklist.erase(it++);
  1372.                 end = m_coverBlacklist.end();
  1373.         }
  1374. }
  1375.  
  1376. void CPipeUser::ResetCoverBlacklist()
  1377. {
  1378.         m_coverBlacklist.clear();
  1379. }
  1380.  
  1381. void CPipeUser::SetCoverBlacklisted(const CoverID& coverID, bool blacklist, float time)
  1382. {
  1383.         if (blacklist)
  1384.         {
  1385.                 std::pair<CoverBlacklist::iterator, bool> iresult = m_coverBlacklist.insert(CoverBlacklist::value_type(coverID, time));
  1386.                 if (!iresult.second)
  1387.                         iresult.first->second = time;
  1388.         }
  1389.         else
  1390.                 m_coverBlacklist.erase(coverID);
  1391. }
  1392.  
  1393. bool CPipeUser::IsCoverBlacklisted(const CoverID& coverID) const
  1394. {
  1395.         return m_coverBlacklist.find(coverID) != m_coverBlacklist.end();
  1396. }
  1397.  
  1398. CoverHeight CPipeUser::CalculateEffectiveCoverHeight() const
  1399. {
  1400.         Vec3 eyes[8];
  1401.         const uint32 MaxEyeCount = std::min<uint32>(gAIEnv.CVars.CoverMaxEyeCount, CRY_ARRAY_COUNT(eyes));
  1402.         CAIObject* attTarget = m_refAttentionTarget.GetAIObject();
  1403.         uint32 eyeCount = 0;
  1404.         if (attTarget)
  1405.                 eyeCount = GetCoverEyes(attTarget, attTarget->GetPos(), eyes, MaxEyeCount);
  1406.         const float effectiveHeight = m_coverUser.CalculateEffectiveHeightAt(GetPhysicsPos(), eyes, eyeCount);
  1407.         return (effectiveHeight >= m_Parameters.effectiveHighCoverHeight) ? HighCover : LowCover;
  1408. }
  1409.  
  1410. //
  1411. //-------------------------------------------------------------------------------------------------------------
  1412. enum ECoverUsageCheckLocation
  1413. {
  1414.         LowLeft = 0,
  1415.         LowCenter,
  1416.         LowRight,
  1417.         HighLeft,
  1418.         HighCenter,
  1419.         HighRight,
  1420. };
  1421.  
  1422. AsyncState CPipeUser::GetCoverUsageInfo(CoverUsageInfo& coverUsageInfo)
  1423. {
  1424.         FUNCTION_PROFILER(GetISystem(), PROFILE_AI);
  1425.  
  1426.         if (m_coverUsageInfoState.state == AsyncComplete)
  1427.         {
  1428.                 coverUsageInfo = m_coverUsageInfoState.result;
  1429.                 m_coverUsageInfoState.state = AsyncReady;
  1430.  
  1431.                 return AsyncComplete;
  1432.         }
  1433.  
  1434.         IAIObject* attentionTarget = GetAttentionTarget();
  1435.         if (!attentionTarget)
  1436.         {
  1437.                 coverUsageInfo = CoverUsageInfo(false);
  1438.  
  1439.                 return AsyncComplete;
  1440.         }
  1441.  
  1442.         if (m_coverUsageInfoState.state == AsyncReady)
  1443.         {
  1444.                 m_coverUsageInfoState.state = AsyncInProgress;
  1445.  
  1446.                 CAIHideObject& hideObject = m_CurrentHideObject;
  1447.  
  1448.                 const Vec3& target = attentionTarget->GetPos();
  1449.                 const float offset = GetParameters().m_fPassRadius;
  1450.  
  1451.                 bool lowCover = hideObject.HasLowCover();
  1452.                 bool highCover = hideObject.HasHighCover();
  1453.  
  1454.                 Vec3 checkOrigin[6];
  1455.                 bool checkResult[6];
  1456.  
  1457.                 m_coverUsageInfoState.result.lowCompromised = !lowCover;
  1458.                 m_coverUsageInfoState.result.highCompromised = !highCover;
  1459.  
  1460.                 float leftEdge;
  1461.                 float rightEdge;
  1462.                 float leftUmbra;
  1463.                 float rightUmbra;
  1464.  
  1465.                 if (lowCover)
  1466.                 {
  1467.                         bool compromised = false;
  1468.  
  1469.                         hideObject.GetCoverDistances(true, target, compromised, leftEdge, rightEdge, leftUmbra, rightUmbra);
  1470.                         float left = max(leftEdge, leftUmbra);
  1471.                         float right = min(rightEdge, rightUmbra);
  1472.  
  1473.                         left += offset;
  1474.                         right -= offset;
  1475.  
  1476.                         Vec3 originOffset(0.0f, 0.0f, 0.7f);
  1477.  
  1478.                         checkOrigin[LowLeft] = hideObject.GetPointAlongCoverPath(left) + originOffset;
  1479.                         checkOrigin[LowRight] = hideObject.GetPointAlongCoverPath(right) + originOffset;
  1480.                         checkOrigin[LowCenter] = 0.5f * (checkOrigin[LowLeft] + checkOrigin[LowRight]);
  1481.  
  1482.                         checkResult[LowLeft] = hideObject.IsLeftEdgeValid(true);
  1483.                         checkResult[LowCenter] = true;
  1484.                         checkResult[LowRight] = hideObject.IsRightEdgeValid(true);
  1485.  
  1486.                         m_coverUsageInfoState.result.lowCompromised = compromised;
  1487.                 }
  1488.                 else
  1489.                 {
  1490.                         checkResult[LowLeft] = false;
  1491.                         checkResult[LowRight] = false;
  1492.                         checkResult[LowCenter] = false;
  1493.  
  1494.                         m_coverUsageInfoState.result.lowLeft = false;
  1495.                         m_coverUsageInfoState.result.lowCenter = false;
  1496.                         m_coverUsageInfoState.result.lowRight = false;
  1497.                 }
  1498.  
  1499.                 if (highCover)
  1500.                 {
  1501.                         bool compromised = false;
  1502.  
  1503.                         hideObject.GetCoverDistances(false, target, compromised, leftEdge, rightEdge, leftUmbra, rightUmbra);
  1504.                         float left = max(leftEdge, leftUmbra);
  1505.                         float right = min(rightEdge, rightUmbra);
  1506.  
  1507.                         left += offset;
  1508.                         right -= offset;
  1509.  
  1510.                         Vec3 originOffset(0.0f, 0.0f, 1.5f);
  1511.  
  1512.                         checkOrigin[HighLeft] = hideObject.GetPointAlongCoverPath(left) + originOffset;
  1513.                         checkOrigin[HighRight] = hideObject.GetPointAlongCoverPath(right) + originOffset;
  1514.                         checkOrigin[HighCenter] = 0.5f * (checkOrigin[HighLeft] + checkOrigin[HighRight]);
  1515.  
  1516.                         checkResult[HighLeft] = hideObject.IsLeftEdgeValid(false);
  1517.                         checkResult[HighCenter] = true;
  1518.                         checkResult[HighRight] = hideObject.IsRightEdgeValid(false);
  1519.  
  1520.                         m_coverUsageInfoState.result.highCompromised = compromised;
  1521.                 }
  1522.                 else
  1523.                 {
  1524.                         checkResult[HighLeft] = false;
  1525.                         checkResult[HighCenter] = false;
  1526.                         checkResult[HighRight] = false;
  1527.  
  1528.                         m_coverUsageInfoState.result.highLeft = false;
  1529.                         m_coverUsageInfoState.result.highCenter = false;
  1530.                         m_coverUsageInfoState.result.highRight = false;
  1531.                 }
  1532.  
  1533.                 for (int i = 0; i < 6; ++i)
  1534.                 {
  1535.                         if (!checkResult[i])
  1536.                                 continue;
  1537.  
  1538.                         Vec3 dir = target - checkOrigin[i];
  1539.                         if (dir.GetLengthSquared2D() > 3.0f * 3.0f)
  1540.                                 dir.SetLength(3.0f);
  1541.  
  1542.                         m_coverUsageInfoState.rayID[i] = gAIEnv.pRayCaster->Queue(
  1543.                           RayCastRequest::HighPriority,
  1544.                           RayCastRequest(
  1545.                             checkOrigin[i], dir, COVER_OBJECT_TYPES,
  1546.                             AI_VISION_RAY_CAST_FLAG_BLOCKED_BY_SOLID_COVER),
  1547.                           functor(*this, &CPipeUser::CoverUsageInfoRayComplete));
  1548.                         ++m_coverUsageInfoState.rayCount;
  1549.                 }
  1550.         }
  1551.  
  1552.         return m_coverUsageInfoState.state;
  1553. }
  1554.  
  1555. void CPipeUser::CoverUsageInfoRayComplete(const QueuedRayID& rayID, const RayCastResult& result)
  1556. {
  1557.         --m_coverUsageInfoState.rayCount;
  1558.  
  1559.         for (uint32 i = 0; i < 6; ++i)
  1560.         {
  1561.                 if (m_coverUsageInfoState.rayID[i] != rayID)
  1562.                         continue;
  1563.  
  1564.                 m_coverUsageInfoState.rayID[i] = 0;
  1565.  
  1566.                 switch (i)
  1567.                 {
  1568.                 case LowLeft:
  1569.                         m_coverUsageInfoState.result.lowLeft = result.hitCount != 0;
  1570.                         break;
  1571.                 case LowCenter:
  1572.                         m_coverUsageInfoState.result.lowCenter = result.hitCount != 0;
  1573.                         break;
  1574.                 case LowRight:
  1575.                         m_coverUsageInfoState.result.lowRight = result.hitCount != 0;
  1576.                         break;
  1577.                 case HighLeft:
  1578.                         m_coverUsageInfoState.result.highLeft = result.hitCount != 0;
  1579.                         break;
  1580.                 case HighCenter:
  1581.                         m_coverUsageInfoState.result.highCenter = result.hitCount != 0;
  1582.                         break;
  1583.                 case HighRight:
  1584.                         m_coverUsageInfoState.result.highRight = result.hitCount != 0;
  1585.                         break;
  1586.                 default:
  1587.                         assert(0);
  1588.                         break;
  1589.                 }
  1590.  
  1591.                 break;
  1592.         }
  1593.  
  1594.         if (m_coverUsageInfoState.rayCount == 0)
  1595.                 m_coverUsageInfoState.state = AsyncComplete;
  1596. }
  1597.  
  1598. //
  1599. //---------------------------------------------------------------------------------------------------------
  1600. bool CPipeUser::ProcessRandomGoal(QGoal& Goal, bool& blocking)
  1601. {
  1602.         if (Goal.op != eGO_RANDOM)
  1603.                 return false;
  1604.  
  1605.         blocking = true;
  1606.         if (Goal.params.fValue > cry_random(0, 99)) // 0 - never jump // 100 - always jump
  1607.                 m_pCurrentGoalPipe->Jump(Goal.params.nValue);
  1608.  
  1609.         return true;
  1610. }
  1611.  
  1612. //
  1613. //---------------------------------------------------------------------------------------------------------
  1614. bool CPipeUser::ProcessClearGoal(QGoal& Goal, bool& blocking)
  1615. {
  1616.         if (Goal.op != eGO_CLEAR)
  1617.                 return false;
  1618.  
  1619.         ClearActiveGoals();
  1620.  
  1621.         //Luciano - CLeader should manage the release of formation
  1622.         //                                      GetAISystem()->FreeFormationPoint(m_Parameters.m_nGroup,this);
  1623.         if (Goal.params.fValue)
  1624.         {
  1625.                 SetAttentionTarget(NILREF);
  1626.                 ClearPotentialTargets();
  1627.         }
  1628.  
  1629.         blocking = false;
  1630.  
  1631.         return true;
  1632. }
  1633.  
  1634. void CPipeUser::SetNavSOFailureStates()
  1635. {
  1636.         if (m_eNavSOMethod != nSOmNone)
  1637.         {
  1638.                 if (!m_currentNavSOStates.IsEmpty())
  1639.                 {
  1640.                         gAIEnv.pSmartObjectManager->ModifySmartObjectStates(GetEntity(), m_currentNavSOStates.sAnimationFailUserStates);
  1641.                         IEntity* pObjectEntity = gEnv->pEntitySystem->GetEntity(m_currentNavSOStates.objectEntId);
  1642.                         if (pObjectEntity)
  1643.                                 gAIEnv.pSmartObjectManager->ModifySmartObjectStates(pObjectEntity, m_currentNavSOStates.sAnimationFailObjectStates);
  1644.                         m_currentNavSOStates.Clear();
  1645.                 }
  1646.  
  1647.                 if (!m_pendingNavSOStates.IsEmpty())
  1648.                 {
  1649.                         gAIEnv.pSmartObjectManager->ModifySmartObjectStates(GetEntity(), m_pendingNavSOStates.sAnimationFailUserStates);
  1650.                         IEntity* pObjectEntity = gEnv->pEntitySystem->GetEntity(m_pendingNavSOStates.objectEntId);
  1651.                         if (pObjectEntity)
  1652.                                 gAIEnv.pSmartObjectManager->ModifySmartObjectStates(pObjectEntity, m_pendingNavSOStates.sAnimationFailObjectStates);
  1653.                         m_pendingNavSOStates.Clear();
  1654.                 }
  1655.         }
  1656.  
  1657.         AIAssert(m_pendingNavSOStates.IsEmpty() && m_currentNavSOStates.IsEmpty());
  1658.  
  1659.         // Stop exact positioning.
  1660.         m_State.actorTargetReq.Reset();
  1661.  
  1662.         m_eNavSOMethod = nSOmNone;
  1663. }
  1664.  
  1665. void CPipeUser::ClearPath(const char* dbgString)
  1666. {
  1667.         SetNavSOFailureStates();
  1668.  
  1669.         // Don't change the pathfinder result since it has to reflect the result of
  1670.         // the last pathfind. If it is set to NoPath then flowgraph AIGoto nodes will
  1671.         // fail at the end of the path.
  1672.         m_Path.Clear(dbgString);
  1673.         m_OrigPath.Clear(dbgString);
  1674.         m_refPathFindTarget.Reset();
  1675. }
  1676.  
  1677. //
  1678. //--------------------------------------------------------------------------------------------------------
  1679. void CPipeUser::GetStateFromActiveGoals(SOBJECTSTATE& state)
  1680. {
  1681.  
  1682. #ifdef _DEBUG
  1683.         // Reset the movement reason at each update, it will be setup by the correct goal operation.
  1684.         m_DEBUGmovementReason = AIMORE_UNKNOWN;
  1685. #endif
  1686.  
  1687.         FUNCTION_PROFILER(gEnv->pSystem, PROFILE_AI);
  1688.  
  1689.         if (m_bFirstUpdate)
  1690.         {
  1691.                 m_bFirstUpdate = false;
  1692.                 SetLooseAttentionTarget(NILREF);
  1693.         }
  1694.  
  1695.         if (IsPaused())
  1696.                 return;
  1697.  
  1698.         m_DeferredActiveGoals.clear();
  1699.  
  1700.         m_pipeExecuting = true;
  1701.  
  1702.         if (m_pCurrentGoalPipe)
  1703.         {
  1704.                 if (m_pCurrentGoalPipe->CountSubpipes() >= 10)
  1705.                 {
  1706.                         AIWarning("%s has too many (%d) subpipes. Pipe <%s>", GetName(), m_pCurrentGoalPipe->CountSubpipes(),
  1707.                                   m_pCurrentGoalPipe->GetName());
  1708.                 }
  1709.  
  1710.                 if (!m_bBlocked)  // if goal queue not blocked
  1711.                 {
  1712.                         // (MATT) Track whether we will add this to the active goals, executed in subsequent frames {2009/10/14}
  1713.                         bool doNotExecuteAgain = false;
  1714.  
  1715.                         QGoal Goal;
  1716.  
  1717.                         EPopGoalResult pgResult = m_pCurrentGoalPipe->PeekPopGoalResult();
  1718.                         bool isLoop = m_pCurrentGoalPipe->IsLoop();
  1719.  
  1720.                         if ((pgResult == ePGR_AtEnd))
  1721.                         {
  1722.                                 if (isLoop)
  1723.                                 {
  1724.                                         m_pCurrentGoalPipe->Reset();
  1725.  
  1726.                                         ClearActiveGoals();
  1727.                                         if (GetAttentionTarget())
  1728.                                                 m_pCurrentGoalPipe->SetAttTargetPosAtStart(GetAttentionTarget()->GetPos());
  1729.                                 }
  1730.                                 else
  1731.                                 {
  1732.                                         NotifyListeners(m_pCurrentGoalPipe, ePN_Exiting);
  1733.                                 }
  1734.                         }
  1735.  
  1736.                         while ((pgResult = m_pCurrentGoalPipe->PopGoal(Goal, this)) == ePGR_Succeed)
  1737.                         {
  1738.                                 // Each Process instruction first checks to see if this goal is of the right type, immediately returning false if not
  1739.                                 bool blocking = false;
  1740.  
  1741.                                 if (ProcessBranchGoal(Goal, blocking))
  1742.                                 {
  1743.                                         // Now, having either taken the branch or not:
  1744.                                         if (blocking)
  1745.                                         {
  1746.                                                 doNotExecuteAgain = true;
  1747.                                                 break; // blocking - don't execute the next instruction until next frame
  1748.                                         }
  1749.                                         continue; // non-blocking - continue with execution immediately
  1750.                                 }
  1751.  
  1752.                                 if (ProcessRandomGoal(Goal, blocking))  // RandomJump would be a better name
  1753.                                 {
  1754.                                         doNotExecuteAgain = blocking;
  1755.                                         break;
  1756.                                 }
  1757.  
  1758.                                 if (ProcessClearGoal(Goal, blocking))
  1759.                                 {
  1760.                                         doNotExecuteAgain = blocking;
  1761.                                         break;
  1762.                                 }
  1763.  
  1764.                                 EGoalOpResult result = Goal.pGoalOp->Execute(this);
  1765.                                 doNotExecuteAgain = false;
  1766.  
  1767.                                 if (result == eGOR_IN_PROGRESS)
  1768.                                 {
  1769.                                         if (Goal.bBlocking)
  1770.                                         {
  1771.                                                 break;
  1772.                                         }
  1773.                                         else
  1774.                                         {
  1775.                                                 m_DeferredActiveGoals.push_back(Goal);
  1776.                                         }
  1777.                                 }
  1778.                                 else
  1779.                                 {
  1780.                                         if (result == eGOR_DONE)
  1781.                                         {
  1782.                                                 Goal.pGoalOp->Reset(this);
  1783.                                         }
  1784.                                         else
  1785.                                         {
  1786.                                                 m_pCurrentGoalPipe->SetLastResult(result);
  1787.                                         }
  1788.  
  1789.                                         doNotExecuteAgain = (result == eGOR_FAILED) || (result == eGOR_DONE);
  1790.                                 }
  1791.                         }
  1792.  
  1793.                         if (pgResult != ePGR_BreakLoop)
  1794.                         {
  1795.                                 if (!Goal.pGoalOp)
  1796.                                 {
  1797.                                         if (isLoop)
  1798.                                         {
  1799.                                                 m_pCurrentGoalPipe->Reset();
  1800.                                                 ClearActiveGoals();
  1801.                                                 if (GetAttentionTarget())
  1802.                                                         m_pCurrentGoalPipe->SetAttTargetPosAtStart(GetAttentionTarget()->GetPos());
  1803.                                         }
  1804.                                 }
  1805.                                 else
  1806.                                 {
  1807.                                         if (!doNotExecuteAgain)
  1808.                                         {
  1809.                                                 //FIXME
  1810.                                                 //todo: remove this, currently happens coz "lookat" never finishes - actor can't rotate sometimes
  1811.                                                 if (m_DeferredActiveGoals.size() < 20)
  1812.                                                 {
  1813.                                                         m_DeferredActiveGoals.push_back(Goal);
  1814.                                                 }
  1815.                                                 else
  1816.                                                 {
  1817.                                                         // (MATT) Test if the lookat problem still occurs {2009/10/20}
  1818.                                                         assert(false);
  1819.                                                 }
  1820.                                                 m_bBlocked = Goal.bBlocking;
  1821.                                         }
  1822.                                 }
  1823.                         }
  1824.                 }
  1825.         }
  1826.         if (m_vActiveGoals.size() >= 10)
  1827.         {
  1828.                 const QGoal& Goal = m_vActiveGoals.back();
  1829.                 AIWarning("%s has too many (%" PRISIZE_T ") active goals. Pipe <%s>; last goal <%s>", GetName(), m_vActiveGoals.size(),
  1830.                           m_pCurrentGoalPipe ? m_pCurrentGoalPipe->GetName() : "_no_pipe_",
  1831.                           Goal.op == eGO_LAST ? Goal.sPipeName.c_str() : m_pCurrentGoalPipe->GetGoalOpName(Goal.op));
  1832.                 assert(m_vActiveGoals.size() < 100);
  1833.         }
  1834.  
  1835.         if (!m_vActiveGoals.empty())
  1836.         {
  1837.                 for (size_t i = 0; i < m_vActiveGoals.size(); i++)
  1838.                 {
  1839.                         QGoal& Goal = m_vActiveGoals[i];
  1840.  
  1841.                         m_lastExecutedGoalop = Goal.op;
  1842.  
  1843.                         /*
  1844.                            ITimer *pTimer = gEnv->pTimer;
  1845.                            int val = gAIEnv.CVars.ProfileGoals;
  1846.  
  1847.                            CTimeValue timeLast;
  1848.  
  1849.                            if (val)
  1850.                            timeLast = pTimer->GetAsyncTime();
  1851.                          */
  1852.                         EGoalOpResult result = Goal.pGoalOp->Execute(this);
  1853.                         /*if (val)
  1854.                            {
  1855.                            CTimeValue timeCurr = pTimer->GetAsyncTime();
  1856.                            float f = (timeCurr-timeLast).GetSeconds();
  1857.                            timeLast=timeCurr;
  1858.  
  1859.                            const char* goalName = Goal.op == eGO_LAST ? Goal.sPipeName.c_str() : m_pCurrentGoalPipe->GetGoalOpName(Goal.op);
  1860.                            GetAISystem()->m_mapDEBUGTimingGOALS[CONST_TEMP_STRING(goalName)] = f;
  1861.                            }
  1862.                          */
  1863.                         if (result != eGOR_IN_PROGRESS)
  1864.                         {
  1865.                                 if (Goal.bBlocking)
  1866.                                 {
  1867.                                         if (result != eGOR_DONE)
  1868.                                                 m_pCurrentGoalPipe->SetLastResult(result);
  1869.                                         m_bBlocked = false;
  1870.                                 }
  1871.  
  1872.                                 RemoveActiveGoal(i);
  1873.                                 if (!m_vActiveGoals.empty())
  1874.                                         --i;
  1875.                         }
  1876.                 }
  1877.         }
  1878.  
  1879.         m_vActiveGoals.insert(m_vActiveGoals.end(), m_DeferredActiveGoals.begin(), m_DeferredActiveGoals.end());
  1880.  
  1881.         if (m_bKeepMoving && m_State.vMoveDir.IsZero(.01f) && !m_vLastMoveDir.IsZero(.01f))
  1882.                 m_State.vMoveDir = m_vLastMoveDir;
  1883.         else if (!m_State.vMoveDir.IsZero(.01f))
  1884.                 m_vLastMoveDir = m_State.vMoveDir;
  1885.  
  1886.         assert(m_pipeExecuting);
  1887.         m_pipeExecuting = false;
  1888.  
  1889.         if (!m_delayedPipeSelection.name.empty())
  1890.         {
  1891.                 const DelayedPipeSelection& delayed = m_delayedPipeSelection;
  1892.                 SelectPipe(delayed.mode, delayed.name.c_str(), delayed.refArgument, delayed.goalPipeId,
  1893.                            delayed.resetAlways /*, &delayed.params*/);
  1894.  
  1895.                 m_delayedPipeSelection = DelayedPipeSelection();
  1896.         }
  1897. }
  1898.  
  1899. void CPipeUser::SetLastOpResult(CWeakRef<CAIObject> refObject)
  1900. {
  1901.         m_refLastOpResult = refObject;
  1902. }
  1903.  
  1904. void CPipeUser::SetAttentionTarget(CWeakRef<CAIObject> refTarget)
  1905. {
  1906.         CCCPOINT(CPipeUser_SetAttentionTarget);
  1907.         CAIObject* pTarget = refTarget.GetAIObject();
  1908.  
  1909.         if (!pTarget)
  1910.         {
  1911.                 m_AttTargetThreat = AITHREAT_NONE;
  1912.                 m_AttTargetExposureThreat = AITHREAT_NONE;
  1913.                 m_AttTargetType = AITARGET_NONE;
  1914.         }
  1915.         else if (m_refAttentionTarget != refTarget && m_pCurrentGoalPipe)
  1916.         {
  1917.                 AIAssert(m_pCurrentGoalPipe);
  1918.                 CGoalPipe* pLastPipe(m_pCurrentGoalPipe->GetLastSubpipe());
  1919.                 if (pLastPipe && pTarget)
  1920.                         pLastPipe->SetAttTargetPosAtStart(pTarget->GetPos());
  1921.         }
  1922.  
  1923.         m_refAttentionTarget = refTarget;
  1924.  
  1925. #ifdef CRYAISYSTEM_DEBUG
  1926.         RecorderEventData recorderEventData(pTarget != NULL ? pTarget->GetName() : "<none>");
  1927.         RecordEvent(IAIRecordable::E_ATTENTIONTARGET, &recorderEventData);
  1928. #endif
  1929. }
  1930.  
  1931. //====================================================================
  1932. // RequestPathTo
  1933. //====================================================================
  1934. void CPipeUser::RequestPathTo(
  1935.   const Vec3& pos
  1936.   , const Vec3& dir
  1937.   , bool allowDangerousDestination
  1938.   , int forceTargetBuildingId
  1939.   , float endTol
  1940.   , float endDistance
  1941.   , CAIObject* pTargetObject
  1942.   , const bool cutPathAtSmartObject
  1943.   , const MNMDangersFlags dangersFlags
  1944.   , const bool considerActorsAsPathObstacles)
  1945. {
  1946.         CCCPOINT(CPipeUser_RequestPathTo);
  1947.  
  1948.         m_cutPathAtSmartObject = cutPathAtSmartObject;
  1949.         m_considerActorsAsPathObstacles = considerActorsAsPathObstacles;
  1950.         m_OrigPath.Clear("CPipeUser::RequestPathTo m_OrigPath");
  1951.         m_nPathDecision = PATHFINDER_STILLFINDING;
  1952.         m_refPathFindTarget = GetWeakRef(pTargetObject);
  1953.         // add a slight offset to avoid starting below the floor
  1954.         Vec3 myPos = GetPhysicsPos() + Vec3(0, 0, 0.05f);
  1955.         Vec3 endDir(ZERO);
  1956.         // Check the type of the way the movement to the target, 0 = strict 1 = fastest, forget end direction.
  1957.         if (m_bPathfinderConsidersPathTargetDirection)
  1958.                 endDir = dir;
  1959.  
  1960.         CancelRequestedPath(false);
  1961.  
  1962.         assert(m_queuedPathId == 0);
  1963.  
  1964.         const MNMPathRequest request(myPos, pos, endDir, forceTargetBuildingId, endTol, endDistance,
  1965.                                      allowDangerousDestination, functor(*this, &CPipeUser::OnMNMPathResult), GetNavigationTypeID(),
  1966.                                      dangersFlags);
  1967.         m_queuedPathId = gAIEnv.pMNMPathfinder->RequestPathTo(this, request);
  1968.  
  1969.         if (m_queuedPathId == 0)
  1970.         {
  1971.                 MNMPathRequestResult result;
  1972.                 HandlePathDecision(result);
  1973.         }
  1974. }
  1975.  
  1976. void CPipeUser::RequestPathTo(MNMPathRequest& request)
  1977. {
  1978.         CCCPOINT(CPipeUser_RequestPathTo);
  1979.  
  1980.         m_cutPathAtSmartObject = false;
  1981.         m_considerActorsAsPathObstacles = false;
  1982.         m_OrigPath.Clear("CPipeUser::RequestPathTo m_OrigPath");
  1983.         m_nPathDecision = PATHFINDER_STILLFINDING;
  1984.         m_refPathFindTarget.Reset();
  1985.         // add a slight offset to avoid starting below the floor
  1986.  
  1987.         CancelRequestedPath(false);
  1988.  
  1989.         assert(m_queuedPathId == 0);
  1990.  
  1991.         request.resultCallback = functor(*this, &CPipeUser::OnMNMPathResult);
  1992.         m_queuedPathId = gAIEnv.pMNMPathfinder->RequestPathTo(this, request);
  1993.  
  1994.         if (m_queuedPathId == 0)
  1995.         {
  1996.                 MNMPathRequestResult result;
  1997.                 HandlePathDecision(result);
  1998.         }
  1999. }
  2000.  
  2001. //===================================================================
  2002. // RequestPathInDirection
  2003. //===================================================================
  2004. void CPipeUser::RequestPathInDirection(const Vec3& pos, float distance, CWeakRef<CAIObject> refTargetObject, float endDistance)
  2005. {
  2006.         AIWarning("CPipeUser::RequestPathInDirection is currently not supported for the MNM Navigation System.");
  2007. }
  2008.  
  2009. //====================================================================
  2010. // GetGoalPipe
  2011. //====================================================================
  2012. CGoalPipe* CPipeUser::GetGoalPipe(const char* name)
  2013. {
  2014.         CGoalPipe* pPipe = (CGoalPipe*) gAIEnv.pPipeManager->OpenGoalPipe(name);
  2015.  
  2016.         if (pPipe)
  2017.                 return pPipe;
  2018.         else
  2019.                 return 0;
  2020. }
  2021.  
  2022. //====================================================================
  2023. // IsUsingPipe
  2024. //====================================================================
  2025. bool CPipeUser::IsUsingPipe(const char* name) const
  2026. {
  2027.         const CGoalPipe* pExecutingPipe = m_pCurrentGoalPipe;
  2028.  
  2029.         if (!pExecutingPipe)
  2030.                 return false;
  2031.  
  2032.         while (pExecutingPipe->IsInSubpipe())
  2033.         {
  2034.                 if (pExecutingPipe->GetNameAsString() == name)
  2035.                         return true;
  2036.                 pExecutingPipe = pExecutingPipe->GetSubpipe();
  2037.         }
  2038.         return pExecutingPipe->GetNameAsString() == name;
  2039. }
  2040.  
  2041. bool CPipeUser::IsUsingPipe(int goalPipeId) const
  2042. {
  2043.         const CGoalPipe* pExecutingPipe = m_pCurrentGoalPipe;
  2044.         while (pExecutingPipe)
  2045.         {
  2046.                 if (pExecutingPipe->GetEventId() == goalPipeId)
  2047.                         return true;
  2048.                 pExecutingPipe = pExecutingPipe->GetSubpipe();
  2049.         }
  2050.         return false;
  2051. }
  2052.  
  2053. //====================================================================
  2054. // RemoveActiveGoal
  2055. //====================================================================
  2056. void CPipeUser::RemoveActiveGoal(int nOrder)
  2057. {
  2058.         if (m_vActiveGoals.empty())
  2059.                 return;
  2060.         int size = (int)m_vActiveGoals.size();
  2061.  
  2062.         if (size == 1)
  2063.         {
  2064.                 m_vActiveGoals.front().pGoalOp->Reset(this);
  2065.                 m_vActiveGoals.clear();
  2066.                 return;
  2067.         }
  2068.  
  2069.         m_vActiveGoals[nOrder].pGoalOp->Reset(this);
  2070.  
  2071.         if (nOrder != size - 1)
  2072.                 m_vActiveGoals[nOrder] = m_vActiveGoals[size - 1];
  2073.  
  2074.         m_vActiveGoals.pop_back();
  2075. }
  2076.  
  2077. bool CPipeUser::AbortActionPipe(int goalPipeId)
  2078. {
  2079.         CGoalPipe* pPipe = m_pCurrentGoalPipe;
  2080.         while (pPipe && pPipe->GetEventId() != goalPipeId)
  2081.                 pPipe = pPipe->GetSubpipe();
  2082.         if (!pPipe)
  2083.                 return false;
  2084.  
  2085.         // high priority pipes are already aborted or not allowed to be aborted
  2086.         if (pPipe->IsHighPriority())
  2087.                 return false;
  2088.  
  2089.         // aborted actions become high priority actions
  2090.         pPipe->HighPriority();
  2091.  
  2092.         // cancel all pipes inserted after this one unless another action is found
  2093.         while (pPipe && pPipe->GetSubpipe())
  2094.         {
  2095.                 if (pPipe->GetSubpipe()->GetNameAsString() == "_action_")
  2096.                         break;
  2097.                 else if (pPipe->GetSubpipe()->GetEventId())
  2098.                         CancelSubPipe(pPipe->GetSubpipe()->GetEventId());
  2099.                 pPipe = pPipe->GetSubpipe();
  2100.         }
  2101.         return true;
  2102. }
  2103.  
  2104. bool CPipeUser::SelectPipe(int mode, const char* name, CWeakRef<CAIObject> refArgument, int goalPipeId, bool resetAlways, const GoalParams* node)
  2105. {
  2106.         if (m_pipeExecuting)
  2107.         {
  2108.                 assert(!node); // don't support parameterized goal pipe selections
  2109.                 m_delayedPipeSelection = DelayedPipeSelection(mode, name, refArgument, goalPipeId, resetAlways);
  2110.  
  2111.                 return true;
  2112.         }
  2113.  
  2114.         if (IEntity* pEntity = GetEntity())
  2115.                 gAIEnv.pAIActionManager->AbortAIAction(pEntity);
  2116.  
  2117.         refArgument.ValidateOrReset();
  2118.  
  2119.         m_lastExecutedGoalop = eGO_LAST;
  2120.  
  2121.         if (m_pCurrentGoalPipe && !resetAlways)
  2122.         {
  2123.                 if (m_pCurrentGoalPipe->GetNameAsString() == name)
  2124.                 {
  2125.                         CCCPOINT(CPipeUser_SelectPipe_A);
  2126.                         NotifyListeners(m_pCurrentGoalPipe->GetEventId(), ePN_Deselected);
  2127.                         m_pCurrentGoalPipe->SetEventId(goalPipeId);
  2128.                         if (refArgument.IsSet())
  2129.                                 m_pCurrentGoalPipe->SetRefArgument(refArgument);
  2130.                         m_pCurrentGoalPipe->SetLoop((mode & AIGOALPIPE_RUN_ONCE) == 0);
  2131.                         return true;
  2132.                 }
  2133.         }
  2134.  
  2135.         CGoalPipe* pHigherPriorityOwner = NULL;
  2136.         CGoalPipe* pHigherPriority = m_pCurrentGoalPipe;
  2137.         while (pHigherPriority && !pHigherPriority->IsHighPriority())
  2138.         {
  2139.                 pHigherPriorityOwner = pHigherPriority;
  2140.                 pHigherPriority = pHigherPriority->GetSubpipe();
  2141.         }
  2142.  
  2143.         if (!pHigherPriority && refArgument.IsSet())
  2144.         {
  2145.                 SetLastOpResult(refArgument);
  2146.         }
  2147.  
  2148.         if (!pHigherPriority || resetAlways)
  2149.         {
  2150.                 CCCPOINT(CPipeUser_SelectPipe_B);
  2151.  
  2152.                 // reset some stuff with every goal-pipe change -----------------------------------------------------------------------------------
  2153.                 // strafing dist should be reset
  2154.                 CPuppet* pPuppet = CastToCPuppet();
  2155.                 if (pPuppet)
  2156.                 {
  2157.                         pPuppet->SetAllowedStrafeDistances(0, 0, false);
  2158.                         pPuppet->SetAdaptiveMovementUrgency(0, 0, 0);
  2159.                         pPuppet->SetDelayedStance(STANCE_NULL);
  2160.                 }
  2161.  
  2162.                 // reset some stuff here
  2163.                 if (!(mode & AIGOALPIPE_DONT_RESET_AG))
  2164.                 {
  2165.                         if (pPuppet)
  2166.                                 pPuppet->GetState().coverRequest.ClearCoverAction(); //Argh!
  2167.  
  2168.                         if (IAIActorProxy* pProxy = GetProxy())
  2169.                                 pProxy->ResetAGInput(AIAG_ACTION);
  2170.                 }
  2171.  
  2172.                 SetNavSOFailureStates();
  2173.         }
  2174.  
  2175.         CGoalPipe* pPipe = gAIEnv.pPipeManager->IsGoalPipe(name);
  2176.         if (pPipe)
  2177.         {
  2178.                 IAIObject* pAttTarget = GetAttentionTarget();
  2179.                 pPipe->SetAttTargetPosAtStart(pAttTarget ? pAttTarget->GetPos() : Vec3Constants<float>::fVec3_Zero);
  2180.                 pPipe->SetRefArgument(refArgument);
  2181.         }
  2182.         else
  2183.         {
  2184.                 AIError("SelectPipe: Goalpipe '%s' does not exists. Selecting default goalpipe '_first_' instead.", name);
  2185.                 pPipe = gAIEnv.pPipeManager->IsGoalPipe("_first_");
  2186.                 AIAssert(pPipe);
  2187.                 pPipe->GetRefArgument().Reset();
  2188.         }
  2189.  
  2190.         if (!pHigherPriority || resetAlways)
  2191.                 ResetCurrentPipe(resetAlways);
  2192.  
  2193.         CGoalPipe* prevGoalPipe = m_pCurrentGoalPipe;
  2194.         m_pCurrentGoalPipe = pPipe;   // this might be too slow, in which case we will go back to registration
  2195.         m_pCurrentGoalPipe->Reset();
  2196.         m_pCurrentGoalPipe->SetEventId(goalPipeId);
  2197.         if (node)
  2198.         {
  2199.                 m_pCurrentGoalPipe->ParseParams(*node);
  2200.         }
  2201.  
  2202.         if (pHigherPriority && !resetAlways)
  2203.         {
  2204.                 if (pHigherPriorityOwner)
  2205.                 {
  2206.                         pHigherPriorityOwner->SetSubpipe(NULL);
  2207.  
  2208.                         delete prevGoalPipe;
  2209.                 }
  2210.  
  2211.                 m_pCurrentGoalPipe->SetSubpipe(pHigherPriority);
  2212.         }
  2213.  
  2214.         m_pCurrentGoalPipe->SetLoop((mode & AIGOALPIPE_RUN_ONCE) == 0);
  2215.  
  2216.         GetAISystem()->Record(this, IAIRecordable::E_GOALPIPESELECTED, name);
  2217.  
  2218. #ifdef CRYAISYSTEM_DEBUG
  2219.         if (pPipe)
  2220.         {
  2221.                 RecorderEventData recorderEventData(name);
  2222.                 RecordEvent(IAIRecordable::E_GOALPIPESELECTED, &recorderEventData);
  2223.         }
  2224.         else
  2225.         {
  2226.                 string str(name);
  2227.                 str += "[Not Found!]";
  2228.                 RecorderEventData recorderEventData(str.c_str());
  2229.                 RecordEvent(IAIRecordable::E_GOALPIPESELECTED, &recorderEventData);
  2230.         }
  2231. #endif  // #ifdef CRYAISYSTEM_DEBUG
  2232.  
  2233.         ClearInvalidatedSOLinks();
  2234.  
  2235.         CCCPOINT(CPipeUser_SelectPipe_End);
  2236.         return true;
  2237. }
  2238.  
  2239. void CPipeUser::Pause(bool pause)
  2240. {
  2241.         if (pause)
  2242.         {
  2243.                 ++m_paused;
  2244.         }
  2245.         else
  2246.         {
  2247.                 assert(m_paused > 0);
  2248.                 if (m_paused > 0)
  2249.                         --m_paused;
  2250.         }
  2251.  
  2252.         assert(m_paused <= 8);
  2253. }
  2254.  
  2255. bool CPipeUser::IsPaused() const
  2256. {
  2257.         return m_paused > 0;
  2258. }
  2259.  
  2260. // used by action system to remove "_action_" inserted goal pipe
  2261. // which would notify goal pipe listeners and resume previous goal pipe
  2262. bool CPipeUser::RemoveSubPipe(int goalPipeId, bool keepInserted)
  2263. {
  2264.         if (!goalPipeId)
  2265.                 return false;
  2266.  
  2267.         if (!m_pCurrentGoalPipe)
  2268.         {
  2269.                 m_notAllowedSubpipes.insert(goalPipeId);
  2270.                 return false;
  2271.         }
  2272.  
  2273.         // find the last goal pipe in the list
  2274.         CGoalPipe* pTargetPipe = NULL;
  2275.         CGoalPipe* pPrevPipe = m_pCurrentGoalPipe;
  2276.         while (pPrevPipe->GetSubpipe())
  2277.         {
  2278.                 pPrevPipe = pPrevPipe->GetSubpipe();
  2279.                 if (pPrevPipe->GetEventId() == goalPipeId)
  2280.                         pTargetPipe = pPrevPipe;
  2281.         }
  2282.  
  2283.         if (keepInserted == false && pTargetPipe != NULL)
  2284.         {
  2285.                 while (CGoalPipe* pSubpipe = pTargetPipe->GetSubpipe())
  2286.                 {
  2287.                         if (pSubpipe->IsHighPriority())
  2288.                                 break;
  2289.                         if (pSubpipe->GetEventId())
  2290.                                 CancelSubPipe(pSubpipe->GetEventId());
  2291.                         else
  2292.                                 pTargetPipe = pSubpipe;
  2293.                 }
  2294.         }
  2295.  
  2296.         if (m_pCurrentGoalPipe->RemoveSubpipe(this, goalPipeId, keepInserted, true))
  2297.         {
  2298.                 NotifyListeners(goalPipeId, ePN_Removed);
  2299.  
  2300.                 // find the last goal pipe in the list
  2301.                 CGoalPipe* pCurrent = m_pCurrentGoalPipe;
  2302.                 while (pCurrent->GetSubpipe())
  2303.                         pCurrent = pCurrent->GetSubpipe();
  2304.  
  2305.                 // only if the removed pipe was the last one in the list
  2306.                 if (pCurrent != pPrevPipe)
  2307.                 {
  2308.                         // remove goals
  2309.                         ClearActiveGoals();
  2310.  
  2311.                         // and resume the new last goal pipe
  2312.                         SetLastOpResult(pCurrent->GetRefArgument());
  2313.                         NotifyListeners(pCurrent, ePN_Resumed);
  2314.                 }
  2315.                 return true;
  2316.         }
  2317.         else
  2318.         {
  2319.                 m_notAllowedSubpipes.insert(goalPipeId);
  2320.                 return false;
  2321.         }
  2322. }
  2323.  
  2324. // used by ai flow graph nodes to cancel inserted goal pipe
  2325. // which would notify goal pipe listeners that operation was failed
  2326. bool CPipeUser::CancelSubPipe(int goalPipeId)
  2327. {
  2328.         if (!m_pCurrentGoalPipe)
  2329.         {
  2330.                 if (goalPipeId != 0)
  2331.                         m_notAllowedSubpipes.insert(goalPipeId);
  2332.                 return false;
  2333.         }
  2334.  
  2335.         CGoalPipe* pCurrent = m_pCurrentGoalPipe;
  2336.         while (pCurrent->GetSubpipe())
  2337.                 pCurrent = pCurrent->GetSubpipe();
  2338.         bool bClearNeeded = !goalPipeId || pCurrent->GetEventId() == goalPipeId;
  2339.  
  2340.         if (CPuppet* pPuppet = CastToCPuppet())
  2341.                 // enable this since it might be disabled from canceled goal pipe (and planed to enable it again at pipe end)
  2342.                 pPuppet->m_bCanReceiveSignals = true;
  2343.  
  2344.         if (m_pCurrentGoalPipe->RemoveSubpipe(this, goalPipeId, true, true))
  2345.         {
  2346.                 NotifyListeners(goalPipeId, ePN_Deselected);
  2347.  
  2348.                 if (bClearNeeded)
  2349.                 {
  2350.                         ClearActiveGoals();
  2351.  
  2352.                         // resume the parent goal pipe
  2353.                         pCurrent = m_pCurrentGoalPipe;
  2354.                         while (pCurrent->GetSubpipe())
  2355.                                 pCurrent = pCurrent->GetSubpipe();
  2356.                         SetLastOpResult(pCurrent->GetRefArgument());
  2357.                         NotifyListeners(pCurrent, ePN_Resumed);
  2358.                 }
  2359.  
  2360.                 return true;
  2361.         }
  2362.         else
  2363.         {
  2364.                 if (goalPipeId != 0)
  2365.                         m_notAllowedSubpipes.insert(goalPipeId);
  2366.                 return false;
  2367.         }
  2368. }
  2369.  
  2370. IGoalPipe* CPipeUser::InsertSubPipe(int mode, const char* name, CWeakRef<CAIObject> refArgument, int goalPipeId, const GoalParams* node)
  2371. {
  2372.         if (!m_pCurrentGoalPipe)
  2373.                 return NULL;
  2374.  
  2375.         if (goalPipeId != 0)
  2376.         {
  2377.                 VectorSet<int>::iterator itFind = m_notAllowedSubpipes.find(goalPipeId);
  2378.                 if (itFind != m_notAllowedSubpipes.end())
  2379.                 {
  2380.                         CCCPOINT(CPipeUser_InsertSubPipe_NotAllowed);
  2381.  
  2382.                         m_notAllowedSubpipes.erase(itFind);
  2383.                         return NULL;
  2384.                 }
  2385.         }
  2386.  
  2387.         if (m_pCurrentGoalPipe->CountSubpipes() >= 8)
  2388.         {
  2389.                 AIWarning("%s has too many (%d) subpipes. Pipe <%s>; inserting <%s>", GetName(), m_pCurrentGoalPipe->CountSubpipes(),
  2390.                           m_pCurrentGoalPipe->GetName(), name);
  2391.         }
  2392.  
  2393.         bool bExclusive = (mode & AIGOALPIPE_NOTDUPLICATE) != 0;
  2394.         bool bHighPriority = (mode & AIGOALPIPE_HIGHPRIORITY) != 0; // it will be not removed when a goal pipe is selected
  2395.         bool bSamePriority = (mode & AIGOALPIPE_SAMEPRIORITY) != 0; // sets the priority to be the same as active goal pipe
  2396.         bool bKeepOnTop = (mode & AIGOALPIPE_KEEP_ON_TOP) != 0;     // will keep this pipe at the top of the stack
  2397.  
  2398.         //      if (m_pCurrentGoalPipe->m_sName == name && !goalPipeId)
  2399.         //              return NULL;
  2400.  
  2401.         // first lets find the goalpipe
  2402.         CGoalPipe* pPipe = gAIEnv.pPipeManager->IsGoalPipe(name);
  2403.         if (!pPipe)
  2404.         {
  2405.                 AIWarning("InsertSubPipe: Goalpipe '%s' does not exists. No goalpipe inserted.", name);
  2406.  
  2407. #ifdef CRYAISYSTEM_DEBUG
  2408.                 string str(name);
  2409.                 str += "[Not Found!]";
  2410.                 RecorderEventData recorderEventData(str.c_str());
  2411.                 RecordEvent(IAIRecordable::E_GOALPIPEINSERTED, &recorderEventData);
  2412. #endif  // #ifdef CRYAISYSTEM_DEBUG
  2413.  
  2414.                 return NULL;
  2415.         }
  2416.  
  2417.         if (bHighPriority)
  2418.                 pPipe->HighPriority();
  2419.  
  2420.         if (bKeepOnTop)
  2421.                 pPipe->m_bKeepOnTop = true;
  2422.  
  2423.         // now find the innermost pipe
  2424.         CGoalPipe* pExecutingPipe = m_pCurrentGoalPipe;
  2425.         int i = 0;
  2426.         while (pExecutingPipe->IsInSubpipe())
  2427.         {
  2428.                 CCCPOINT(CPipeUser_InsertSubPipe_IsInSubpipe);
  2429.  
  2430.                 if (bExclusive && pExecutingPipe->GetNameAsString() == name)
  2431.                 {
  2432.                         delete pPipe;
  2433.                         return NULL;
  2434.                 }
  2435.                 if (pExecutingPipe->GetSubpipe()->m_bKeepOnTop)
  2436.                         break;
  2437.                 if (!bSamePriority && !bHighPriority)
  2438.                 {
  2439.                         if (pExecutingPipe->GetSubpipe()->IsHighPriority())
  2440.                                 break;
  2441.                 }
  2442.                 pExecutingPipe = pExecutingPipe->GetSubpipe();
  2443.                 ++i;
  2444.         }
  2445.  
  2446.         if (i > 10)
  2447.         {
  2448.                 CGoalPipe* pCurrentPipe = m_pCurrentGoalPipe;
  2449.                 AIWarning("%s: More than 10 subpipes", GetName());
  2450.                 int j = 0;
  2451.                 while (pCurrentPipe->IsInSubpipe())
  2452.                 {
  2453.                         const string& sDebugName = pCurrentPipe->GetDebugName();
  2454.                         AILogAlways("%d) %s", j++, sDebugName.empty() ? pCurrentPipe->GetName() : sDebugName.c_str());
  2455.                         pCurrentPipe = pCurrentPipe->GetSubpipe();
  2456.                 }
  2457.         }
  2458.         CCCPOINT(CPipeUser_InsertSubPipe_A);
  2459.  
  2460.         if (bExclusive && pExecutingPipe->GetNameAsString() == name)
  2461.         {
  2462.                 delete pPipe;
  2463.                 return NULL;
  2464.         }
  2465.         if (!pExecutingPipe->GetSubpipe())
  2466.         {
  2467.                 if (!m_vActiveGoals.empty())
  2468.                 {
  2469.                         ClearActiveGoals();
  2470.  
  2471.                         // but make sure we end up executing it again
  2472.                         pExecutingPipe->ReExecuteGroup();
  2473.                 }
  2474.  
  2475.                 NotifyListeners(pExecutingPipe, ePN_Suspended);
  2476.  
  2477.                 // (MATT) Do we actually need to check? {2009/03/13}
  2478.                 if (refArgument.IsSet())
  2479.                         SetLastOpResult(refArgument);
  2480.  
  2481.                 CCCPOINT(CPipeUser_InsertSubPipe_Unblock);
  2482.  
  2483.                 // unblock current pipe
  2484.                 m_bBlocked = false;
  2485.         }
  2486.  
  2487.         pExecutingPipe->SetSubpipe(pPipe);
  2488.  
  2489.         if (GetAttentionTarget())
  2490.                 pPipe->SetAttTargetPosAtStart(GetAttentionTarget()->GetPos());
  2491.         else
  2492.                 pPipe->SetAttTargetPosAtStart(Vec3Constants<float>::fVec3_Zero);
  2493.         pPipe->SetRefArgument(refArgument);
  2494.         pPipe->SetEventId(goalPipeId);
  2495.  
  2496.         if (node)
  2497.                 pPipe->ParseParams(*node);
  2498.  
  2499.         NotifyListeners(pPipe, ePN_Inserted);
  2500.  
  2501.         GetAISystem()->Record(this, IAIRecordable::E_GOALPIPEINSERTED, name);
  2502.  
  2503. #ifdef CRYAISYSTEM_DEBUG
  2504.         RecorderEventData recorderEventData(name);
  2505.         RecordEvent(IAIRecordable::E_GOALPIPEINSERTED, &recorderEventData);
  2506. #endif
  2507.  
  2508.         CCCPOINT(CPipeUser_InsertSubPipe_End);
  2509.  
  2510.         return pPipe;
  2511. }
  2512.  
  2513. void CPipeUser::ClearActiveGoals()
  2514. {
  2515.         if (!m_vActiveGoals.empty())
  2516.         {
  2517.                 VectorOGoals::iterator li, liEnd = m_vActiveGoals.end();
  2518.                 for (li = m_vActiveGoals.begin(); li != liEnd; ++li)
  2519.                         li->pGoalOp->Reset(this);
  2520.  
  2521.                 m_vActiveGoals.clear();
  2522.         }
  2523.         m_bBlocked = false;
  2524. }
  2525.  
  2526. void CPipeUser::ResetCurrentPipe(bool resetAlways)
  2527. {
  2528.         assert(!m_pipeExecuting);
  2529.  
  2530.         GetAISystem()->Record(this, IAIRecordable::E_GOALPIPERESETED,
  2531.                               m_pCurrentGoalPipe ? m_pCurrentGoalPipe->GetName() : 0);
  2532.  
  2533. #ifdef CRYAISYSTEM_DEBUG
  2534.         RecorderEventData recorderEventData(m_pCurrentGoalPipe ? m_pCurrentGoalPipe->GetName() : 0);
  2535.         RecordEvent(IAIRecordable::E_GOALPIPERESETED, &recorderEventData);
  2536. #endif
  2537.  
  2538.         CGoalPipe* pPipe = m_pCurrentGoalPipe;
  2539.         while (pPipe)
  2540.         {
  2541.                 NotifyListeners(pPipe, ePN_Deselected);
  2542.                 if (resetAlways || !pPipe->GetSubpipe() || !pPipe->GetSubpipe()->IsHighPriority())
  2543.                         pPipe = pPipe->GetSubpipe();
  2544.                 else
  2545.                         break;
  2546.         }
  2547.  
  2548.         if (!pPipe)
  2549.                 ClearActiveGoals();
  2550.         else
  2551.                 pPipe->SetSubpipe(NULL);
  2552.  
  2553.         if (m_pCurrentGoalPipe)
  2554.         {
  2555.                 m_pCurrentGoalPipe->ResetGoalops(this);
  2556.                 delete m_pCurrentGoalPipe;
  2557.                 m_pCurrentGoalPipe = 0;
  2558.         }
  2559.  
  2560.         if (!pPipe)
  2561.         {
  2562.                 if (CPuppet* pPuppet = CastToCPuppet())
  2563.                         pPuppet->m_bCanReceiveSignals = true;
  2564.  
  2565.                 m_bKeepMoving = false;
  2566.                 ResetLookAt();
  2567.                 ResetBodyTargetDir();
  2568.                 ResetDesiredBodyDirectionAtTarget();
  2569.                 ResetMovementContext();
  2570.         }
  2571. }
  2572.  
  2573. int CPipeUser::GetGoalPipeId() const
  2574. {
  2575.         const CGoalPipe* pPipe = m_pCurrentGoalPipe;
  2576.         if (!pPipe)
  2577.                 return -1;
  2578.         while (pPipe->GetSubpipe())
  2579.                 pPipe = pPipe->GetSubpipe();
  2580.         return pPipe->GetEventId();
  2581. }
  2582.  
  2583. void CPipeUser::ResetLookAt()
  2584. {
  2585.         m_bPriorityLookAtRequested = false;
  2586.         if (m_bLooseAttention)
  2587.         {
  2588.                 SetLooseAttentionTarget(NILREF);
  2589.         }
  2590. }
  2591.  
  2592. bool CPipeUser::SetLookAtPointPos(const Vec3& point, bool priority)
  2593. {
  2594.         if (!priority && m_bPriorityLookAtRequested)
  2595.                 return false;
  2596.         m_bPriorityLookAtRequested = priority;
  2597.  
  2598.         CCCPOINT(CPipeUser_SetLookAtPoint);
  2599.  
  2600.         CreateLookAtTarget();
  2601.         m_refLooseAttentionTarget = m_refLookAtTarget;
  2602.         CAIObject* pLookAtTarget = m_refLookAtTarget.GetAIObject();
  2603.         pLookAtTarget->SetPos(point);
  2604.         m_bLooseAttention = true;
  2605.  
  2606.         // check only in 2D
  2607.         Vec3 desired(point - GetPos());
  2608.         desired.z = 0;
  2609.         desired.NormalizeSafe();
  2610.         const SAIBodyInfo& bodyInfo = GetBodyInfo();
  2611.         Vec3 current(bodyInfo.vEyeDirAnim);
  2612.         current.z = 0;
  2613.         current.NormalizeSafe();
  2614.  
  2615.         // cos( 11.5deg ) ~ 0.98
  2616.         return 0.98f <= current.Dot(desired);
  2617. }
  2618.  
  2619. bool CPipeUser::SetLookAtDir(const Vec3& dir, bool priority)
  2620. {
  2621.         if (!priority && m_bPriorityLookAtRequested)
  2622.                 return false;
  2623.         m_bPriorityLookAtRequested = priority;
  2624.  
  2625.         CCCPOINT(CPipeUser_SetLookAtDir);
  2626.  
  2627.         Vec3 vDir = dir;
  2628.         if (vDir.NormalizeSafe())
  2629.         {
  2630.                 CreateLookAtTarget();
  2631.                 m_refLooseAttentionTarget = m_refLookAtTarget;
  2632.                 CAIObject* pLookAtTarget = m_refLookAtTarget.GetAIObject();
  2633.                 pLookAtTarget->SetPos(GetPos() + vDir * 100.0f);
  2634.                 m_bLooseAttention = true;
  2635.  
  2636.                 // check only in 2D
  2637.                 Vec3 desired(vDir);
  2638.                 desired.z = 0;
  2639.                 desired.NormalizeSafe();
  2640.                 const SAIBodyInfo& bodyInfo = GetBodyInfo();
  2641.                 Vec3 current(bodyInfo.vEyeDirAnim);
  2642.                 current.z = 0;
  2643.                 current.NormalizeSafe();
  2644.  
  2645.                 // cos( 11.5deg ) ~ 0.98
  2646.                 if (0.98f <= current.Dot(desired))
  2647.                 {
  2648.                         SetLooseAttentionTarget(NILREF);
  2649.                         return true;
  2650.                 }
  2651.                 else
  2652.                         return false;
  2653.         }
  2654.         else
  2655.                 return true;
  2656. }
  2657.  
  2658. void CPipeUser::ResetBodyTargetDir()
  2659. {
  2660.         m_vBodyTargetDir.zero();
  2661. }
  2662.  
  2663. void CPipeUser::SetBodyTargetDir(const Vec3& dir)
  2664. {
  2665.         m_vBodyTargetDir = dir;
  2666. }
  2667.  
  2668. void CPipeUser::ResetDesiredBodyDirectionAtTarget()
  2669. {
  2670.         m_vDesiredBodyDirectionAtTarget.zero();
  2671. }
  2672.  
  2673. void CPipeUser::SetDesiredBodyDirectionAtTarget(const Vec3& dir)
  2674. {
  2675.         m_vDesiredBodyDirectionAtTarget = dir;
  2676. }
  2677.  
  2678. void CPipeUser::ResetMovementContext()
  2679. {
  2680.         m_movementContext = 0;
  2681. }
  2682.  
  2683. void CPipeUser::ClearMovementContext(unsigned int movementContext)
  2684. {
  2685.         m_movementContext &= ~movementContext;
  2686. }
  2687.  
  2688. void CPipeUser::SetMovementContext(unsigned int movementContext)
  2689. {
  2690.         m_movementContext |= movementContext;
  2691. }
  2692.  
  2693. Vec3 CPipeUser::GetLooseAttentionPos()
  2694. {
  2695.         CCCPOINT(CPipeUser_GetLooseAttentionPos);
  2696.  
  2697.         if (m_bLooseAttention)
  2698.         {
  2699.                 CAIObject* pLooseAttentionTarget = m_refLooseAttentionTarget.GetAIObject();
  2700.                 if (pLooseAttentionTarget)
  2701.                 {
  2702.                         return pLooseAttentionTarget->GetPos();
  2703.                 }
  2704.         }
  2705.  
  2706.         return ZERO;
  2707. }
  2708.  
  2709. void DeleteLookTarget(Vec3* lookTarget)
  2710. {
  2711.         delete lookTarget;
  2712. }
  2713.  
  2714. std::shared_ptr<Vec3> CPipeUser::CreateLookTarget()
  2715. {
  2716.         std::shared_ptr<Vec3> lookTarget(new Vec3(ZERO), DeleteLookTarget);
  2717.         m_lookTargets.push_back(lookTarget);
  2718.         return lookTarget;
  2719. }
  2720.  
  2721. CAIObject* CPipeUser::GetSpecialAIObject(const char* objName, float range)
  2722. {
  2723.         if (!objName) return NULL;
  2724.  
  2725.         CCCPOINT(CPipeUser_GetSpecialAIObject);
  2726.  
  2727.         CAIObject* pObject = NULL;
  2728.  
  2729.         CWeakRef<CPipeUser> refThis = GetWeakRef(this);
  2730.  
  2731.         if (range <= 0.0f)
  2732.                 range = 20.0f;
  2733.  
  2734.         CAISystem* pAISystem = GetAISystem();
  2735.  
  2736.         if (strcmp(objName, "player") == 0)
  2737.         {
  2738.                 pObject = pAISystem->GetPlayer();
  2739.         }
  2740.         else if (strcmp(objName, "self") == 0)
  2741.         {
  2742.                 pObject = this;
  2743.         }
  2744.         else if (strcmp(objName, "beacon") == 0)
  2745.         {
  2746.                 pObject = static_cast<CAIObject*>(pAISystem->GetBeacon(GetGroupId()));
  2747.         }
  2748.         else if (strcmp(objName, "refpoint") == 0)
  2749.         {
  2750.                 CPipeUser* pPipeUser = CastToCPipeUser();
  2751.                 if (pPipeUser)
  2752.                         pObject = pPipeUser->GetRefPoint();
  2753.         }
  2754.         else if (strcmp(objName, "formation") == 0)
  2755.         {
  2756.                 CLeader* pLeader = pAISystem->GetLeader(GetGroupId());
  2757.                 // is leader managing my formation?
  2758.                 {
  2759.                         CAIObject* pFormationOwner = (pLeader ? pLeader->GetFormationOwner().GetAIObject() : 0);
  2760.                         if (pFormationOwner && pFormationOwner->m_pFormation)
  2761.                         {
  2762.                                 // check if I already have one
  2763.                                 pObject = pLeader->GetFormationPoint(refThis).GetAIObject();
  2764.                                 if (!pObject)
  2765.                                         pObject = pLeader->GetNewFormationPoint(refThis).GetAIObject();
  2766.                         }
  2767.                         else
  2768.                         {
  2769.                                 CCCPOINT(CPipeUser_GetSpecialAIObject_A);
  2770.  
  2771.                                 CAIObject* pLastOp = GetLastOpResult();
  2772.                                 // check if Formation point is already acquired to lastOpResult
  2773.                                 if (pLastOp && pLastOp->GetSubType() == CAIObject::STP_FORMATION)
  2774.                                         pObject = pLastOp;
  2775.                                 else
  2776.                                 {
  2777.                                         IAIObject* pBoss = pAISystem->GetNearestObjectOfTypeInRange(this, AIOBJECT_ACTOR, 0, range, AIFAF_HAS_FORMATION | AIFAF_INCLUDE_DEVALUED | AIFAF_SAME_GROUP_ID);
  2778.                                         if (!pBoss)
  2779.                                                 pBoss = pAISystem->GetNearestObjectOfTypeInRange(this, AIOBJECT_VEHICLE, 0, range, AIFAF_HAS_FORMATION | AIFAF_INCLUDE_DEVALUED | AIFAF_SAME_GROUP_ID);
  2780.                                         if (CAIObject* pTheBoss = static_cast<CAIObject*>(pBoss))
  2781.                                         {
  2782.                                                 // check if I already have one
  2783.                                                 pObject = pTheBoss->m_pFormation->GetFormationPoint(refThis);
  2784.                                                 if (!pObject)
  2785.                                                         pObject = pTheBoss->m_pFormation->GetNewFormationPoint(refThis);
  2786.                                         }
  2787.                                 }
  2788.                                 if (!pObject)
  2789.                                 {
  2790.                                         // lets send a NoFormationPoint event
  2791.                                         SetSignal(1, "OnNoFormationPoint", 0, 0, gAIEnv.SignalCRCs.m_nOnNoFormationPoint);
  2792.                                         if (pLeader)
  2793.                                                 pLeader->SetSignal(1, "OnNoFormationPoint", GetEntity(), 0, gAIEnv.SignalCRCs.m_nOnNoFormationPoint);
  2794.                                 }
  2795.                         }
  2796.  
  2797.                 }
  2798.  
  2799.         }
  2800.         else if (strcmp(objName, "formation_id") == 0)
  2801.         {
  2802.  
  2803.                 CAIObject* pLastOp = GetLastOpResult();
  2804.                 // check if Formation point is already aquired to lastOpResult
  2805.  
  2806.                 if (pLastOp && pLastOp->GetSubType() == CAIObject::STP_FORMATION)
  2807.                         pObject = pLastOp;
  2808.                 else  // if not - find available formation point
  2809.                 {
  2810.                         int groupid((int)range);
  2811.                         CAIObject* pBoss(NULL);
  2812.                         AIObjects::iterator ai;
  2813.                         if ((ai = GetAISystem()->m_mapGroups.find(groupid)) != GetAISystem()->m_mapGroups.end())
  2814.                         {
  2815.                                 for (; ai != GetAISystem()->m_mapGroups.end() && !pBoss; )
  2816.                                 {
  2817.                                         if (ai->first != groupid)
  2818.                                                 break;
  2819.                                         CAIObject* pObj = ai->second.GetAIObject();
  2820.                                         if (pObj && pObj != this && pObj->m_pFormation)
  2821.                                         {
  2822.                                                 pBoss = pObj;
  2823.                                         }
  2824.                                         ++ai;
  2825.                                 }
  2826.                         }
  2827.                         if (pBoss && pBoss->m_pFormation)
  2828.                         {
  2829.                                 // check if I already have one
  2830.  
  2831.                                 pObject = pBoss->m_pFormation->GetFormationPoint(refThis);
  2832.                                 if (!pObject)
  2833.                                         pObject = pBoss->m_pFormation->GetNewFormationPoint(refThis);
  2834.                         }
  2835.  
  2836.                         if (!pObject)
  2837.                         {
  2838.                                 // lets send a NoFormationPoint event
  2839.                                 SetSignal(1, "OnNoFormationPoint", 0, 0, gAIEnv.SignalCRCs.