BVB Source Codes

CRYENGINE Show GoalOp_Crysis2.cpp Source code

Return Download CRYENGINE: download GoalOp_Crysis2.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: GoalOp_Crysis2.cpp
  6.    Description: Crysis2 goalops
  7.    These should move into GameDLL when interfaces allow!
  8.    -------------------------------------------------------------------------
  9.    History:
  10.    - 18:11:2009 - Created by M谩rcio Martins
  11.  *********************************************************************/
  12.  
  13. #include "StdAfx.h"
  14. #include "GoalOp_Crysis2.h"
  15. #include "GoalOpTrace.h"
  16.  
  17. #include "PipeUser.h"
  18. #include "Puppet.h"
  19. #include "DebugDrawContext.h"
  20. #include "HideSpot.h"
  21. #include "Cover/CoverSystem.h"
  22. #include "GenericAStarSolver.h"
  23. #include "FlightNavRegion2.h"
  24. #include "ObjectContainer.h"
  25.  
  26. #include "Communication/CommunicationManager.h"
  27. #include "Navigation/NavigationSystem/NavigationSystem.h"
  28. #include "AIPlayer.h"
  29.  
  30. //#pragma optimize("", off)
  31. //#pragma inline_depth(0)
  32.  
  33. namespace COPCrysis2Utils
  34. {
  35. //
  36. //-------------------------------------------------------------------------------------------------------------
  37. // Turns body to the left when 'targetPos' is left of 'pos' (with hideDir a vector pointing out of the cover object)
  38. static void TurnBodyToTargetInCover(CPipeUser* pPipeUser, const Vec3& pos, const Vec3& hideDir, const Vec3& targetPos)
  39. {
  40.         SOBJECTSTATE& state = pPipeUser->GetState();
  41.         state.coverRequest.SetCoverBodyDirection(hideDir, targetPos - pos);
  42. }
  43. }
  44.  
  45. //
  46. //-------------------------------------------------------------------------------------------------------------
  47. IGoalOp* CGoalOpFactoryCrysis2::GetGoalOp(const char* sGoalOpName, IFunctionHandler* pH, int firstParam, GoalParameters& params) const
  48. {
  49.         EGoalOperations op = CGoalPipe::GetGoalOpEnum(sGoalOpName);
  50.  
  51.         switch (op)
  52.         {
  53.         case eGO_ADJUSTAIM:
  54.                 {
  55.                         params.nValue = 0;
  56.                         params.fValue = 0.0f; // timeout
  57.                         int hide = 0;
  58.                         int useLastOpResultAsBackup = 0;
  59.                         int allowProne = 0;
  60.  
  61.                         pH->GetParam(firstParam, hide);
  62.                         if (pH->GetParamCount() > firstParam)
  63.                                 pH->GetParam(firstParam + 1, params.fValue); // timeout
  64.                         if (pH->GetParamCount() > firstParam + 1)
  65.                                 pH->GetParam(firstParam + 2, useLastOpResultAsBackup);
  66.                         if (pH->GetParamCount() > firstParam + 2)
  67.                                 pH->GetParam(firstParam + 3, allowProne);
  68.  
  69.                         if (hide)
  70.                                 params.nValue |= 0x1;
  71.  
  72.                         if (useLastOpResultAsBackup)
  73.                                 params.nValue |= 0x2;
  74.  
  75.                         if (allowProne)
  76.                                 params.nValue |= 0x4;
  77.                 }
  78.                 break;
  79.         case eGO_PEEK:
  80.                 {
  81.                         params.nValue = 0;
  82.                         params.fValue = 0.0f; // timeout
  83.                         int useLastOpResultAsBackup = 0;
  84.  
  85.                         pH->GetParam(firstParam, params.fValue); // timeout
  86.                         if (pH->GetParamCount() > firstParam)
  87.                                 pH->GetParam(firstParam + 1, useLastOpResultAsBackup);
  88.  
  89.                         if (useLastOpResultAsBackup)
  90.                                 params.nValue |= 0x1;
  91.                 }
  92.                 break;
  93.         case eGO_HIDE:
  94.                 {
  95.                         params.nValue = AI_REG_COVER;
  96.                         params.bValue = true;
  97.  
  98.                         pH->GetParam(firstParam, params.nValue); // location
  99.                         if (pH->GetParamCount() > firstParam)
  100.                                 pH->GetParam(firstParam + 1, params.bValue); // exact
  101.                 }
  102.                 break;
  103.         case eGO_STICKPATH:
  104.                 {
  105.                         const int paramCount = pH->GetParamCount();
  106.  
  107.                         // finishInRange
  108.                         bool bFinishInRange = true;
  109.                         pH->GetParam(firstParam, bFinishInRange);
  110.                         params.nValue |= (bFinishInRange ? 0x02 : 0);
  111.  
  112.                         // stick distance max
  113.                         pH->GetParam(firstParam + 1, params.vPos.y);
  114.  
  115.                         if (paramCount > firstParam + 1)
  116.                         {
  117.                                 // stick distance min
  118.                                 pH->GetParam(firstParam + 2, params.vPos.x);
  119.  
  120.                                 if (paramCount > firstParam + 2)
  121.                                 {
  122.                                         // canReverse
  123.                                         bool bCanReverse = true;
  124.                                         pH->GetParam(firstParam + 3, bCanReverse);
  125.                                         params.nValue |= (bCanReverse ? 0x01 : 0);
  126.                                 }
  127.                         }
  128.                 }
  129.                 break;
  130.         case eGO_FIREWEAPONS:
  131.                 pH->GetParam(firstParam, params.nValue);
  132.                 pH->GetParam(firstParam + 1, params.fValue);
  133.                 pH->GetParam(firstParam + 2, params.fValueAux);
  134.                 pH->GetParam(firstParam + 3, params.bValue);
  135.                 pH->GetParam(firstParam + 4, params.nValueAux);
  136.                 break;
  137.         case eGO_HOVER:
  138.                 pH->GetParam(firstParam, params.nValue);
  139.                 pH->GetParam(firstParam + 1, params.bValue);
  140.                 break;
  141.  
  142.         default:
  143.                 return NULL;
  144.         }
  145.  
  146.         return GetGoalOp(op, params);
  147. }
  148.  
  149. //
  150. //-------------------------------------------------------------------------------------------------------------
  151. IGoalOp* CGoalOpFactoryCrysis2::GetGoalOp(EGoalOperations op, GoalParameters& params) const
  152. {
  153.         IGoalOp* pResult = NULL;
  154.  
  155.         switch (op)
  156.         {
  157.         case eGO_ADJUSTAIM:
  158.                 {
  159.                         pResult = new COPCrysis2AdjustAim((params.nValue & 0x02) != 0, (params.nValue & 0x04) != 0, params.fValue);
  160.                 }
  161.                 break;
  162.         case eGO_PEEK:
  163.                 {
  164.                         pResult = new COPCrysis2Peek((params.nValue & 0x02) != 0, params.fValue);
  165.                 }
  166.                 break;
  167.         case eGO_HIDE:
  168.                 {
  169.                         pResult = new COPCrysis2Hide(static_cast<EAIRegister>(params.nValue), params.bValue);
  170.                 }
  171.                 break;
  172.         case eGO_COMMUNICATE:
  173.                 {
  174.                         pResult = new COPCrysis2Communicate(CommID(params.nValue), CommChannelID(params.nValueAux), params.fValue, static_cast<EAIRegister>(int(params.fValueAux)),
  175.                                                             params.bValue ? SCommunicationRequest::Unordered : SCommunicationRequest::Ordered);
  176.                 }
  177.                 break;
  178.         case eGO_STICKPATH:
  179.                 {
  180.                         // nValue & 0x01 == canReverse
  181.                         // nValue & 0x02 == finishInRange
  182.                         pResult = new COPCrysis2StickPath((params.nValue & 0x02) != 0, params.vPos.y, params.vPos.x, (params.nValue & 0x01) != 0);
  183.                 }
  184.                 break;
  185.         case eGO_HOVER:
  186.                 {
  187.                         pResult = new COPCrysis2Hover(static_cast<EAIRegister>(params.nValue), params.bValue);
  188.                 }
  189.                 break;
  190.         case eGO_FLY:
  191.                 {
  192.                         pResult = new COPCrysis2Fly();
  193.                 }
  194.                 break;
  195.         case eGO_CHASETARGET:
  196.                 {
  197.                         pResult = new COPCrysis2ChaseTarget();
  198.                 }
  199.                 break;
  200.         case eGO_FIREWEAPONS:
  201.                 {
  202.                         pResult = new COPCrysis2FlightFireWeapons(static_cast<EAIRegister>(params.nValue), params.fValue, params.fValueAux, params.bValue, static_cast<uint32>(params.nValueAux));
  203.                 }
  204.                 break;
  205.         case eGO_ACQUIREPOSITION:
  206.                 {
  207.                         pResult = new COPAcquirePosition();
  208.                 }
  209.                 break;
  210.         default:
  211.                 return NULL;
  212.         }
  213.  
  214.         return pResult;
  215. }
  216.  
  217. //
  218. //-------------------------------------------------------------------------------------------------------------
  219. COPCrysis2AdjustAim::COPCrysis2AdjustAim(bool useLastOpAsBackup, bool allowProne, float timeout) :
  220.         m_useLastOpAsBackup(useLastOpAsBackup),
  221.         m_allowProne(allowProne),
  222.         m_timeoutMs((int)(timeout * 1000.0f)),
  223.         m_timeoutRandomness(0.0f),
  224.         m_bestPostureID(-1),
  225.         m_queryID(0)
  226. {
  227.         m_startTime.SetValue(0);
  228.         m_lastGood.SetValue(0);
  229.  
  230.         m_nextUpdateMs = RandomizeTimeInterval();
  231.         m_runningTimeoutMs = 0;
  232. }
  233.  
  234. //
  235. //-------------------------------------------------------------------------------------------------------------
  236. COPCrysis2AdjustAim::COPCrysis2AdjustAim(const XmlNodeRef& node) :
  237.         m_useLastOpAsBackup(s_xml.GetBool(node, "useLastOpResultAsBackup")),
  238.         m_allowProne(s_xml.GetBool(node, "allowProne")),
  239.         m_timeoutRandomness(0.0f),
  240.         m_timeoutMs(0),
  241.         m_bestPostureID(-1),
  242.         m_queryID(0)
  243. {
  244.         float timeout = 0.0f;
  245.         node->getAttr("timeout", timeout);
  246.         m_timeoutMs = (int)(timeout * 1000.0f);
  247.  
  248.         node->getAttr("timeoutRandomness", m_timeoutRandomness);
  249.  
  250.         m_startTime.SetValue(0);
  251.         m_lastGood.SetValue(0);
  252.  
  253.         m_nextUpdateMs = RandomizeTimeInterval();
  254.         m_runningTimeoutMs = 0;
  255. }
  256.  
  257. //
  258. //-------------------------------------------------------------------------------------------------------------
  259. int COPCrysis2AdjustAim::RandomizeTimeInterval() const
  260. {
  261.         return cry_random(250, 500);
  262. }
  263.  
  264. //
  265. //-------------------------------------------------------------------------------------------------------------
  266. EGoalOpResult COPCrysis2AdjustAim::Execute(CPipeUser* pPipeUser)
  267. {
  268.         CCCPOINT(COPCrysis2AdjustAim_Execute);
  269.         FUNCTION_PROFILER(GetISystem(), PROFILE_AI);
  270.  
  271.         CPuppet* pPuppet = pPipeUser->CastToCPuppet();
  272.         if (!pPuppet)
  273.                 return eGOR_FAILED;
  274.  
  275.         CTimeValue now(GetAISystem()->GetFrameStartTime());
  276.  
  277.         if (!m_startTime.GetValue())
  278.         {
  279.                 m_runningTimeoutMs = m_timeoutMs;
  280.  
  281.                 if (m_timeoutRandomness > 0.0001f)
  282.                         m_runningTimeoutMs += (int)cry_random(0.0f, m_timeoutRandomness * 1000.0f);
  283.  
  284.                 m_startTime = now;
  285.                 m_lastGood = now;
  286.  
  287.                 pPipeUser->SetAdjustingAim(true);
  288.         }
  289.  
  290.         CAIObject* pLastOpResult = pPipeUser->m_refLastOpResult.GetAIObject();
  291.  
  292.         Vec3 target(ZERO);
  293.  
  294.         if (pPipeUser->GetAttentionTarget())
  295.                 target = pPipeUser->GetAttentionTarget()->GetPos();
  296.         else if (m_useLastOpAsBackup && (pLastOpResult != NULL))
  297.                 target = pLastOpResult->GetPos();
  298.         else
  299.         {
  300.                 Reset(pPipeUser);
  301.  
  302.                 return eGOR_FAILED;
  303.         }
  304.  
  305.         bool isMoving = (pPipeUser->m_State.fDesiredSpeed >= 0.001f) && !pPipeUser->m_State.vMoveDir.IsZero();
  306.         int64 elapsedMs = (now - m_startTime).GetMilliSecondsAsInt64();
  307.  
  308.         if ((elapsedMs >= m_nextUpdateMs) && isMoving)
  309.                 m_nextUpdateMs += 150;
  310.         else if (elapsedMs >= m_nextUpdateMs)
  311.         {
  312.                 PostureManager::PostureID postureID = -1;
  313.                 PostureManager::PostureInfo* posture;
  314.  
  315.                 PostureManager& postureManager = pPuppet->GetPostureManager();
  316.  
  317.                 if (!m_queryID)
  318.                 {
  319.                         uint32 checks = PostureManager::DefaultChecks;
  320.                         if (pPuppet->GetFireMode() == FIREMODE_OFF)
  321.                                 checks &= ~PostureManager::CheckAimability;
  322.  
  323.                         PostureManager::PostureQuery query;
  324.                         query.actor = pPuppet;
  325.                         query.allowLean = true;
  326.                         query.allowProne = m_allowProne;
  327.                         query.checks = checks;
  328.  
  329.                         if (pPuppet->IsInCover())
  330.                                 query.coverID = pPuppet->GetCoverID();
  331.  
  332.                         query.distancePercent = 0.85f;
  333.                         query.hintPostureID = m_bestPostureID;
  334.                         query.position = pPuppet->GetPhysicsPos();
  335.                         query.target = target;
  336.                         query.type = PostureManager::AimPosture;
  337.  
  338.                         m_queryID = postureManager.QueryPosture(query);
  339.                         if (!m_queryID)
  340.                         {
  341.                                 if (!ProcessQueryResult(pPipeUser, AsyncFailed, 0))
  342.                                 {
  343.                                         Reset(pPipeUser);
  344.  
  345.                                         return eGOR_FAILED;
  346.                                 }
  347.                         }
  348.                 }
  349.                 else
  350.                 {
  351.                         AsyncState queryStatus = postureManager.GetPostureQueryResult(m_queryID, &m_bestPostureID, &posture);
  352.  
  353.                         if (queryStatus != AsyncInProgress)
  354.                         {
  355.                                 m_queryID = 0;
  356.                                 if (!ProcessQueryResult(pPipeUser, queryStatus, posture))
  357.                                 {
  358.                                         Reset(pPipeUser);
  359.  
  360.                                         return eGOR_FAILED;
  361.                                 }
  362.                         }
  363.                 }
  364.  
  365.                 m_nextUpdateMs += RandomizeTimeInterval();
  366.                 if (pPipeUser->m_State.bodystate == STANCE_PRONE)
  367.                         m_nextUpdateMs += 2000;
  368.         }
  369.  
  370.         bool finished = (m_runningTimeoutMs > 0) && (elapsedMs >= m_runningTimeoutMs);
  371.         if (!finished)
  372.         {
  373.                 int timeToNextShotMs = (int)(pPuppet->GetTimeToNextShot() * 1000.0f);
  374.  
  375.                 finished = (timeToNextShotMs > 0) && (timeToNextShotMs > (m_runningTimeoutMs - elapsedMs));
  376.         }
  377.  
  378.         if (finished)
  379.         {
  380.                 Reset(pPipeUser);
  381.  
  382.                 return eGOR_SUCCEEDED;
  383.         }
  384.  
  385.         return eGOR_IN_PROGRESS;
  386. }
  387.  
  388. bool COPCrysis2AdjustAim::ProcessQueryResult(CPipeUser* pipeUser, AsyncState queryStatus,
  389.                                              PostureManager::PostureInfo* postureInfo)
  390. {
  391.         CRY_ASSERT(pipeUser);
  392.  
  393.         CTimeValue now(GetAISystem()->GetFrameStartTime());
  394.  
  395.         if (queryStatus != AsyncFailed)
  396.         {
  397.                 CRY_ASSERT(postureInfo);
  398.  
  399.                 pipeUser->m_State.bodystate = postureInfo->stance;
  400.                 pipeUser->m_State.lean = postureInfo->lean;
  401.                 pipeUser->m_State.peekOver = postureInfo->peekOver;
  402.  
  403.                 const bool coverAction = pipeUser->IsInCover();
  404.                 if (coverAction)
  405.                 {
  406.                         const char* const coverActionName = postureInfo->agInput.c_str();
  407.                         pipeUser->m_State.coverRequest.SetCoverAction(coverActionName, postureInfo->lean);
  408.                 }
  409.                 else
  410.                 {
  411.                         if (!postureInfo->agInput.empty())
  412.                                 pipeUser->GetProxy()->SetAGInput(AIAG_ACTION, postureInfo->agInput.c_str());
  413.                         else
  414.                                 pipeUser->GetProxy()->ResetAGInput(AIAG_ACTION);
  415.                 }
  416.  
  417.                 m_lastGood = now;
  418.         }
  419.         else
  420.         {
  421.                 if ((now - m_lastGood).GetMilliSecondsAsInt64() > 500)
  422.                 {
  423.                         pipeUser->SetSignal(1, "OnNoAimPosture", 0, 0, gAIEnv.SignalCRCs.m_nOnNoAimPosture);
  424.  
  425.                         return false;
  426.                 }
  427.  
  428.                 // Could not find new pose, keep stance and remove peek.
  429.                 pipeUser->GetProxy()->ResetAGInput(AIAG_ACTION);
  430.                 pipeUser->m_State.lean = 0;
  431.                 pipeUser->m_State.peekOver = 0;
  432.                 pipeUser->m_State.coverRequest.ClearCoverAction();
  433.         }
  434.  
  435.         return true;
  436. }
  437.  
  438. //
  439. //-------------------------------------------------------------------------------------------------------------
  440. void COPCrysis2AdjustAim::Reset(CPipeUser* pPipeUser)
  441. {
  442.         pPipeUser->m_State.lean = 0.0f;
  443.         pPipeUser->m_State.peekOver = 0.0f;
  444.         pPipeUser->m_State.coverRequest.ClearCoverAction();
  445.         pPipeUser->GetProxy()->ResetAGInput(AIAG_ACTION);
  446.         pPipeUser->SetAdjustingAim(false);
  447.  
  448.         if (m_queryID)
  449.         {
  450.                 pPipeUser->CastToCPuppet()->GetPostureManager().CancelPostureQuery(m_queryID);
  451.                 m_queryID = 0;
  452.         }
  453.  
  454.         m_startTime.SetValue(0);
  455.         m_lastGood.SetValue(0);
  456.         m_nextUpdateMs = RandomizeTimeInterval();
  457.         m_bestPostureID = -1;
  458. }
  459.  
  460. //
  461. //-------------------------------------------------------------------------------------------------------------
  462. void COPCrysis2AdjustAim::Serialize(TSerialize ser)
  463. {
  464.         ser.BeginGroup("COPCrysis2AdjustAim");
  465.         {
  466.                 ser.Value("m_startTime", m_startTime);
  467.                 ser.Value("m_nextUpdateMs", m_nextUpdateMs);
  468.                 ser.Value("m_useLastOpAsBackup", m_useLastOpAsBackup);
  469.         }
  470.         ser.EndGroup();
  471. }
  472.  
  473. //
  474. //-------------------------------------------------------------------------------------------------------------
  475. void COPCrysis2AdjustAim::DebugDraw(CPipeUser* pPipeUser) const
  476. {
  477.         if (!pPipeUser)
  478.                 return;
  479.  
  480.         // m_selector.DebugDraw(pPipeUser);
  481.  
  482.         Vec3 basePos = pPipeUser->GetPhysicsPos();
  483.         Vec3 targetPos = pPipeUser->GetProbableTargetPosition();
  484.  
  485.         CDebugDrawContext dc;
  486.  
  487.         /* for(unsigned i = 0; i < 8; ++i)
  488.            {
  489.            if(!m_postures[i].valid) continue;
  490.            dc->DrawCone(m_postures[i].weapon, m_postures[i].weaponDir, 0.05f, m_postures[i].targetAim ? 0.4f : 0.2f, ColorB(255,0,0, m_postures[i].targetAim ? 255 : 128));
  491.            dc->DrawSphere(m_postures[i].eye, 0.1f, ColorB(255,255,255, m_postures[i].targetVis ? 255 : 128));
  492.            dc->DrawLine(basePos, ColorB(255,255,255), m_postures[i].eye, ColorB(255,255, 255));
  493.  
  494.            if((int)i == m_bestPosture)
  495.            {
  496.            dc->DrawLine(m_postures[i].weapon, ColorB(255,0,0), targetPos, ColorB(255,0,0,0));
  497.            dc->DrawLine(m_postures[i].eye, ColorB(255, 255, 255), targetPos, ColorB(255, 255, 255, 0));
  498.            }
  499.            }
  500.          */
  501.  
  502.         Vec3 toeToHead = pPipeUser->GetPos() - pPipeUser->GetPhysicsPos();
  503.         float len = toeToHead.GetLength();
  504.         if (len > 0.0001f)
  505.                 toeToHead *= (len - 0.3f) / len;
  506.         dc->DrawSphere(pPipeUser->GetPhysicsPos() + toeToHead, 0.4f, ColorB(200, 128, 0, 90));
  507.  
  508.         dc->DrawLine(pPipeUser->GetFirePos(), ColorB(255, 0, 0), targetPos, ColorB(255, 0, 0, 64));
  509.         dc->DrawLine(pPipeUser->GetPos(), ColorB(255, 255, 255), targetPos, ColorB(255, 255, 255, 64));
  510.  
  511.         CPuppet* pPuppet = pPipeUser->CastToCPuppet();
  512.         if (!pPuppet)
  513.                 return;
  514.  
  515.         static string text;
  516.  
  517.         text = "AIM ";
  518.  
  519.         if (m_bestPostureID > -1)
  520.         {
  521.                 PostureManager::PostureInfo posture;
  522.                 pPuppet->GetPostureManager().GetPosture(m_bestPostureID, &posture);
  523.  
  524.                 text += posture.name;
  525.         }
  526.         else
  527.                 text += "<$4No Posture$o>";
  528.  
  529.         const Vec3 agentHead = pPipeUser->GetPos();
  530.         const ColorB white(255, 255, 255, 255);
  531.         const float fontSize = 1.25f;
  532.  
  533.         float x, y, z;
  534.         if (!dc->ProjectToScreen(agentHead.x, agentHead.y, agentHead.z, &x, &y, &z))
  535.                 return;
  536.  
  537.         if ((z < 0.0f) || (z > 1.0f))
  538.                 return;
  539.  
  540.         x *= dc->GetWidth() * 0.01f;
  541.         y *= dc->GetHeight() * 0.01f;
  542.  
  543.         y += 100.0f;
  544.         dc->Draw2dLabel(x, y, fontSize, white, true, "%s", text.c_str());
  545. }
  546.  
  547. //
  548. //-------------------------------------------------------------------------------------------------------------
  549. COPCrysis2Peek::COPCrysis2Peek(bool useLastOpAsBackup, float timeout) :
  550.         m_useLastOpAsBackup(useLastOpAsBackup),
  551.         m_timeoutMs((int)(timeout * 1000.0f)),
  552.         m_timeoutRandomness(0.0f),
  553.         m_bestPostureID(-1),
  554.         m_queryID(0)
  555. {
  556.         m_startTime.SetValue(0);
  557.         m_lastGood.SetValue(0);
  558.  
  559.         m_nextUpdateMs = RandomizeTimeInterval();
  560.         m_runningTimeoutMs = 0;
  561. }
  562.  
  563. //
  564. //-------------------------------------------------------------------------------------------------------------
  565. COPCrysis2Peek::COPCrysis2Peek(const XmlNodeRef& node) :
  566.         m_useLastOpAsBackup(s_xml.GetBool(node, "useLastOpResultAsBackup")),
  567.         m_timeoutRandomness(0.0f),
  568.         m_timeoutMs(0),
  569.         m_bestPostureID(-1),
  570.         m_queryID(0)
  571. {
  572.         float timeout = 0.0f;
  573.         node->getAttr("timeout", timeout);
  574.         m_timeoutMs = (int)(timeout * 1000.0f);
  575.  
  576.         node->getAttr("timeoutRandomness", m_timeoutRandomness);
  577.  
  578.         m_startTime.SetValue(0);
  579.         m_lastGood.SetValue(0);
  580.  
  581.         m_nextUpdateMs = RandomizeTimeInterval();
  582.         m_runningTimeoutMs = 0;
  583. }
  584.  
  585. //
  586. //-------------------------------------------------------------------------------------------------------------
  587. int COPCrysis2Peek::RandomizeTimeInterval() const
  588. {
  589.         return cry_random(250, 500);
  590. }
  591.  
  592. //
  593. //-------------------------------------------------------------------------------------------------------------
  594. EGoalOpResult COPCrysis2Peek::Execute(CPipeUser* pPipeUser)
  595. {
  596.         CCCPOINT(COPCrysis2Peek_Execute);
  597.         FUNCTION_PROFILER(GetISystem(), PROFILE_AI);
  598.  
  599.         CPuppet* pPuppet = pPipeUser->CastToCPuppet();
  600.         if (!pPuppet)
  601.                 return eGOR_FAILED;
  602.  
  603.         if (!pPuppet->IsInCover())
  604.         {
  605.                 Reset(pPipeUser);
  606.  
  607.                 return eGOR_FAILED;
  608.         }
  609.  
  610.         CTimeValue now(GetAISystem()->GetFrameStartTime());
  611.  
  612.         if (!m_startTime.GetValue())
  613.         {
  614.                 m_runningTimeoutMs = m_timeoutMs;
  615.  
  616.                 if (m_timeoutRandomness > 0.0001f)
  617.                         m_runningTimeoutMs += (int)cry_random(0.0f, m_timeoutRandomness * 1000.0f);
  618.  
  619.                 m_startTime = now;
  620.                 m_lastGood = now;
  621.         }
  622.  
  623.         CAIObject* pLastOpResult = pPipeUser->m_refLastOpResult.GetAIObject();
  624.  
  625.         Vec3 target;
  626.  
  627.         if (pPipeUser->GetAttentionTarget())
  628.                 target = pPipeUser->GetAttentionTarget()->GetPos();
  629.         else if (m_useLastOpAsBackup && (pLastOpResult != NULL))
  630.                 target = pLastOpResult->GetPos();
  631.         else
  632.         {
  633.                 Reset(pPipeUser);
  634.  
  635.                 return eGOR_FAILED;
  636.         }
  637.  
  638.         int64 elapsedMs = (now - m_startTime).GetMilliSecondsAsInt64();
  639.  
  640.         if (elapsedMs >= m_nextUpdateMs)
  641.         {
  642.                 PostureManager::PostureID postureID = -1;
  643.                 PostureManager::PostureInfo* posture;
  644.  
  645.                 PostureManager& postureManager = pPuppet->GetPostureManager();
  646.  
  647.                 if (!m_queryID)
  648.                 {
  649.                         uint32 checks = PostureManager::CheckVisibility | PostureManager::CheckLeanability;
  650.  
  651.                         PostureManager::PostureQuery query;
  652.                         query.actor = pPuppet;
  653.                         query.allowLean = true;
  654.                         query.allowProne = false;
  655.                         query.checks = checks;
  656.                         query.coverID = pPuppet->GetCoverID();
  657.                         query.distancePercent = 0.25f;
  658.                         query.hintPostureID = m_bestPostureID;
  659.                         query.position = pPuppet->GetPhysicsPos();
  660.                         query.target = target;
  661.                         query.type = PostureManager::PeekPosture;
  662.  
  663.                         m_queryID = postureManager.QueryPosture(query);
  664.                         if (!m_queryID)
  665.                         {
  666.                                 if (!ProcessQueryResult(pPipeUser, AsyncFailed, 0))
  667.                                 {
  668.                                         Reset(pPipeUser);
  669.  
  670.                                         return eGOR_FAILED;
  671.                                 }
  672.                         }
  673.                 }
  674.                 else
  675.                 {
  676.                         AsyncState queryStatus = postureManager.GetPostureQueryResult(m_queryID, &m_bestPostureID, &posture);
  677.  
  678.                         if (queryStatus != AsyncInProgress)
  679.                         {
  680.                                 m_queryID = 0;
  681.                                 if (!ProcessQueryResult(pPipeUser, queryStatus, posture))
  682.                                 {
  683.                                         Reset(pPipeUser);
  684.  
  685.                                         return eGOR_FAILED;
  686.                                 }
  687.                         }
  688.                 }
  689.  
  690.                 m_nextUpdateMs += RandomizeTimeInterval();
  691.         }
  692.  
  693.         bool finished = (m_runningTimeoutMs > 0) && (elapsedMs >= m_runningTimeoutMs);
  694.  
  695.         if (finished)
  696.         {
  697.                 Reset(pPipeUser);
  698.  
  699.                 return eGOR_SUCCEEDED;
  700.         }
  701.  
  702.         return eGOR_IN_PROGRESS;
  703. }
  704.  
  705. bool COPCrysis2Peek::ProcessQueryResult(CPipeUser* pipeUser, AsyncState queryStatus,
  706.                                         PostureManager::PostureInfo* postureInfo)
  707. {
  708.         assert(pipeUser);
  709.  
  710.         CTimeValue now(GetAISystem()->GetFrameStartTime());
  711.  
  712.         if (queryStatus != AsyncFailed)
  713.         {
  714.                 assert(postureInfo);
  715.  
  716.                 pipeUser->m_State.bodystate = postureInfo->stance;
  717.                 pipeUser->m_State.lean = postureInfo->lean;
  718.                 pipeUser->m_State.peekOver = postureInfo->peekOver;
  719.  
  720.                 const bool coverAction = pipeUser->IsInCover();
  721.                 if (coverAction)
  722.                 {
  723.                         const char* const coverActionName = postureInfo->agInput.c_str();
  724.                         pipeUser->m_State.coverRequest.SetCoverAction(coverActionName, postureInfo->lean);
  725.                 }
  726.                 else
  727.                 {
  728.                         if (!postureInfo->agInput.empty())
  729.                                 pipeUser->GetProxy()->SetAGInput(AIAG_ACTION, postureInfo->agInput.c_str());
  730.                         else
  731.                                 pipeUser->GetProxy()->ResetAGInput(AIAG_ACTION);
  732.                 }
  733.  
  734.                 m_lastGood = now;
  735.         }
  736.         else
  737.         {
  738.                 if ((now - m_lastGood).GetMilliSecondsAsInt64() > 500)
  739.                 {
  740.                         pipeUser->SetSignal(1, "OnNoPeekPosture", 0, 0, gAIEnv.SignalCRCs.m_nOnNoPeekPosture);
  741.  
  742.                         return false;
  743.                 }
  744.  
  745.                 // Could not find new pose, keep stance and remove peek.
  746.                 pipeUser->GetProxy()->ResetAGInput(AIAG_ACTION);
  747.                 pipeUser->m_State.lean = 0;
  748.                 pipeUser->m_State.peekOver = 0;
  749.                 pipeUser->m_State.coverRequest.ClearCoverAction();
  750.         }
  751.  
  752.         return true;
  753. }
  754.  
  755. //
  756. //-------------------------------------------------------------------------------------------------------------
  757. void COPCrysis2Peek::Reset(CPipeUser* pPipeUser)
  758. {
  759.         pPipeUser->m_State.lean = 0.0f;
  760.         pPipeUser->m_State.peekOver = 0.0f;
  761.         pPipeUser->m_State.coverRequest.ClearCoverAction();
  762.         pPipeUser->GetProxy()->ResetAGInput(AIAG_ACTION);
  763.  
  764.         if (m_queryID)
  765.         {
  766.                 pPipeUser->CastToCPuppet()->GetPostureManager().CancelPostureQuery(m_queryID);
  767.                 m_queryID = 0;
  768.         }
  769.  
  770.         m_startTime.SetValue(0);
  771.         m_lastGood.SetValue(0);
  772.         m_nextUpdateMs = RandomizeTimeInterval();
  773.         m_bestPostureID = -1;
  774. }
  775.  
  776. //
  777. //-------------------------------------------------------------------------------------------------------------
  778. void COPCrysis2Peek::Serialize(TSerialize ser)
  779. {
  780.         ser.BeginGroup("COPCrysis2Peek");
  781.         {
  782.                 ser.Value("m_startTime", m_startTime);
  783.                 ser.Value("m_nextUpdateMs", m_nextUpdateMs);
  784.                 ser.Value("m_useLastOpAsBackup", m_useLastOpAsBackup);
  785.         }
  786.         ser.EndGroup();
  787. }
  788.  
  789. //
  790. //-------------------------------------------------------------------------------------------------------------
  791. void COPCrysis2Peek::DebugDraw(CPipeUser* pPipeUser) const
  792. {
  793.         if (!pPipeUser)
  794.                 return;
  795.  
  796.         CPuppet* pPuppet = pPipeUser->CastToCPuppet();
  797.         if (!pPuppet)
  798.                 return;
  799.  
  800.         CDebugDrawContext dc;
  801.  
  802.         stack_string text;
  803.  
  804.         text = "AIM ";
  805.  
  806.         if (m_bestPostureID > -1)
  807.         {
  808.                 PostureManager::PostureInfo posture;
  809.                 pPuppet->GetPostureManager().GetPosture(m_bestPostureID, &posture);
  810.  
  811.                 text += posture.name;
  812.         }
  813.         else
  814.                 text += "<$4No Posture$o>";
  815.  
  816.         const Vec3 agentHead = pPipeUser->GetPos();
  817.         const ColorB white(255, 255, 255, 255);
  818.         const float fontSize = 1.25f;
  819.  
  820.         float x, y, z;
  821.         if (!dc->ProjectToScreen(agentHead.x, agentHead.y, agentHead.z, &x, &y, &z))
  822.                 return;
  823.  
  824.         if ((z < 0.0f) || (z > 1.0f))
  825.                 return;
  826.  
  827.         x *= dc->GetWidth() * 0.01f;
  828.         y *= dc->GetHeight() * 0.01f;
  829.  
  830.         y += 100.0f;
  831.         dc->Draw2dLabel(x, y, fontSize, white, true, "%s", text.c_str());
  832. }
  833.  
  834. COPCrysis2Hide::COPCrysis2Hide(EAIRegister location, bool exact)
  835.         : m_location(location)
  836.         , m_exact(exact)
  837.         , m_pPathfinder(0)
  838.         , m_pTracer(0)
  839. {
  840. }
  841.  
  842. COPCrysis2Hide::COPCrysis2Hide(const XmlNodeRef& node) :
  843.         m_location(AI_REG_NONE),
  844.         m_exact(s_xml.GetBool(node, "exact", true)),
  845.         m_pPathfinder(0),
  846.         m_pTracer(0)
  847. {
  848.         s_xml.GetRegister(node, "register", m_location, CGoalOpXMLReader::MANDATORY);
  849. }
  850.  
  851. COPCrysis2Hide::COPCrysis2Hide(const COPCrysis2Hide& rhs) :
  852.         m_location(rhs.m_location),
  853.         m_exact(rhs.m_exact),
  854.         m_pPathfinder(0),
  855.         m_pTracer(0)
  856. {
  857. }
  858.  
  859. COPCrysis2Hide::~COPCrysis2Hide()
  860. {
  861.         m_refHideTarget.Release();
  862.  
  863.         SAFE_DELETE(m_pPathfinder);
  864.         SAFE_DELETE(m_pTracer);
  865. }
  866.  
  867. EGoalOpResult COPCrysis2Hide::Execute(CPipeUser* pPipeUser)
  868. {
  869.         CCCPOINT(COPCrysis2Hide_Execute);
  870.  
  871.         if (m_refHideTarget.IsNil())
  872.         {
  873.                 CCCPOINT(COPCrysis2Hide_Execute_NoHideTarget);
  874.  
  875.                 pPipeUser->ClearPath("COPCrysis2Hide::Execute");
  876.  
  877.                 if (m_location == AI_REG_REFPOINT)
  878.                 {
  879.                         CCCPOINT(COPCrysis2Hide_Execute_RefPoint);
  880.  
  881.                         if (IAIObject* pRefPoint = pPipeUser->GetRefPoint())
  882.                         {
  883.                                 // Setup the hide object.
  884.                                 Vec3 pos = pRefPoint->GetPos();
  885.                                 Vec3 dir = pRefPoint->GetEntityDir();
  886.  
  887.                                 if (dir.IsZero())
  888.                                 {
  889.                                         Vec3 target(pPipeUser->GetAttentionTarget() ? pPipeUser->GetAttentionTarget()->GetPos() : pos);
  890.                                         dir = (target - pos).GetNormalizedSafe();
  891.                                 }
  892.  
  893.                                 SHideSpot hideSpot(SHideSpotInfo::eHST_ANCHOR, pos, dir);
  894.                                 CAIHideObject& currentHideObject = pPipeUser->m_CurrentHideObject;
  895.                                 currentHideObject.Set(&hideSpot, hideSpot.info.pos, hideSpot.info.dir);
  896.  
  897.                                 if (!currentHideObject.IsValid() ||
  898.                                     !GetAISystem()->IsHideSpotOccupied(pPipeUser, hideSpot.info.pos))
  899.                                 {
  900.                                         Reset(pPipeUser);
  901.  
  902.                                         pPipeUser->SetInCover(false);
  903.  
  904.                                         return eGOR_FAILED;
  905.                                 }
  906.  
  907.                                 CreateHideTarget(pPipeUser, pos);
  908.                         }
  909.                 }
  910.                 else // AI_REG_COVER
  911.                 {
  912.                         CCCPOINT(COPCrysis2Hide_Execute_HideObject);
  913.  
  914.                         if (CoverID coverID = pPipeUser->GetCoverRegister())
  915.                         {
  916.                                 float distanceToCover = pPipeUser->GetParameters().distanceToCover;
  917.  
  918.                                 Vec3 normal(1.f, 0, 0);
  919.                                 Vec3 pos = gAIEnv.pCoverSystem->GetCoverLocation(coverID, distanceToCover, 0, &normal);
  920.  
  921.                                 CreateHideTarget(pPipeUser, pos, -normal);
  922.  
  923.                                 if (gAIEnv.CVars.CoverExactPositioning)
  924.                                 {
  925.                                         SAIActorTargetRequest req;
  926.                                         req.approachLocation = pos + normal * 0.25f;
  927.                                         req.approachDirection = -normal;
  928.                                         req.animLocation = pos;
  929.                                         req.animDirection = -normal;
  930.  
  931.                                         req.directionTolerance = DEG2RAD(5.0f);
  932.                                         req.startArcAngle = 0.5f;
  933.                                         req.startWidth = 0.5f;
  934.                                         req.signalAnimation = false;
  935.  
  936.                                         pPipeUser->SetActorTargetRequest(req);
  937.                                 }
  938.  
  939. #ifdef CRYAISYSTEM_DEBUG
  940.                                 if (gAIEnv.CVars.DebugDrawCover)
  941.                                         GetAISystem()->AddDebugCylinder(pos + CoverUp * 0.015f, CoverUp, pPipeUser->GetParameters().m_fPassRadius, 0.025f, Col_Red, 3.5f);
  942. #endif
  943.                         }
  944.                         else if (pPipeUser->m_CurrentHideObject.IsValid())
  945.                         {
  946.                                 Vec3 pos = pPipeUser->m_CurrentHideObject.GetLastHidePos();
  947.  
  948.                                 CreateHideTarget(pPipeUser, pos);
  949.                         }
  950.                         else
  951.                         {
  952.                                 Reset(pPipeUser);
  953.  
  954.                                 return eGOR_FAILED;
  955.                         }
  956.                 }
  957.  
  958.                 pPipeUser->m_nPathDecision = PATHFINDER_STILLFINDING;
  959.         }
  960.  
  961.         if (!m_refHideTarget.IsNil())
  962.         {
  963.                 if (!m_pPathfinder)
  964.                 {
  965.                         if (gAIEnv.CVars.DebugPathFinding)
  966.                         {
  967.                                 const Vec3& vPos = m_refHideTarget->GetPos();
  968.                                 AILogAlways("COPCrysis2Hide::Execute %s pathfinding to (%5.2f, %5.2f, %5.2f)", pPipeUser->GetName(),
  969.                                             vPos.x, vPos.y, vPos.z);
  970.                         }
  971.  
  972.                         CAIObject* targetObject = 0;
  973.                         if (gAIEnv.CVars.CoverSystem && gAIEnv.CVars.CoverExactPositioning)
  974.                                 targetObject = pPipeUser->GetOrCreateSpecialAIObject(CPipeUser::AISPECIAL_ANIM_TARGET);
  975.                         else
  976.                                 targetObject = m_refHideTarget.GetAIObject();
  977.  
  978.                         m_pPathfinder = new COPPathFind("", targetObject);
  979.                 }
  980.  
  981.                 if (!m_pTracer && (m_pPathfinder->Execute(pPipeUser) != eGOR_IN_PROGRESS))
  982.                 {
  983.                         if (pPipeUser->m_nPathDecision == PATHFINDER_PATHFOUND)
  984.                         {
  985.                                 if (gAIEnv.CVars.DebugPathFinding)
  986.                                 {
  987.                                         const Vec3& vPos = m_refHideTarget->GetPos();
  988.                                         AILogAlways("COPCrysis2Hide::Execute %s Creating trace to hide target (%5.2f, %5.2f, %5.2f)", pPipeUser->GetName(),
  989.                                                     vPos.x, vPos.y, vPos.z);
  990.                                 }
  991.  
  992.                                 if (CoverID nextCoverID = pPipeUser->GetCoverRegister())
  993.                                 {
  994.                                         if (CoverID currCoverID = pPipeUser->GetCoverID())
  995.                                         {
  996.                                                 CCoverSystem& coverSystem = *gAIEnv.pCoverSystem;
  997.  
  998.                                                 bool movingInCover = false;
  999.  
  1000.                                                 if (coverSystem.GetSurfaceID(currCoverID) == coverSystem.GetSurfaceID(nextCoverID))
  1001.                                                 {
  1002.                                                         movingInCover = true;
  1003.                                                 }
  1004.                                                 else
  1005.                                                 {
  1006.                                                         // Check if surfaces are neighbors (edges are close to each other)
  1007.                                                         const CoverSurface& currSurface = coverSystem.GetCoverSurface(currCoverID);
  1008.                                                         const CoverSurface& nextSurface = coverSystem.GetCoverSurface(nextCoverID);
  1009.  
  1010.                                                         const float neighborDistSq = 0.3f * 0.3f;
  1011.  
  1012.                                                         ICoverSystem::SurfaceInfo currSurfaceInfo;
  1013.                                                         ICoverSystem::SurfaceInfo nextSurfaceInfo;
  1014.  
  1015.                                                         if (currSurface.GetSurfaceInfo(&currSurfaceInfo) && nextSurface.GetSurfaceInfo(&nextSurfaceInfo))
  1016.                                                         {
  1017.                                                                 const Vec3& currLeft = currSurfaceInfo.samples[0].position;
  1018.                                                                 const Vec3& currRight = currSurfaceInfo.samples[currSurfaceInfo.sampleCount - 1].position;
  1019.                                                                 const Vec3& nextLeft = nextSurfaceInfo.samples[0].position;
  1020.                                                                 const Vec3& nextRight = nextSurfaceInfo.samples[nextSurfaceInfo.sampleCount - 1].position;
  1021.  
  1022.                                                                 if (Distance::Point_Point2DSq(currLeft, nextRight) < neighborDistSq ||
  1023.                                                                     Distance::Point_Point2DSq(currRight, nextLeft) < neighborDistSq)
  1024.                                                                 {
  1025.                                                                         movingInCover = true;
  1026.                                                                 }
  1027.                                                         }
  1028.                                                 }
  1029.  
  1030.                                                 pPipeUser->SetMovingInCover(movingInCover);
  1031.                                                 pPipeUser->SetInCover(movingInCover);
  1032.                                         }
  1033.  
  1034.                                         pPipeUser->SetCoverRegister(CoverID());
  1035.                                         pPipeUser->SetCoverID(nextCoverID);
  1036.                                 }
  1037.  
  1038.                                 pPipeUser->SetMovingToCover(true);
  1039.  
  1040.                                 m_pTracer = new COPTrace(m_exact, 0.0f);
  1041.                         }
  1042.                         else
  1043.                         {
  1044.                                 CCCPOINT(COPCrysis2Hide_Execute_Unreachable);
  1045.  
  1046.                                 // Could not reach the point, mark it ignored so that we do not try to pick it again.
  1047.                                 if (CoverID coverID = pPipeUser->GetCoverRegister())
  1048.                                 {
  1049.                                         pPipeUser->SetMovingToCover(false);
  1050.                                         pPipeUser->SetMovingInCover(false);
  1051.  
  1052.                                         pPipeUser->SetCoverRegister(CoverID());
  1053.                                         pPipeUser->SetCoverBlacklisted(coverID, true, 10.0f);
  1054.                                 }
  1055.                                 else
  1056.                                         pPipeUser->IgnoreCurrentHideObject(10.0f);
  1057.  
  1058.                                 Reset(pPipeUser);
  1059.  
  1060.                                 return eGOR_FAILED;
  1061.                         }
  1062.                 }
  1063.  
  1064.                 if (m_pTracer)
  1065.                 {
  1066.                         EGoalOpResult result = m_pTracer->Execute(pPipeUser);
  1067.  
  1068.                         if (result == eGOR_SUCCEEDED)
  1069.                         {
  1070.                                 CCCPOINT(COPCrysis2Hide_Execute_A);
  1071.  
  1072.                                 Reset(pPipeUser);
  1073.  
  1074.                                 pPipeUser->SetMovingToCover(false);
  1075.                                 pPipeUser->SetMovingInCover(false);
  1076.  
  1077.                                 if (pPipeUser->GetCoverID())
  1078.                                 {
  1079.                                         pPipeUser->SetInCover(true);
  1080.                                         pPipeUser->SetSignal(1, "OnCoverReached", 0, 0, gAIEnv.SignalCRCs.m_nOnCoverReached);
  1081.                                 }
  1082.  
  1083.                                 return eGOR_SUCCEEDED;
  1084.                         }
  1085.                         else if (result == eGOR_IN_PROGRESS)
  1086.                         {
  1087.                                 CCCPOINT(COPCrysis2Hide_Execute_B);
  1088.  
  1089.                                 pPipeUser->SetMovingToCover(true);
  1090.                                 UpdateMovingToCoverAnimation(pPipeUser);
  1091.                         }
  1092.                         else
  1093.                         {
  1094.                                 Reset(pPipeUser);
  1095.  
  1096.                                 return eGOR_FAILED;
  1097.                         }
  1098.                 }
  1099.         }
  1100.  
  1101.         return eGOR_IN_PROGRESS;
  1102. }
  1103.  
  1104. void COPCrysis2Hide::ExecuteDry(CPipeUser* pPipeUser)
  1105. {
  1106.         CCCPOINT(COPCrysis2Hide_ExecuteDry);
  1107.  
  1108.         if (m_pTracer)
  1109.                 m_pTracer->ExecuteTrace(pPipeUser, false);
  1110. }
  1111.  
  1112. void COPCrysis2Hide::Reset(CPipeUser* pPipeUser)
  1113. {
  1114.         CCCPOINT(COPCrysis2Hide_Reset);
  1115.  
  1116.         SAFE_DELETE(m_pPathfinder);
  1117.         SAFE_DELETE(m_pTracer);
  1118.  
  1119.         if (pPipeUser)
  1120.         {
  1121.                 pPipeUser->SetMovingToCover(false);
  1122.                 pPipeUser->SetMovingInCover(false);
  1123.  
  1124.                 pPipeUser->ClearPath("COPCrysis2Hide::Reset");
  1125.  
  1126.                 pPipeUser->ClearMovementContext(1);
  1127.                 pPipeUser->ResetDesiredBodyDirectionAtTarget();
  1128.         }
  1129.  
  1130.         m_refHideTarget.Release();
  1131. }
  1132.  
  1133. void COPCrysis2Hide::Serialize(TSerialize ser)
  1134. {
  1135.         ser.BeginGroup("COPCrysis2Hide");
  1136.         {
  1137.                 m_refHideTarget.Serialize(ser, "m_refHideTarget");
  1138.  
  1139.                 ser.EnumValue("m_location", m_location, AI_REG_NONE, AI_REG_LAST);
  1140.                 ser.Value("m_exact", m_exact);
  1141.  
  1142.                 if (ser.IsWriting())
  1143.                 {
  1144.                         if (ser.BeginOptionalGroup("Tracer", m_pTracer != NULL))
  1145.                         {
  1146.                                 PREFAST_SUPPRESS_WARNING(6011) m_pTracer->Serialize(ser);
  1147.                                 ser.EndGroup();
  1148.                         }
  1149.                         if (ser.BeginOptionalGroup("Pathfinder", m_pPathfinder != NULL))
  1150.                         {
  1151.                                 PREFAST_SUPPRESS_WARNING(6011) m_pPathfinder->Serialize(ser);
  1152.                                 ser.EndGroup();
  1153.                         }
  1154.                 }
  1155.                 else
  1156.                 {
  1157.                         SAFE_DELETE(m_pTracer);
  1158.  
  1159.                         if (ser.BeginOptionalGroup("Tracer", true))
  1160.                         {
  1161.                                 m_pTracer = new COPTrace(m_exact);
  1162.                                 m_pTracer->Serialize(ser);
  1163.                                 ser.EndGroup();
  1164.                         }
  1165.  
  1166.                         SAFE_DELETE(m_pPathfinder);
  1167.  
  1168.                         if (ser.BeginOptionalGroup("Pathfinder", true))
  1169.                         {
  1170.                                 m_pPathfinder = new COPPathFind("");
  1171.                                 m_pPathfinder->Serialize(ser);
  1172.                                 ser.EndGroup();
  1173.                         }
  1174.                 }
  1175.  
  1176.                 ser.EndGroup();
  1177.         }
  1178. }
  1179.  
  1180. void COPCrysis2Hide::CreateHideTarget(CPipeUser* pPipeUser, const Vec3& pos, const Vec3& dir)
  1181. {
  1182.         CCCPOINT(COPCrysis2Hide_CreateHideTarget);
  1183.  
  1184.         assert(m_refHideTarget.IsNil() || !m_refHideTarget.GetAIObject());
  1185.  
  1186.         if (m_refHideTarget.IsNil() || !m_refHideTarget.GetAIObject())
  1187.                 gAIEnv.pAIObjectManager->CreateDummyObject(m_refHideTarget);
  1188.  
  1189.         IAIObject* hideTarget = m_refHideTarget.GetAIObject();
  1190.         assert(hideTarget);
  1191.  
  1192.         if (const NavigationAgentTypeID agentTypeID = pPipeUser->GetNavigationTypeID())
  1193.         {
  1194.                 if (const NavigationMeshID meshID = gAIEnv.pNavigationSystem->GetEnclosingMeshID(agentTypeID, pos))
  1195.                 {
  1196.                         Vec3 fixedLoc;
  1197.  
  1198.                         const float radius = pPipeUser->GetPathAgentPassRadius(); // TODO: fix - this should use agent type settings from new navigation system
  1199.                         if (gAIEnv.pNavigationSystem->GetClosestMeshLocation(meshID, pos, 2.0f, radius + 0.25f, &fixedLoc, 0))
  1200.                         {
  1201.                                 hideTarget->SetPos(fixedLoc);
  1202.                                 hideTarget->SetEntityDir(dir);
  1203.  
  1204.                                 return;
  1205.                         }
  1206.                 }
  1207.         }
  1208.  
  1209.         hideTarget->SetPos(pos);
  1210.         hideTarget->SetEntityDir(dir);
  1211. }
  1212.  
  1213. void COPCrysis2Hide::DebugDraw(CPipeUser* pPipeUser) const
  1214. {
  1215.         if (!m_refHideTarget.IsNil())
  1216.         {
  1217.                 CDebugDrawContext dc;
  1218.  
  1219.                 dc->DrawCylinder(m_refHideTarget.GetAIObject()->GetPos() + Vec3Constants<float>::fVec3_OneZ * 0.15f * 0.5f,
  1220.                                  Vec3Constants<float>::fVec3_OneZ, pPipeUser->GetParameters().m_fPassRadius, 0.15f, Col_DarkGreen);
  1221.         }
  1222. }
  1223.  
  1224. void COPCrysis2Hide::UpdateMovingToCoverAnimation(CPipeUser* pPipeUser) const
  1225. {
  1226.         // Give hints to animation system for sliding into cover
  1227.         if (pPipeUser->IsMovingToCover() && !pPipeUser->IsInCover()) // GoalOpHide is used both when moving into cover and *in* cover..
  1228.         {
  1229.                 Vec3 hidePos, hideNormal;
  1230.                 float hideHeight;
  1231.                 if (CoverID coverID = pPipeUser->GetCoverID())
  1232.                 {
  1233.                         float radius = pPipeUser->GetParameters().distanceToCover;
  1234.                         hidePos = gAIEnv.pCoverSystem->GetCoverLocation(coverID, radius, &hideHeight, &hideNormal);
  1235.                         //hidePos = gAIEnv.pCoverSystem->GetCoverSurface(coverID)->GetCoverOcclusionAt(radius, &hideHeight, &hideNormal);
  1236.                         hideHeight = pPipeUser->GetCoverLocationEffectiveHeight();
  1237.                 }
  1238.                 else
  1239.                 {
  1240.                         hidePos = pPipeUser->m_CurrentHideObject.GetLastHidePos();
  1241.                         hideNormal = -pPipeUser->m_CurrentHideObject.GetObjectDir();
  1242.                         hideHeight = pPipeUser->m_CurrentHideObject.HasLowCover() ? 0 : HighCoverMaxHeight; // old system: assume low cover when low cover is available, otherwise assume high cover
  1243.                 }
  1244.  
  1245.                 if (hideHeight < LowCoverMaxHeight) // only slides into low cover are supported
  1246.                 {
  1247.                         pPipeUser->SetDesiredBodyDirectionAtTarget(-hideNormal);
  1248.  
  1249.                         SOBJECTSTATE& state = pPipeUser->GetState();
  1250.                         state.coverRequest.SetCoverLocation(hidePos, -hideNormal);
  1251.  
  1252.                         // when coming from the left, turn body to left (and vice versa)
  1253.                         COPCrysis2Utils::TurnBodyToTargetInCover(pPipeUser, hidePos, hideNormal, pPipeUser->GetPhysicsPos());
  1254.  
  1255.                         pPipeUser->SetMovementContext(1); // 1 ~ "moving into low cover"
  1256.                 }
  1257.         }
  1258. }
  1259.  
  1260. COPCrysis2Communicate::COPCrysis2Communicate(
  1261.   CommID commID, CommChannelID channelID, float expirity, EAIRegister target,
  1262.   SCommunicationRequest::EOrdering ordering)
  1263.         : m_commID(commID)
  1264.         , m_channelID(channelID)
  1265.         , m_ordering(ordering)
  1266.         , m_expirity(expirity)
  1267.         , m_target(target)
  1268. {
  1269. }
  1270.  
  1271. COPCrysis2Communicate::COPCrysis2Communicate(const XmlNodeRef& node) :
  1272.         m_expirity(0.f),
  1273.         m_target(AI_REG_NONE)
  1274. {
  1275.         const char* szName = s_xml.GetMandatoryString(node, "name");
  1276.         CCommunicationManager* pCommunicationManager = gAIEnv.pCommunicationManager;
  1277.         m_commID = pCommunicationManager->GetCommunicationID(szName);
  1278.         m_channelID = pCommunicationManager->GetChannelID(szName);
  1279.  
  1280.         m_ordering = s_xml.GetBool(node, "ordered") ? SCommunicationRequest::Ordered : SCommunicationRequest::Unordered;
  1281.         s_xml.GetMandatory(node, "expiry", m_expirity);
  1282.         s_xml.GetRegister(node, "register", m_target);
  1283. }
  1284.  
  1285. COPCrysis2Communicate::~COPCrysis2Communicate()
  1286. {
  1287. }
  1288.  
  1289. EGoalOpResult COPCrysis2Communicate::Execute(CPipeUser* pPipeUser)
  1290. {
  1291.         SCommunicationRequest request;
  1292.         request.actorID = pPipeUser->GetEntityID();
  1293.         request.commID = m_commID;
  1294.         request.channelID = m_channelID;
  1295.         request.configID = gAIEnv.pCommunicationManager->GetConfigID(pPipeUser->GetProxy()->GetCommunicationConfigName());
  1296.         request.contextExpiry = m_expirity;
  1297.         request.ordering = m_ordering;
  1298.  
  1299.         IAIObject* target = 0;
  1300.  
  1301.         switch (m_target)
  1302.         {
  1303.         case AI_REG_LASTOP:
  1304.                 target = pPipeUser->GetLastOpResult();
  1305.                 break;
  1306.         case AI_REG_ATTENTIONTARGET:
  1307.                 target = pPipeUser->GetAttentionTarget();
  1308.                 break;
  1309.         case AI_REG_REFPOINT:
  1310.                 target = pPipeUser->GetRefPoint();
  1311.                 break;
  1312.         case AI_REG_COVER:
  1313.                 if (CoverID coverID = pPipeUser->GetCoverRegister())
  1314.                         request.target = gAIEnv.pCoverSystem->GetCoverLocation(coverID);
  1315.                 else
  1316.                         request.target = pPipeUser->m_CurrentHideObject.GetObjectPos();
  1317.                 break;
  1318.         default:
  1319.                 break;
  1320.         }
  1321.  
  1322.         if (target)
  1323.         {
  1324.                 request.targetID = target->GetEntityID();
  1325.                 if (!request.targetID)
  1326.                         request.target = target->GetPos();
  1327.         }
  1328.  
  1329.         gAIEnv.pCommunicationManager->PlayCommunication(request);
  1330.  
  1331.         return eGOR_DONE;
  1332. }
  1333.  
  1334. //////////////////////////////////////////////////////////////////////////
  1335. COPCrysis2StickPath::COPCrysis2StickPath(bool bFinishInRange, float fMaxStickDist, float fMinStickDist, bool bCanReverse)
  1336.         : m_State(eState_FIRST)
  1337.         , m_fPathLength(0.0f)
  1338.         , m_fMinStickDistSq(sqr(fMinStickDist))
  1339.         , m_fMaxStickDistSq(sqr(fMaxStickDist))
  1340.         , m_bFinishInRange(bFinishInRange)
  1341.         , m_bCanReverse(bCanReverse)
  1342. {
  1343.  
  1344. }
  1345.  
  1346. //////////////////////////////////////////////////////////////////////////
  1347. COPCrysis2StickPath::COPCrysis2StickPath(const XmlNodeRef& node)
  1348.         : m_State(eState_FIRST)
  1349.         , m_fPathLength(0.0f)
  1350.         , m_fMinStickDistSq(0.0f)
  1351.         , m_fMaxStickDistSq(0.0f)
  1352.         , m_bFinishInRange(false)
  1353.         , m_bCanReverse(s_xml.GetBool(node, "canReverse", true))
  1354. {
  1355.         float fMaxStickDist = 0.0f;
  1356.         s_xml.GetMandatory(node, "maxStickDist", fMaxStickDist);
  1357.         m_fMaxStickDistSq = sqr(fMaxStickDist);
  1358.  
  1359.         float fMinStickDist = s_xml.Get(node, "minStickDist", 0.0f);
  1360.         m_fMinStickDistSq = sqr(fMinStickDist);
  1361.  
  1362.         m_bFinishInRange = s_xml.GetMandatoryBool(node, "finishInRange");
  1363. }
  1364.  
  1365. //////////////////////////////////////////////////////////////////////////
  1366. COPCrysis2StickPath::COPCrysis2StickPath(const COPCrysis2StickPath& rhs)
  1367.         : m_State(rhs.m_State)
  1368.         , m_fPathLength(rhs.m_fPathLength)
  1369.         , m_fMinStickDistSq(rhs.m_fMinStickDistSq)
  1370.         , m_fMaxStickDistSq(rhs.m_fMaxStickDistSq)
  1371.         , m_bFinishInRange(rhs.m_bFinishInRange)
  1372.         , m_bCanReverse(rhs.m_bCanReverse)
  1373. {
  1374.  
  1375. }
  1376.  
  1377. //////////////////////////////////////////////////////////////////////////
  1378. COPCrysis2StickPath::~COPCrysis2StickPath()
  1379. {
  1380.         m_refNavTarget.Release();
  1381. }
  1382.  
  1383. //////////////////////////////////////////////////////////////////////////
  1384. void COPCrysis2StickPath::Reset(CPipeUser* pPipeUser)
  1385. {
  1386.         // Note: pPipeUser can be NULL!
  1387.  
  1388.         if (pPipeUser)
  1389.         {
  1390.                 SAIEVENT aiEvent;
  1391.                 aiEvent.vForcedNavigation.zero();
  1392.                 pPipeUser->Event(AIEVENT_FORCEDNAVIGATION, &aiEvent);
  1393.         }
  1394.  
  1395.         m_State = eState_FIRST;
  1396.  
  1397.         m_refTarget.Reset();
  1398.         m_refNavTarget.Release();
  1399.  
  1400.         m_fPathLength = 0.0f;
  1401. }
  1402.  
  1403. //////////////////////////////////////////////////////////////////////////
  1404. void COPCrysis2StickPath::Serialize(TSerialize ser)
  1405. {
  1406.         ser.BeginGroup("COPCrysis2StickPath");
  1407.         {
  1408.                 ser.Value("m_fMinStickDistSq", m_fMinStickDistSq);
  1409.                 ser.Value("m_fMaxStickDistSq", m_fMaxStickDistSq);
  1410.                 ser.Value("m_bFinishInRange", m_bFinishInRange);
  1411.                 ser.Value("m_bCanReverse", m_bCanReverse);
  1412.  
  1413.                 m_refNavTarget.Serialize(ser, "m_refNavTarget");
  1414.         }
  1415.         ser.EndGroup();
  1416.  
  1417.         if (ser.IsReading())
  1418.         {
  1419.                 Reset(0);
  1420.         }
  1421. }
  1422.  
  1423. //////////////////////////////////////////////////////////////////////////
  1424. void COPCrysis2StickPath::ProjectTargetOntoPath(Vec3& outPos, float& outNearestDistance, float& outDistanceAlongPath) const
  1425. {
  1426.         assert(m_refTarget.IsValid());
  1427.  
  1428.         const Vec3 vTargetPos = m_refTarget.GetAIObject()->GetPos();
  1429.         m_Path.NearestPointOnPath(vTargetPos, false, outNearestDistance, outPos, &outDistanceAlongPath);
  1430. }
  1431.  
  1432. //////////////////////////////////////////////////////////////////////////
  1433. COPCrysis2StickPath::ETargetRange COPCrysis2StickPath::GetTargetRange(const Vec3& vMyPos) const
  1434. {
  1435.         assert(m_refTarget.IsValid());
  1436.  
  1437.         ETargetRange result = eTR_TooFar;
  1438.  
  1439.         Vec3 vNearestTargetPoint(ZERO);
  1440.         float fNearestTargetDist = 0.0f;
  1441.         float fTargetDistAlongPath = 0.0f;
  1442.         ProjectTargetOntoPath(vNearestTargetPoint, fNearestTargetDist, fTargetDistAlongPath);
  1443.  
  1444.         const float fDistSq = vMyPos.GetSquaredDistance(vNearestTargetPoint);
  1445.         if (fDistSq < m_fMaxStickDistSq)
  1446.         {
  1447.                 result = (fDistSq > m_fMinStickDistSq ? eTR_InRange : eTR_TooClose);
  1448.         }
  1449.  
  1450.         return result;
  1451. }
  1452.  
  1453. //////////////////////////////////////////////////////////////////////////
  1454. COPCrysis2StickPath::ETargetRange COPCrysis2StickPath::GetTargetRange(const Vec3& vMyPos, const Vec3& vTargetPos) const
  1455. {
  1456.         ETargetRange result = eTR_TooFar;
  1457.  
  1458.         const float fDistSq = vMyPos.GetSquaredDistance(vTargetPos);
  1459.         if (fDistSq < m_fMaxStickDistSq)
  1460.         {
  1461.                 result = (fDistSq > m_fMinStickDistSq ? eTR_InRange : eTR_TooClose);
  1462.         }
  1463.  
  1464.         return result;
  1465. }
  1466.  
  1467. //////////////////////////////////////////////////////////////////////////
  1468. Vec3 COPCrysis2StickPath::GetProjectedPos(CPuppet* pPuppet) const
  1469. {
  1470.         assert(pPuppet);
  1471.  
  1472.         return pPuppet->GetPos() + pPuppet->GetMoveDir() * pPuppet->GetState().fDesiredSpeed;
  1473. }
  1474.  
  1475. //////////////////////////////////////////////////////////////////////////
  1476. EGoalOpResult COPCrysis2StickPath::Execute(CPipeUser* pPipeUser)
  1477. {
  1478.         FUNCTION_PROFILER(GetISystem(), PROFILE_AI);
  1479.  
  1480.         return ExecuteCurrentState(pPipeUser, false);
  1481. }
  1482.  
  1483. //////////////////////////////////////////////////////////////////////////
  1484. void COPCrysis2StickPath::ExecuteDry(CPipeUser* pPipeUser)
  1485. {
  1486.         FUNCTION_PROFILER(GetISystem(), PROFILE_AI);
  1487.  
  1488.         ExecuteCurrentState(pPipeUser, true);
  1489. }
  1490.  
  1491. //////////////////////////////////////////////////////////////////////////
  1492. EGoalOpResult COPCrysis2StickPath::ExecuteCurrentState(CPipeUser* pPipeUser, bool bDryUpdate)
  1493. {
  1494.         FUNCTION_PROFILER(GetISystem(), PROFILE_AI);
  1495.  
  1496.         EGoalOpResult eGoalOpResult = eGOR_FAILED;
  1497.  
  1498.         CPuppet* pPuppet = CastToCPuppetSafe(pPipeUser);
  1499.         if (pPuppet)
  1500.         {
  1501.                 switch (m_State)
  1502.                 {
  1503.                 case eState_Prepare:
  1504.                         {
  1505.                                 eGoalOpResult = ExecuteState_Prepare(pPuppet, bDryUpdate) ? eGOR_IN_PROGRESS : eGOR_FAILED;
  1506.                         }
  1507.                         break;
  1508.  
  1509.                 case eState_Navigate:
  1510.                         {
  1511.                                 eGoalOpResult = ExecuteState_Navigate(pPuppet, bDryUpdate) ? eGOR_IN_PROGRESS : eGOR_FAILED;
  1512.                         }
  1513.                         break;
  1514.  
  1515.                 case eState_Wait:
  1516.                         {
  1517.                                 if (m_bFinishInRange)
  1518.                                         eGoalOpResult = eGOR_SUCCEEDED;
  1519.                                 else
  1520.                                         eGoalOpResult = ExecuteState_Wait(pPuppet, bDryUpdate) ? eGOR_IN_PROGRESS : eGOR_FAILED;
  1521.                         }
  1522.                         break;
  1523.  
  1524.                 default:
  1525.                         CRY_ASSERT_MESSAGE(false, "COPCrysis2StickPath::Execute Unhandled state");
  1526.                         break;
  1527.                 }
  1528.         }
  1529.  
  1530.         if (eGoalOpResult == eGOR_FAILED)
  1531.                 Reset(pPipeUser);
  1532.  
  1533.         return eGoalOpResult;
  1534. }
  1535.  
  1536. //////////////////////////////////////////////////////////////////////////
  1537. bool COPCrysis2StickPath::ExecuteState_Prepare(CPuppet* pPuppet, bool bDryUpdate)
  1538. {
  1539.         FUNCTION_PROFILER(GetISystem(), PROFILE_AI);
  1540.  
  1541.         assert(pPuppet);
  1542.  
  1543.         if (!bDryUpdate)
  1544.         {
  1545.                 const char* szPathName = pPuppet->GetPathToFollow();
  1546.                 if (!gAIEnv.pNavigation->GetDesignerPath(szPathName, m_Path))
  1547.                 {
  1548.                         pPuppet->SetSignal(0, "OnNoPathFound", 0, 0, gAIEnv.SignalCRCs.m_nOnNoPathFound);
  1549.                         return false;
  1550.                 }
  1551.  
  1552.                 Vec3 vPathEndPos(pPuppet->GetPos());
  1553.                 m_fPathLength = 0.0f;
  1554.                 ListPositions::const_iterator itPathCurrent(m_Path.shape.begin());
  1555.                 ListPositions::const_iterator itPathEnd(m_Path.shape.end());
  1556.                 ListPositions::const_iterator itPathNext(itPathCurrent);
  1557.                 ++itPathNext;
  1558.                 while (itPathNext != itPathEnd)
  1559.                 {
  1560.                         Lineseg seg(*itPathCurrent, *itPathNext);
  1561.                         m_fPathLength += Distance::Point_Point(seg.start, seg.end);
  1562.                         vPathEndPos = seg.end;
  1563.                         itPathCurrent = itPathNext;
  1564.                         ++itPathNext;
  1565.                 }
  1566.  
  1567.                 // Get desired target to stick towards
  1568.                 IEntity* pTargetEntity = gEnv->pEntitySystem->GetEntity(pPuppet->GetVehicleStickTarget());
  1569.                 CAIObject* pTarget = pTargetEntity ? static_cast<CAIObject*>(pTargetEntity->GetAI()) : NULL;
  1570.                 if (pTarget)
  1571.                 {
  1572.                         m_refTarget = gAIEnv.pObjectContainer->GetWeakRef(pTarget);
  1573.                 }
  1574.                 else if (m_refNavTarget.IsNil())
  1575.                 {
  1576.                         // Obtain a NavTarget
  1577.                         stack_string name("navTarget_");
  1578.                         name += GetNameSafe(pPuppet);
  1579.  
  1580.                         gAIEnv.pAIObjectManager->CreateDummyObject(m_refNavTarget, name, CAIObject::STP_REFPOINT);
  1581.                         m_refNavTarget.GetAIObject()->SetPos(vPathEndPos);
  1582.  
  1583.                         m_refTarget = m_refNavTarget.GetWeakRef();
  1584.  
  1585.                         // Follow path to end means we always finish when in range.
  1586.                         // (Since we have no target to stick to, there's nothing else for us to do once we get to the end)
  1587.                         m_bFinishInRange = true;
  1588.                 }
  1589.                 else
  1590.                 {
  1591.                         return false;
  1592.                 }
  1593.  
  1594.                 assert(m_refTarget.IsValid());
  1595.  
  1596.                 m_fMinStickDistSq = min(m_fMinStickDistSq, m_fMaxStickDistSq);
  1597.  
  1598.                 // Set to correct state based on current target distance
  1599.                 if (eTR_InRange == GetTargetRange(pPuppet->GetPos()))
  1600.                         m_State = eState_Wait;
  1601.                 else
  1602.                         m_State = eState_Navigate;
  1603.         }
  1604.  
  1605.         return true;
  1606. }
  1607.  
  1608. //////////////////////////////////////////////////////////////////////////
  1609. bool COPCrysis2StickPath::ExecuteState_Navigate(CPuppet* pPuppet, bool bDryUpdate)
  1610. {
  1611.         FUNCTION_PROFILER(GetISystem(), PROFILE_AI);
  1612.  
  1613.         assert(pPuppet);
  1614.         assert(m_refTarget.IsValid());
  1615.  
  1616.         Vec3 vNearestTargetPoint(ZERO);
  1617.         float fNearestTargetDist = 0.0f;
  1618.         float fTargetDistAlongPath = 0.0f;
  1619.         ProjectTargetOntoPath(vNearestTargetPoint, fNearestTargetDist, fTargetDistAlongPath);
  1620.  
  1621.         // Check if close enough to target yet
  1622.         ETargetRange targetRange = GetTargetRange(pPuppet->GetPos(), vNearestTargetPoint);
  1623.         if (eTR_InRange == targetRange || (eTR_TooClose == targetRange && !m_bCanReverse))
  1624.         {
  1625.                 m_State = eState_Wait;
  1626.                 return true;
  1627.         }
  1628.  
  1629.         if (!bDryUpdate)
  1630.         {
  1631.                 CAIObject* pTarget = m_refTarget.GetAIObject();
  1632.                 assert(pTarget);
  1633.  
  1634.                 const Vec3 vMyPos = pPuppet->GetPos();
  1635.  
  1636.                 Vec3 vNearestMyPoint(ZERO);
  1637.                 float fNearestMyDist = 0.0f;
  1638.                 float fMyDistAlongPath = 0.0f;
  1639.                 m_Path.NearestPointOnPath(vMyPos, false, fNearestMyDist, vNearestMyPoint, &fMyDistAlongPath);
  1640.  
  1641.                 // Determine movement direction to get to the target as quickly as possible along the path
  1642.                 bool bMoveForward = true;
  1643.                 if (m_bCanReverse)
  1644.                 {
  1645.                         if (m_Path.closed)
  1646.                         {
  1647.                                 // Move forward if the absolute distance between my projection and the target's projection is less than
  1648.                                 // half of the path's total length, keeping in mind the path loop connection
  1649.                                 const float fDistBetween = fTargetDistAlongPath - fMyDistAlongPath;
  1650.                                 bMoveForward = (fDistBetween >= 0.0f ? fDistBetween<m_fPathLength*0.5f : -fDistBetween> m_fPathLength * 0.5f);
  1651.                         }
  1652.                         else
  1653.                         {
  1654.                                 // Move forward as long as the target's projection is further along the path than my own
  1655.                                 bMoveForward = (fTargetDistAlongPath >= fMyDistAlongPath);
  1656.                         }
  1657.  
  1658.                         // Go in opposite direction determined if too close
  1659.                         if (eTR_TooClose == targetRange)
  1660.                         {
  1661.                                 bMoveForward = !bMoveForward;
  1662.                         }
  1663.                 }
  1664.  
  1665.                 // On non-closed paths, just don't move anymore if we have to reverse and we can't
  1666.                 bool bCanMove = true;
  1667.                 if (!m_Path.closed && !m_bCanReverse && fTargetDistAlongPath < fMyDistAlongPath && eTR_TooFar == targetRange)
  1668.                 {
  1669.                         bCanMove = false;
  1670.                 }
  1671.  
  1672.                 if (bCanMove)
  1673.                 {
  1674.                         const float fDesiredSpeed = pPuppet->GetState().fDesiredSpeed;
  1675.                         const float fSpeed = (bMoveForward ? fDesiredSpeed : -fDesiredSpeed);
  1676.  
  1677.                         // Get the nearest path point to use from my position towards target
  1678.                         // Where I will be in one second if nothing goes wrong
  1679.                         bool bBeyondPathLength = false;
  1680.                         float fClosestPointDist = fMyDistAlongPath + fSpeed;
  1681.                         if (fClosestPointDist >= m_fPathLength)
  1682.                         {
  1683.                                 fClosestPointDist -= m_fPathLength;
  1684.                                 bBeyondPathLength = true;
  1685.                         }
  1686.                         else if (fClosestPointDist < 0.0f)
  1687.                         {
  1688.                                 fClosestPointDist += m_fPathLength;
  1689.                         }
  1690.  
  1691.                         const Vec3 vClosestPathPoint = m_Path.GetPointAlongPath(fClosestPointDist);
  1692.                         const Vec3 vDirection = (vClosestPathPoint - vMyPos).GetNormalizedSafe(pPuppet->GetMoveDir()) * fSpeed;
  1693.  
  1694.                         pPuppet->SetForcedNavigation(vDirection, fSpeed);
  1695.  
  1696.                         // Special case: If navigating to end of path, switch to waiting once we project beyond the path length
  1697.                         if (bBeyondPathLength && m_refNavTarget.IsSet())
  1698.                         {
  1699.                                 m_State = eState_Wait;
  1700.                         }
  1701.                 }
  1702.                 else
  1703.                 {
  1704.                         pPuppet->ClearForcedNavigation();
  1705.                 }
  1706.         }
  1707.  
  1708.         return true;
  1709. }
  1710.  
  1711. //////////////////////////////////////////////////////////////////////////
  1712. bool COPCrysis2StickPath::ExecuteState_Wait(CPuppet* pPuppet, bool bDryUpdate)
  1713. {
  1714.         FUNCTION_PROFILER(GetISystem(), PROFILE_AI);
  1715.  
  1716.         assert(pPuppet);
  1717.         assert(m_refTarget.IsValid());
  1718.  
  1719.         if (!bDryUpdate)
  1720.         {
  1721.                 pPuppet->ClearForcedNavigation();
  1722.  
  1723.                 // Navigate again if target moves too far away
  1724.                 ETargetRange targetRange = GetTargetRange(pPuppet->GetPos());
  1725.                 if (eTR_TooFar == targetRange || (eTR_TooClose == targetRange && m_bCanReverse))
  1726.                 {
  1727.                         m_State = eState_Navigate;
  1728.                 }
  1729.         }
  1730.  
  1731.         return true;
  1732. }
  1733.  
  1734. COPAcquirePosition::COPAcquirePosition() : m_target(AI_REG_NONE), m_Graph(0), m_State(C2AP_INIT), m_SubState(C2APCS_GATHERSPANS)
  1735. {
  1736.  
  1737. }
  1738.  
  1739. COPAcquirePosition::COPAcquirePosition(const XmlNodeRef& node) : m_target(AI_REG_NONE), m_Graph(0), m_State(C2AP_INIT), m_SubState(C2APCS_GATHERSPANS)
  1740. {
  1741.         s_xml.GetRegister(node, "register", m_target);
  1742.         s_xml.GetRegister(node, "output", m_output);
  1743. }
  1744.  
  1745. COPAcquirePosition::~COPAcquirePosition()
  1746. {
  1747.  
  1748. }
  1749.  
  1750. void COPAcquirePosition::Reset(CPipeUser* pPipeUser)
  1751. {
  1752.         m_State = C2AP_INIT;
  1753.         m_SubState = C2APCS_GATHERSPANS;
  1754.         m_target = AI_REG_NONE;
  1755.         m_output = AI_REG_NONE;
  1756.         m_Graph = 0;
  1757. }
  1758.  
  1759. bool COPAcquirePosition::GetTarget(CPipeUser* pPipeUser, Vec3& target)
  1760. {
  1761.         bool ret = false;
  1762.  
  1763.         switch (m_target)
  1764.         {
  1765.         case AI_REG_REFPOINT:
  1766.                 {
  1767.                         CAIObject* refPoint = pPipeUser->GetRefPoint();
  1768.                         if (refPoint)
  1769.                         {
  1770.                                 target = refPoint->GetPos();
  1771.                                 ret = true;
  1772.                         }
  1773.                 }
  1774.                 break;
  1775.  
  1776.         case AI_REG_ATTENTIONTARGET:
  1777.                 {
  1778.                         IAIObject* refTarget = pPipeUser->GetAttentionTarget();
  1779.                         if (refTarget)
  1780.                         {
  1781.                                 target = refTarget->GetPos();
  1782.                                 ret = true;
  1783.                         }
  1784.                 }
  1785.         }
  1786.  
  1787.         return ret;
  1788. }
  1789.  
  1790. bool COPAcquirePosition::SetOutput(CPipeUser* pPipeUser, Vec3& target)
  1791. {
  1792.         bool ret = true;
  1793.  
  1794.         switch (m_output)
  1795.         {
  1796.         case AI_REG_REFPOINT:
  1797.                 {
  1798.                         pPipeUser->SetRefPointPos(target);
  1799.                 }
  1800.                 break;
  1801.         }
  1802.  
  1803.         return ret;
  1804. }
  1805.  
  1806. struct MINUS1
  1807. {
  1808.         bool operator==(const Vec3i& value)
  1809.         {
  1810.                 return value.z == -1;
  1811.         }
  1812.  
  1813.         bool operator!=(const Vec3i& value)
  1814.         {
  1815.                 return value.z != -1;
  1816.         }
  1817. };
  1818.  
  1819. bool operator==(const Vec3i& vec, const MINUS1& mone)
  1820. {
  1821.         return vec.z == -1;
  1822. }
  1823.  
  1824. bool operator!=(const Vec3i& vec, const MINUS1& mone)
  1825. {
  1826.         return vec.z != -1;
  1827. }
  1828.  
  1829. EGoalOpResult COPAcquirePosition::Execute(CPipeUser* pPipeUser)
  1830. {
  1831.         EGoalOpResult ret = eGOR_FAILED;
  1832.  
  1833.         if (pPipeUser)
  1834.         {
  1835.                 switch (m_State)
  1836.                 {
  1837.                 case C2AP_INIT:
  1838.                         if (GetTarget(pPipeUser, m_destination))
  1839.                         {
  1840.                                 m_curPosition = pPipeUser->GetPos();
  1841.                                 ret = eGOR_FAILED;
  1842.                         }
  1843.                         break;
  1844.                 case C2AP_COMPUTING:
  1845.                         {
  1846.                                 switch (m_SubState)
  1847.                                 {
  1848.                                 case C2APCS_GATHERSPANS:
  1849.                                         {
  1850.                                                 m_Coords.clear();
  1851.                                                 m_Graph->GetSpansAlongLine(m_curPosition, m_destination, m_Coords);
  1852.                                                 m_SubState = C2APCS_CHECKSPANS;
  1853.                                                 ret = eGOR_IN_PROGRESS;
  1854.                                         }
  1855.                                         break;
  1856.                                 case C2APCS_CHECKSPANS:
  1857.                                         {
  1858.                                                 std::vector<Vec3i>::iterator end = m_Coords.end();
  1859.                                                 for (std::vector<Vec3i>::iterator it = m_Coords.begin(); it != end; ++it)
  1860.                                                 {
  1861.                                                         uint32 x = it->x;
  1862.                                                         uint32 y = it->y;
  1863.                                                         it->z = -1;
  1864.  
  1865.                                                         const CFlightNavRegion2::NavData::Span* span = &m_Graph->GetColumn(x, y);
  1866.                                                         if (m_Graph->IsSpanValid(span))
  1867.                                                         {
  1868.                                                                 Vec3 center;
  1869.                                                                 m_Graph->GetHorCenter(x, y, center);
  1870.                                                                 Vec3 diff = center - m_destination;
  1871.                                                                 diff.z = 0.0f;
  1872.  
  1873.                                                                 float dist = diff.GetLength();
  1874.                                                                 float diffZ = 0.25f;
  1875.  
  1876.                                                                 int32 z = 0;
  1877.                                                                 while (span)
  1878.                                                                 {
  1879.                                                                         float minh = span->heightMin + m_Graph->basePos.z;
  1880.                                                                         float maxh = span->heightMax + m_Graph->basePos.z;
  1881.  
  1882.                                                                         if (minh > m_destination.z + dist * -diffZ || maxh < m_destination.z + dist * diffZ)
  1883.                                                                         {
  1884.                                                                                 it->z = z;
  1885.                                                                                 break;
  1886.                                                                         }
  1887.  
  1888.                                                                         ++z;
  1889.                                                                         span = span->next;
  1890.                                                                 }
  1891.                                                         }
  1892.                                                 }
  1893.  
  1894.                                                 m_Coords.erase(std::remove(m_Coords.begin(), m_Coords.end(), MINUS1()), m_Coords.end());
  1895.  
  1896.                                                 if (!m_Coords.empty())
  1897.                                                 {
  1898.                                                         m_SubState = C2APCS_VISTESTS;
  1899.                                                         ret = eGOR_IN_PROGRESS;
  1900.                                                 }
  1901.                                                 else
  1902.                                                 {
  1903.                                                         return eGOR_FAILED;
  1904.                                                 }
  1905.                                         }
  1906.                                         break;
  1907.                                 case C2APCS_VISTESTS:
  1908.                                         {
  1909.                                                 uint32 count = 0;
  1910.                                                 std::vector<Vec3i>::iterator end = m_Coords.end();
  1911.                                                 for (std::vector<Vec3i>::iterator it = m_Coords.begin(); it != end; ++it)
  1912.                                                 {
  1913.                                                         const CFlightNavRegion2::NavData::Span* span = m_Graph->GetSpan(it->x, it->y, it->z);
  1914.  
  1915.                                                         Vec3 center;
  1916.                                                         m_Graph->GetHorCenter(it->x, it->y, center);
  1917.  
  1918.                                                         Vec3 diff = center - m_destination;
  1919.                                                         float dist = diff.GetLength2D();
  1920.  
  1921.                                                         float height = m_destination.z + dist * 0.25f;
  1922.  
  1923.                                                         center.z = max(m_Graph->basePos.z + span->heightMin, min(height, m_Graph->basePos.z + span->heightMax)); //m_Graph->basePos.z + (span->heightMin + span->heightMax) * 0.5f;
  1924.                                                         SetOutput(pPipeUser, center);
  1925.  
  1926.                                                         if (count > 0)
  1927.                                                         {
  1928.                                                                 break;
  1929.                                                         }
  1930.  
  1931.                                                         ++count;
  1932.                                                 }
  1933.                                                 m_State = C2AP_FAILED;
  1934.                                                 ret = eGOR_IN_PROGRESS;
  1935.                                         }
  1936.                                         break;
  1937.  
  1938.                                 }
  1939.                         }
  1940.                         break;
  1941.  
  1942.                 case C2AP_FAILED:
  1943.                         ret = eGOR_FAILED;
  1944.                         break;
  1945.                 }
  1946.         }
  1947.  
  1948.         return ret;
  1949. }
  1950.  
  1951. void COPAcquirePosition::ExecuteDry(CPipeUser* pPipeUser)
  1952. {
  1953.         Execute(pPipeUser);
  1954. }
  1955.  
  1956. COPCrysis2Fly::SolverAllocator COPCrysis2Fly::m_Solvers;
  1957.  
  1958. COPCrysis2Fly::COPCrysis2Fly()
  1959.         : m_State(C2F_INVALID)
  1960.         , m_target(AI_REG_NONE)
  1961.         , m_Graph(0)
  1962.         , m_lookAheadDist(10.0f)
  1963.         , m_Solver(0)
  1964.         , m_CurSegmentDir(ZERO)
  1965.         , m_destination(ZERO)
  1966.         , m_nextDestination(ZERO)
  1967.         , m_Length(0xffffffff)
  1968.         , m_PathSizeFinish(1)
  1969.         , m_minDistance(-1.0f)
  1970.         , m_maxDistance(-1.0f)
  1971.         , m_TargetEntity(0)
  1972.         , m_Circular(false)
  1973.         , m_desiredSpeed(50.0f)
  1974.         , m_currentSpeed(50.0f)
  1975.         , m_Timeout(0.0f)
  1976. {
  1977. }
  1978.  
  1979. COPCrysis2Fly::COPCrysis2Fly(const XmlNodeRef& node)
  1980.         : m_State(C2F_INVALID)
  1981.         , m_target(AI_REG_NONE)
  1982.         , m_Graph(0)
  1983.         , m_lookAheadDist(10.0f)
  1984.         , m_Solver(0)
  1985.         , m_CurSegmentDir(ZERO)
  1986.         , m_destination(ZERO)
  1987.         , m_nextDestination(ZERO)
  1988.         , m_Length(0xffffffff)
  1989.         , m_PathSizeFinish(1)
  1990.         , m_minDistance(-1.0f)
  1991.         , m_maxDistance(-1.0f)
  1992.         , m_TargetEntity(0)
  1993.         , m_Circular(false)
  1994.         , m_desiredSpeed(50.0f)
  1995.         , m_currentSpeed(50.0f)
  1996.         , m_Timeout(0.0f)
  1997. {
  1998.         s_xml.GetRegister(node, "register", m_target);
  1999.         node->getAttr("lookahead", m_lookAheadDist);
  2000. }
  2001.  
  2002. COPCrysis2Fly::COPCrysis2Fly(const COPCrysis2Fly& rhs)
  2003. {
  2004.         m_State = rhs.m_State;
  2005.         m_target = rhs.m_target;
  2006.         m_CurSegmentDir = rhs.m_CurSegmentDir;
  2007.         m_destination = rhs.m_destination;
  2008.         m_nextDestination = rhs.m_nextDestination;
  2009.         m_Length = rhs.m_Length;
  2010.         m_Timeout = rhs.m_Timeout;
  2011.         m_lookAheadDist = rhs.m_lookAheadDist;
  2012.         m_PathSizeFinish = rhs.m_PathSizeFinish;
  2013.         m_Circular = rhs.m_Circular;
  2014.         m_minDistance = rhs.m_minDistance;
  2015.         m_maxDistance = rhs.m_maxDistance;
  2016.         m_TargetEntity = rhs.m_TargetEntity;
  2017.         m_desiredSpeed = rhs.m_desiredSpeed;
  2018.         m_currentSpeed = rhs.m_currentSpeed;
  2019.  
  2020.         m_Graph = 0; //rhs.m_Graph;
  2021.         m_Solver = 0;
  2022. }
  2023.  
  2024. COPCrysis2Fly::~COPCrysis2Fly()
  2025. {
  2026. }
  2027.  
  2028. void COPCrysis2Fly::ExecuteDry(CPipeUser* pPipeUser)
  2029. {
  2030.         Execute(pPipeUser);
  2031. }
  2032.  
  2033. static const float drawPath = 0.0f;
  2034.  
  2035. float GetNextPathPoint(std::vector<Vec3>& pathOut, const Vec3& curPos, Vec3& pos, std::vector<Vec3>* reversePath = 0)
  2036. {
  2037.         float ret = 0.0f;
  2038.  
  2039.         pos = curPos;
  2040.  
  2041.         uint32 size = pathOut.size();
  2042.         if (size > 1)
  2043.         {
  2044.                 std::vector<Vec3>::reverse_iterator it = pathOut.rbegin();
  2045.                 Vec3 lastPos = *it;
  2046.  
  2047.                 // current target
  2048.                 ++it;
  2049.                 pos = *it;
  2050.  
  2051.                 Vec3 lastDir = pos - lastPos;
  2052.  
  2053.                 Vec3 curDir = pos - curPos;
  2054.                 float curMagnitude = curDir.GetLength();
  2055.  
  2056.                 lastDir.Normalize();
  2057.                 curDir.Normalize();
  2058.  
  2059.                 if (lastDir.dot(curDir) < 0.98f || curMagnitude < 0.5f)
  2060.                 {
  2061.                         pathOut.pop_back();
  2062.                         it = pathOut.rbegin();
  2063.  
  2064.                         if (reversePath)
  2065.                         {
  2066.                                 reversePath->push_back(*it);
  2067.                         }
  2068.  
  2069.                         --size;
  2070.  
  2071.                         if (size > 1)
  2072.                         {
  2073.                                 *it = curPos;
  2074.                                 ++it;
  2075.                                 pos = *it;
  2076.                         }
  2077.  
  2078.                         curDir = pos - curPos;
  2079.                 }
  2080.  
  2081.                 if (size > 2)
  2082.                 {
  2083.                         ++it;
  2084.  
  2085.                         Vec3 nextPos = *it;
  2086.                         Vec3 nextDir = nextPos - pos;
  2087.                         nextDir.Normalize();
  2088.  
  2089.                         curDir = pos - curPos;
  2090.                         curDir.Normalize();
  2091.  
  2092.                         if (nextDir.dot(curDir) < -0.3f)
  2093.                         {
  2094.                                 pathOut.pop_back();
  2095.                                 it = pathOut.rbegin();
  2096.  
  2097.                                 if (reversePath)
  2098.                                 {
  2099.                                         reversePath->push_back(*it);
  2100.                                 }
  2101.  
  2102.                                 --size;
  2103.  
  2104.                                 *it = curPos;
  2105.                                 ++it;
  2106.  
  2107.                                 pos = *it;
  2108.  
  2109.                                 curDir = pos - curPos;
  2110.                         }
  2111.                 }
  2112.  
  2113.                 ret = pos.GetDistance(curPos);
  2114.         }
  2115.  
  2116.         return ret;
  2117. }
  2118.  
  2119. void UpdatePathPos(std::vector<Vec3>& pathOut, const Vec3& curPos)
  2120. {
  2121.         uint32 size = pathOut.size();
  2122.         if (size > 1)
  2123.         {
  2124.                 std::vector<Vec3>::reverse_iterator it = pathOut.rbegin();
  2125.                 *it = curPos;
  2126.         }
  2127. }
  2128.  
  2129. float GetLookAheadPoint(std::vector<Vec3>& pathOut, float dist, Vec3& pos)
  2130. {
  2131.         float tempDist = dist;
  2132.         float ret = 0.0f;
  2133.  
  2134.         Vec3 lastDir = ZERO;
  2135.  
  2136.         uint32 size = pathOut.size();
  2137.         if (size > 1)
  2138.         {
  2139.                 std::vector<Vec3>::reverse_iterator it = pathOut.rbegin();
  2140.                 Vec3 startPos = *it;
  2141.  
  2142.                 while (++it != pathOut.rend())
  2143.                 {
  2144.                         Vec3 endPos = *it;
  2145.  
  2146.                         Vec3 segment = endPos - startPos;
  2147.                         segment.Normalize();
  2148.  
  2149.                         float temp = startPos.GetDistance(endPos);
  2150.                         float bonus = 1.0f - fabs(lastDir.Dot(segment));
  2151.                         bonus *= 10.0f;
  2152.  
  2153.                         temp += bonus;
  2154.                         lastDir = segment;
  2155.  
  2156.                         if (temp > tempDist)
  2157.                         {
  2158.                                 Vec3 dir = (endPos - startPos);
  2159.                                 dir.Normalize();
  2160.  
  2161.                                 pos = startPos + tempDist * dir;
  2162.                                 ret += tempDist;
  2163.  
  2164.                                 tempDist = 0.0f;
  2165.                                 break;
  2166.                         }
  2167.  
  2168.                         startPos = endPos;
  2169.                         tempDist -= temp;
  2170.                         ret += temp;
  2171.                 }
  2172.  
  2173.                 if (0.0f < tempDist)
  2174.                 {
  2175.                         pos = startPos;
  2176.                 }
  2177.  
  2178.         }
  2179.         else
  2180.         {
  2181.                 pos = pathOut.back();
  2182.         }
  2183.  
  2184.         return ret;
  2185. }
  2186.  
  2187. void COPCrysis2Fly::Reset(CPipeUser* pPipeUser)
  2188. {
  2189.         m_State = C2F_INVALID;
  2190.         m_Graph = 0;
  2191.         m_Length = 0xffffffff;
  2192.         m_desiredSpeed = 50.0f;
  2193.         m_currentSpeed = 50.0f;
  2194.         m_PathSizeFinish = 1;
  2195.         m_Circular = false;
  2196.  
  2197.         m_minDistance = -1.0f;
  2198.         m_maxDistance = -1.0f;
  2199.         m_TargetEntity = 0;
  2200.  
  2201.         m_Threat.Reset();
  2202.  
  2203.         std::vector<Vec3> temp;
  2204.         m_PathOut.swap(temp);
  2205.         std::vector<Vec3> temp2;
  2206.         m_Reversed.swap(temp2);
  2207.  
  2208.         Base::Reset(pPipeUser);
  2209. }
  2210.  
  2211. void COPCrysis2Fly::Serialize(TSerialize ser)
  2212. {
  2213.         ser.BeginGroup("COPCrysis2Fly");
  2214.         {
  2215.                 ser.Value("m_state", *(alias_cast<int*>(&m_State)));
  2216.                 ser.Value("m_target", *(alias_cast<int*>(&m_target)));
  2217.                 ser.Value("m_CurSegmentDir", m_CurSegmentDir);
  2218.                 ser.Value("m_destination", m_destination);
  2219.                 ser.Value("m_nextDestination", m_nextDestination);
  2220.                 ser.Value("m_Length", m_Length);
  2221.                 ser.Value("m_PathSizeFinish", m_PathSizeFinish);
  2222.                 ser.Value("m_Timeout", m_Timeout);
  2223.                 ser.Value("m_lookAheadDist", m_lookAheadDist);
  2224.                 ser.Value("m_desiredSpeed", m_desiredSpeed);
  2225.                 ser.Value("m_currentSpeed", m_currentSpeed);
  2226.  
  2227.                 ser.Value("m_minDistance", m_minDistance);
  2228.                 ser.Value("m_maxDistance", m_maxDistance);
  2229.                 ser.Value("m_TargetEntity", m_TargetEntity);
  2230.  
  2231.                 ser.Value("m_ThreatthreatId", m_Threat.threatId);
  2232.                 ser.Value("m_ThreatthreatPos", m_Threat.threatPos);
  2233.                 ser.Value("m_ThreatthreatDir", m_Threat.threatDir);
  2234.  
  2235.                 ser.Value("m_Circular", m_Circular);
  2236.  
  2237.                 ser.Value("m_PathOut", m_PathOut);
  2238.                 ser.Value("m_Reversed", m_Reversed);
  2239.         }
  2240.         ser.EndGroup();
  2241. }
  2242.  
  2243. COPCrysis2Fly::TargetResult COPCrysis2Fly::GetTarget(CPipeUser* pPipeUser, Vec3& target) const
  2244. {
  2245.         TargetResult ret = C2F_NO_TARGET;
  2246.  
  2247.         switch (m_target)
  2248.         {
  2249.         case AI_REG_REFPOINT:
  2250.                 {
  2251.                         CAIObject* refPoint = pPipeUser->GetRefPoint();
  2252.                         if (refPoint)
  2253.                         {
  2254.                                 target = refPoint->GetPos();
  2255.                                 assert(target.IsValid());
  2256.                                 ret = C2F_TARGET_FOUND;
  2257.                         }
  2258.                 }
  2259.                 break;
  2260.  
  2261.         case AI_REG_ATTENTIONTARGET:
  2262.                 {
  2263.                         IAIObject* refTarget = pPipeUser->GetAttentionTarget();
  2264.                         if (refTarget)
  2265.                         {
  2266.                                 target = refTarget->GetPos();
  2267.                                 assert(target.IsValid());
  2268.                                 ret = C2F_TARGET_FOUND;
  2269.                         }
  2270.                 }
  2271.                 break;
  2272.  
  2273.         case AI_REG_PATH:
  2274.                 {
  2275.                         if (m_State != C2F_FOLLOWINGPATH)
  2276.                                 ret = C2F_SET_PATH;
  2277.                 }
  2278.                 break;
  2279.         }
  2280.  
  2281.         return ret;
  2282. }
  2283.  
  2284. void COPCrysis2Fly::ParseParam(const char* param, const GoalParams& value)
  2285. {
  2286.         if (!stricmp("desiredSpeed", param))
  2287.         {
  2288.                 value.GetValue(m_desiredSpeed);
  2289.                 m_currentSpeed = m_desiredSpeed;
  2290.         }
  2291.         else if (!stricmp("concurrent", param))
  2292.         {
  2293.                 const char* str;
  2294.                 value.GetValue(str);
  2295.  
  2296.                 CGoalPipe* pPipe = gAIEnv.pPipeManager->IsGoalPipe(str);
  2297.  
  2298.                 if (value.GetChildCount() > 0)
  2299.                 {
  2300.                         int32 id;
  2301.                         if (value.GetChild(0).GetValue(id))
  2302.                         {
  2303.                                 pPipe->SetEventId(id);
  2304.                         }
  2305.                 }
  2306.  
  2307.                 if (pPipe)
  2308.                 {
  2309.                         SetConcurrentPipe(pPipe);
  2310.                 }
  2311.         }
  2312.         else if (!stricmp("continuous", param))
  2313.         {
  2314.                 value.GetValue(m_Circular);
  2315.         }
  2316.         else if (!stricmp("minDistance", param))
  2317.         {
  2318.                 value.GetValue(m_minDistance);
  2319.         }
  2320.         else if (!stricmp("maxDistance", param))
  2321.         {
  2322.                 value.GetValue(m_maxDistance);
  2323.         }
  2324.         else if (!stricmp("targetEntity", param))
  2325.         {
  2326.                 value.GetValue(m_TargetEntity);
  2327.         }
  2328.         else if (!stricmp("impulse", param))
  2329.         {
  2330.                 if (!m_Threat.threatId)
  2331.                 {
  2332.                         if (value.GetChildCount() == 2)
  2333.                         {
  2334.                                 value.GetValue(m_Threat.threatPos);
  2335.                                 value.GetChild(0).GetValue(m_Threat.threatDir);
  2336.                                 value.GetChild(1).GetValue(m_Threat.threatId);
  2337.                         }
  2338.                 }
  2339.         }
  2340. }
  2341.  
  2342. EGoalOpResult COPCrysis2Fly::CalculateTarget(CPipeUser* pPipeUser)
  2343. {
  2344.         EGoalOpResult result = eGOR_FAILED;
  2345.  
  2346.         switch (GetTarget(pPipeUser, m_destination))
  2347.         {
  2348.         case C2F_TARGET_FOUND:
  2349.                 {
  2350.                         m_nextDestination = m_destination;
  2351.                         const Vec3& currentPos = pPipeUser->GetPos();
  2352.  
  2353.                         if (m_destination.GetSquaredDistance(currentPos) > 0.25f)
  2354.                         {
  2355.                                 if (m_Graph)
  2356.                                 {
  2357.                                         m_Solver = AllocateSolver();
  2358.  
  2359.                                         if (m_Solver)
  2360.                                         {
  2361.                                                 m_Solver->StartPathFind(m_Graph, m_Graph, m_Graph, currentPos, m_destination);
  2362.                                                 m_State = C2F_PATHFINDING;
  2363.                                         }
  2364.                                         else
  2365.                                         {
  2366.                                                 return eGOR_FAILED;
  2367.                                         }
  2368.                                 }
  2369.                         }
  2370.                 }
  2371.                 result = eGOR_IN_PROGRESS;
  2372.                 break;
  2373.         case C2F_SET_PATH:
  2374.                 {
  2375.                         const char* pathToFollow = pPipeUser->GetPathToFollow();
  2376.  
  2377.                         SShape path;
  2378.                         if (gAIEnv.pNavigation->GetDesignerPath(pathToFollow, path))
  2379.                         {
  2380.                                 if (!path.shape.empty())
  2381.                                 {
  2382.                                         uint32 index = 0;
  2383.  
  2384.                                         uint32 startIndex;
  2385.                                         float dist;
  2386.                                         Vec3 nearestPt;
  2387.                                         path.NearestPointOnPath(pPipeUser->GetPos(), m_Circular, dist, nearestPt, 0, 0, &startIndex);
  2388.  
  2389.                                         m_PathOut.clear();
  2390.  
  2391.                                         size_t pathSize = path.shape.size();
  2392.  
  2393.                                         if (m_Circular && !path.closed)
  2394.                                         {
  2395.                                                 m_PathOut.push_back(path.shape.front());
  2396.                                                 ++pathSize;
  2397.                                                 ++index;
  2398.                                         }
  2399.  
  2400.                                         if (path.closed || m_Circular)
  2401.                                         {
  2402.                                                 m_PathSizeFinish = 2;
  2403.                                                 m_Circular = true;
  2404.  
  2405.                                                 if (startIndex == pathSize - 2)
  2406.                                                 {
  2407.                                                         startIndex = 0;
  2408.                                                 }
  2409.                                         }
  2410.  
  2411.                                         m_PathOut.resize(pathSize + 1 - startIndex);
  2412.                                         std::vector<Vec3>::const_reverse_iterator end = path.shape.rend() - startIndex;
  2413.                                         for (std::vector<Vec3>::const_reverse_iterator it = path.shape.rbegin(); end != it; ++it)
  2414.                                         {
  2415.                                                 m_PathOut[index] = *it;
  2416.                                                 ++index;
  2417.                                         }
  2418.  
  2419.                                         m_PathOut[index] = pPipeUser->GetPos();
  2420.  
  2421.                                         m_Reversed.clear();
  2422.                                         m_Reversed.reserve(m_PathOut.size());
  2423.  
  2424.                                         m_destination = (m_Circular) ? m_PathOut[1] : m_PathOut[0];
  2425.  
  2426.                                         m_State = C2F_FOLLOWINGPATH;
  2427.                                         result = eGOR_IN_PROGRESS;
  2428.                                 }
  2429.                         }
  2430.                 }
  2431.                 break;
  2432.         default:
  2433.                 break;
  2434.         }
  2435.  
  2436.         return result;
  2437. }
  2438.  
  2439. bool COPCrysis2Fly::HandleThreat(CPipeUser* pPipeUser, const Vec3& moveDir)
  2440. {
  2441.         bool ret = false;
  2442.  
  2443.         if (pPipeUser->IsPerceptionEnabled())
  2444.         {
  2445.                 if (m_Threat.threatId)
  2446.                 {
  2447.                         if (IEntity* entity = gEnv->pEntitySystem->GetEntity(m_Threat.threatId))
  2448.                         {
  2449.                                 Vec3 dir = pPipeUser->GetPos() - entity->GetPos();
  2450.                                 dir.Normalize();
  2451.  
  2452.                                 if (m_Threat.threatDir.dot(dir) > 0.5f)
  2453.                                 {
  2454.                                         if (!moveDir.IsEquivalent(ZERO))
  2455.                                         {
  2456.                                                 Vec3 pos = pPipeUser->GetPos();
  2457.                                                 Lineseg moveSeg(pos + moveDir * 50.0f, pos - moveDir * 50.0f);
  2458.                                                 Lineseg threSeg(m_Threat.threatPos, m_Threat.threatPos + m_Threat.threatDir * 5.0f);
  2459.  
  2460.                                                 float moveFrac, threadFrac;
  2461.                                                 if (Intersect::Lineseg_Lineseg2D(moveSeg, threSeg, moveFrac, threadFrac))
  2462.                                                 {
  2463.                                                         if (moveFrac < 0.5f)
  2464.                                                         {
  2465.                                                                 if (m_currentSpeed < 5.0f)
  2466.                                                                 {
  2467.                                                                         m_PathOut.swap(m_Reversed);
  2468.                                                                         m_PathOut.push_back(pPipeUser->GetPos());
  2469.                                                                         m_currentSpeed = m_desiredSpeed;
  2470.                                                                 }
  2471.                                                                 else
  2472.                                                                 {
  2473.                                                                         m_currentSpeed = 0.0f;
  2474.                                                                 }
  2475.                                                         }
  2476.                                                         else
  2477.                                                         {
  2478.                                                                 m_currentSpeed = m_desiredSpeed;
  2479.                                                         }
  2480.  
  2481.                                                         ret = true;
  2482.                                                 }
  2483.                                         }
  2484.                                 }
  2485.                                 else
  2486.                                 {
  2487.                                         m_Threat.Reset();
  2488.                                 }
  2489.                         }
  2490.                         else
  2491.                         {
  2492.                                 m_Threat.Reset();
  2493.                         }
  2494.                 }
  2495.         }
  2496.  
  2497.         return ret;
  2498. }
  2499.  
  2500. void COPCrysis2Fly::SendEvent(CPipeUser* pPipeUser, const char* eventName)
  2501. {
  2502.         if (pPipeUser && eventName)
  2503.         {
  2504.                 SEntityEvent event(ENTITY_EVENT_SCRIPT_EVENT);
  2505.                 event.nParam[0] = (INT_PTR)eventName;
  2506.                 event.nParam[1] = IEntityClass::EVT_BOOL;
  2507.                 bool bValue = true;
  2508.                 event.nParam[2] = (INT_PTR)&bValue;
  2509.                 pPipeUser->GetEntity()->SendEvent(event);
  2510.         }
  2511. }
  2512.  
  2513. float COPCrysis2Fly::CheckTargetEntity(const CPipeUser* pPipeUser, const Vec3& lookAheadPos)
  2514. {
  2515.         float ret = m_desiredSpeed;
  2516.  
  2517.         if (m_TargetEntity && (m_minDistance > 0.0f) && (m_maxDistance > 0.0f))
  2518.         {
  2519.                 IEntity* pEntity = gEnv->pEntitySystem->GetEntity(m_TargetEntity);
  2520.  
  2521.                 if (pEntity)
  2522.                 {
  2523.                         float frameTime = gEnv->pTimer->GetFrameTime();
  2524.  
  2525.                         Vec3 targetEntityPos = pEntity->GetPos();
  2526.  
  2527.                         const char* pathToFollow = pPipeUser->GetPathToFollow();
  2528.  
  2529.                         SShape path;
  2530.                         if (gAIEnv.pNavigation->GetDesignerPath(pathToFollow, path))
  2531.                         {
  2532.                                 float dist;
  2533.                                 path.NearestPointOnPath(pEntity->GetPos(), false, dist, targetEntityPos);
  2534.                         }
  2535.  
  2536.                         Vec3 currentPos = pPipeUser->GetPos();
  2537.  
  2538.                         Vec3 currentDir = lookAheadPos - currentPos;
  2539.                         currentDir.Normalize();
  2540.  
  2541.                         Vec3 diff = targetEntityPos - currentPos;
  2542.                         float dist = diff.GetLength();
  2543.  
  2544.                         diff *= 1.0f / dist;
  2545.  
  2546.                         pe_status_dynamics vel;
  2547.                         float targetSpeed = 0.f;
  2548.                         if (IPhysicalEntity* pPhysics = pEntity->GetPhysics())
  2549.                         {
  2550.                                 pPhysics->GetStatus(&vel);
  2551.                                 targetSpeed = vel.v.GetLength();
  2552.                         }
  2553.  
  2554.                         Vec3 targetDir = pEntity->GetForwardDir();
  2555.  
  2556.                         bool behind = targetDir.dot(diff) > 0.0f && currentDir.dot(targetDir) > 0.0f;
  2557.  
  2558.                         if (dist < m_minDistance && !behind)
  2559.                         {
  2560.                                 //Speed up or so
  2561.                                 if (currentDir.dot(diff) > 0.0f)
  2562.                                 {
  2563.                                         if (m_currentSpeed > 1.0f)
  2564.                                         {
  2565.                                                 m_currentSpeed = m_currentSpeed - m_currentSpeed * frameTime;
  2566.                                                 ret = m_currentSpeed;
  2567.                                         }
  2568.                                         else
  2569.                                         {
  2570.                                                 m_PathOut.swap(m_Reversed);
  2571.                                                 m_PathOut.push_back(currentPos);
  2572.                                         }
  2573.                                 }
  2574.                                 else
  2575.                                 {
  2576.                                         m_currentSpeed = max(min(targetSpeed, m_desiredSpeed), m_desiredSpeed * 0.25f);
  2577.                                         ret = m_currentSpeed;
  2578.                                 }
  2579.                         }
  2580.                         else if (dist > m_maxDistance && !behind)
  2581.                         {
  2582.                                 //slow down or approach
  2583.                                 //Speed up or so
  2584.                                 if (currentDir.dot(diff) < 0.0f)
  2585.                                 {
  2586.                                         if (m_currentSpeed > 1.0f)
  2587.                                         {
  2588.                                                 m_currentSpeed = m_currentSpeed - m_currentSpeed * frameTime;
  2589.                                                 ret = m_currentSpeed;
  2590.                                         }
  2591.                                         else
  2592.                                         {
  2593.                                                 m_PathOut.swap(m_Reversed);
  2594.                                                 m_PathOut.push_back(currentPos);
  2595.                                         }
  2596.                                 }
  2597.                                 else
  2598.                                 {
  2599.                                         m_currentSpeed = max(min(targetSpeed, m_desiredSpeed), m_desiredSpeed * 0.25f);
  2600.                                         ret = m_currentSpeed;
  2601.                                 }
  2602.                         }
  2603.                         else if (!behind)
  2604.                         {
  2605.                                 m_currentSpeed = m_currentSpeed + (targetSpeed - m_currentSpeed) * frameTime;
  2606.                                 ret = m_currentSpeed;
  2607.                         }
  2608.                         else
  2609.                         {
  2610.                                 m_currentSpeed = m_desiredSpeed;
  2611.                                 ret = m_currentSpeed;
  2612.                         }
  2613.                 }
  2614.         }
  2615.  
  2616.         return ret;
  2617. }
  2618.  
  2619. EGoalOpResult COPCrysis2Fly::Execute(CPipeUser* pPipeUser)
  2620. {
  2621.         EGoalOpResult result = eGOR_FAILED;
  2622.  
  2623.         if (Base::Execute(pPipeUser) == eGOR_DONE)
  2624.         {
  2625.                 Base::Reset(pPipeUser);
  2626.         }
  2627.  
  2628.         switch (m_State)
  2629.         {
  2630.         case C2F_INVALID:
  2631.                 {
  2632.                         FRAME_PROFILER("COPCrysis2Fly: SETUP ASTAR", gEnv->pSystem, PROFILE_AI);
  2633.  
  2634.                         result = CalculateTarget(pPipeUser);
  2635.  
  2636.                         //break here if failed or designer placed path set
  2637.                         if (eGOR_FAILED == result)
  2638.                         {
  2639.                                 SendEvent(pPipeUser, "GoToFailed");
  2640.                                 break;
  2641.                         }
  2642.                         else if (C2F_FOLLOWINGPATH == m_State)
  2643.                         {
  2644.                                 break;
  2645.                         }
  2646.                 }
  2647.         case C2F_PATHFINDING:
  2648.                 {
  2649.                         FRAME_PROFILER("COPCrysis2Fly: ASTAR UPDATE", gEnv->pSystem, PROFILE_AI);
  2650.  
  2651.                         if (m_Solver)
  2652.                         {
  2653.                                 if (m_Solver->Update(10))
  2654.                                 {
  2655.                                         std::vector<Vec3i> pathRaw;
  2656.                                         pathRaw.clear();
  2657.  
  2658.                                         m_Solver->GetPathReversed(pathRaw);
  2659.                                         DestroySolver(m_Solver);
  2660.                                         m_Solver = 0;
  2661.  
  2662.                                         m_PathOut.clear();
  2663.                                         if (m_Graph)
  2664.                                         {
  2665.                                                 m_Graph->BeautifyPath(pPipeUser->GetPos(), m_destination, pathRaw, m_PathOut);
  2666.  
  2667.                                                 if (m_PathOut.size() < 2)
  2668.                                                 {
  2669.                                                         SendEvent(pPipeUser, "GoToSucceeded");
  2670.                                                         return eGOR_DONE;
  2671.                                                 }
  2672.  
  2673.                                                 m_Reversed.clear();
  2674.                                                 m_Reversed.reserve(m_PathOut.size());
  2675.  
  2676.                                                 Vec3& curPos = m_PathOut.back();
  2677.                                                 curPos = pPipeUser->GetPos();
  2678.  
  2679.                                                 Vec3& nextPos = *(&curPos - 1);
  2680.                                                 Vec3 moveDir = nextPos - curPos;
  2681.                                                 moveDir.Normalize();
  2682.  
  2683.                                                 m_CurSegmentDir = moveDir;
  2684.  
  2685.                                                 pPipeUser->m_State.predictedCharacterStates.nStates = 0;
  2686.                                                 pPipeUser->m_State.vMoveDir = moveDir;
  2687.                                                 pPipeUser->m_State.vLookTargetPos = curPos + 100.0f * moveDir;
  2688.                                                 pPipeUser->m_State.fDesiredSpeed = 0.0f;
  2689.  
  2690.                                                 m_State = C2F_FOLLOWINGPATH;
  2691.                                         }
  2692.                                 }
  2693.  
  2694.                                 result = eGOR_IN_PROGRESS;
  2695.  
  2696.                         }
  2697.                         else
  2698.                         {
  2699.                                 result = eGOR_IN_PROGRESS;
  2700.                         }
  2701.                 }
  2702.                 break;
  2703.  
  2704.         case C2F_FOLLOW_AND_SWITCH:
  2705.         case C2F_FOLLOW_AND_CALC_NEXT:
  2706.                 switch (m_State)
  2707.                 {
  2708.                 case C2F_FOLLOW_AND_CALC_NEXT:
  2709.                         if (m_Solver)
  2710.                         {
  2711.                                 if (m_Solver->Update(2))
  2712.                                 {
  2713.                                         m_State = C2F_FOLLOW_AND_SWITCH;
  2714.                                         m_Length = 0xffffffff;
  2715.                                 }
  2716.                         }
  2717.                         break;
  2718.                 case C2F_FOLLOW_AND_SWITCH:
  2719.                         {
  2720.                                 if (m_Solver)
  2721.                                 {
  2722.                                         std::vector<Vec3i> pathRaw;
  2723.                                         pathRaw.clear();
  2724.  
  2725.                                         m_Solver->GetPathReversed(pathRaw);
  2726.                                         DestroySolver(m_Solver);
  2727.                                         m_Solver = 0;
  2728.  
  2729.                                         m_PathOut.clear();
  2730.                                         if (m_Graph)
  2731.                                         {
  2732.                                                 m_Graph->BeautifyPath(m_destination, m_nextDestination, pathRaw, m_PathOut);
  2733.                                                 m_PathOut.push_back(pPipeUser->GetPos());
  2734.  
  2735.                                                 m_Length = m_PathOut.size();
  2736.                                                 if (m_PathOut.size() < 2)
  2737.                                                 {
  2738.                                                         SendEvent(pPipeUser, "GoToSucceeded");
  2739.                                                         return eGOR_DONE;
  2740.                                                 }
  2741.  
  2742.                                         }
  2743.                                 }
  2744.  
  2745.                                 if (m_PathOut.size() < m_Length)
  2746.                                 {
  2747.                                         SendEvent(pPipeUser, "GoToSucceeded");
  2748.  
  2749.                                         m_destination = m_nextDestination;
  2750.                                         m_State = C2F_FOLLOWINGPATH;
  2751.                                         m_Length = 0xffffffff;
  2752.                                 }
  2753.                         }
  2754.                         break;
  2755.                 }
  2756.  
  2757.         case C2F_FOLLOWINGPATH:
  2758.                 {
  2759.                         if ((m_State != C2F_FOLLOW_AND_CALC_NEXT) && (m_State != C2F_FOLLOW_AND_SWITCH) && (GetTarget(pPipeUser, m_nextDestination) != C2F_NO_TARGET))
  2760.                         {
  2761.                                 if (!m_destination.IsEquivalent(m_nextDestination))
  2762.                                 {
  2763.                                         m_Solver = AllocateSolver();
  2764.                                         m_Solver->StartPathFind(m_Graph, m_Graph, m_Graph, m_destination, m_nextDestination);
  2765.                                         m_State = C2F_FOLLOW_AND_CALC_NEXT;
  2766.                                 }
  2767.                         }
  2768.  
  2769.                         if (m_PathSizeFinish == m_PathOut.size() && m_Circular)
  2770.                         {
  2771.                                 Vec3 target;
  2772.                                 m_State = C2F_INVALID;
  2773.                                 CalculateTarget(pPipeUser);
  2774.                         }
  2775.  
  2776.                         if (m_PathOut.size() > m_PathSizeFinish)
  2777.                         {
  2778.                                 Vec3 curPos = pPipeUser->GetPos();
  2779.  
  2780.                                 ColorB colour(0, 255, 0);
  2781.                                 Vec3 nextPos;
  2782.                                 float dist = GetNextPathPoint(m_PathOut, curPos, nextPos, &m_Reversed);
  2783.  
  2784.                                 if (FLT_EPSILON > dist)
  2785.                                 {
  2786.                                         SendEvent(pPipeUser, "GoToFailed");
  2787.  
  2788.                                         pPipeUser->m_State.predictedCharacterStates.nStates = 0;
  2789.                                         pPipeUser->m_State.vMoveDir = ZERO;
  2790.                                         pPipeUser->m_State.fDesiredSpeed = 0.0f;
  2791.  
  2792.                                         m_State = C2F_FAILED;
  2793.                                         result = eGOR_FAILED;
  2794.                                 }
  2795.  
  2796.                                 if (gAIEnv.CVars.DebugPathFinding)
  2797.                                 {
  2798.                                         gEnv->pRenderer->GetIRenderAuxGeom()->DrawCone(nextPos + Vec3(0.0f, 0.0f, 2.0f), Vec3(0.0f, 0.0f, -1.0f), 1.0f, 2.0f, colour);
  2799.                                 }
  2800.  
  2801.                                 colour.r = 255;
  2802.                                 colour.g = 0;
  2803.                                 Vec3 lookAheadPos;
  2804.  
  2805.                                 float lookDist = m_lookAheadDist;
  2806.                                 GetLookAheadPoint(m_PathOut, lookDist, lookAheadPos);
  2807.  
  2808.                                 if (gAIEnv.CVars.DebugPathFinding)
  2809.                                 {
  2810.                                         gEnv->pRenderer->GetIRenderAuxGeom()->DrawCone(lookAheadPos + Vec3(0.0f, 0.0f, 2.0f