BVB Source Codes

CRYENGINE Show GoalOpTrace.cpp Source code

Return Download CRYENGINE: download GoalOpTrace.cpp Source code - Download CRYENGINE Source code - Type:.cpp
  1. // Copyright 2001-2016 Crytek GmbH / Crytek Group. All rights reserved.
  2.  
  3. #include "StdAfx.h"
  4. #include "GoalOpTrace.h"
  5. #include "DebugDrawContext.h"
  6. #include "Puppet.h"
  7.  
  8. #include "Navigation/NavigationSystem/NavigationSystem.h"
  9. #include "Navigation/NavigationSystem/OffMeshNavigationManager.h"
  10. #include "Navigation/MNM/OffGridLinks.h"
  11.  
  12. PathFollowResult::TPredictedStates COPTrace::s_tmpPredictedStates;
  13. int COPTrace::s_instanceCount;
  14.  
  15. //===================================================================
  16. // COPTrace
  17. //===================================================================
  18. COPTrace::COPTrace(bool bExactFollow, float fEndAccuracy, bool bForceReturnPartialPath, bool bStopOnAnimationStart, ETraceEndMode eTraceEndMode)
  19.         : m_Maneuver(eMV_None)
  20.         , m_ManeuverDir(eMVD_Clockwise)
  21.         , m_eTraceEndMode(eTraceEndMode)
  22.         , m_fEndAccuracy(fEndAccuracy)
  23.         , m_passingStraightNavSO(false)
  24.         , m_bBlock_ExecuteTrace_untilFullUpdateThenReset(false)
  25.         , m_ManeuverDist(0.f)
  26.         , m_landHeight(0.f)
  27.         , m_workingLandingHeightOffset(0.f)
  28.         , m_landingPos(ZERO)
  29.         , m_landingDir(ZERO)
  30.         , m_bExactFollow(bExactFollow)
  31.         , m_bForceReturnPartialPath(bForceReturnPartialPath)
  32.         , m_lastPosition(ZERO)
  33.         , m_prevFrameStartTime(-1000ll)
  34.         , m_TimeStep(0.1f)
  35.         , m_looseAttentionId(0)
  36.         , m_fTotalTracingTime(0.f)
  37.         , m_inhibitPathRegen(false)
  38.         , m_bWaitingForPathResult(false)
  39.         , m_bWaitingForBusySmartObject(false)
  40.         , m_earlyPathRegen(false)
  41.         , m_bControlSpeed(true)
  42.         , m_fTravelDist(0.f)
  43.         , m_accumulatedFailureTime(0.0f)
  44.         , m_actorTargetRequester(eTATR_None)
  45.         , m_pendingActorTargetRequester(eTATR_None)
  46.         , m_stopOnAnimationStart(bStopOnAnimationStart)
  47. {
  48.         if (gAIEnv.CVars.DebugPathFinding)
  49.                 AILogAlways("COPTrace::COPTrace %p", this);
  50.  
  51.         ++s_instanceCount;
  52. }
  53.  
  54. COPTrace::COPTrace(const XmlNodeRef& node)
  55.         : m_Maneuver(eMV_None)
  56.         , m_ManeuverDir(eMVD_Clockwise)
  57.         , m_eTraceEndMode(eTEM_FixedDistance)
  58.         , m_fEndAccuracy(0.f)
  59.         , m_passingStraightNavSO(false)
  60.         , m_bBlock_ExecuteTrace_untilFullUpdateThenReset(false)
  61.         , m_ManeuverDist(0.f)
  62.         , m_landHeight(0.f)
  63.         , m_workingLandingHeightOffset(0.f)
  64.         , m_landingPos(ZERO)
  65.         , m_landingDir(ZERO)
  66.         , m_bExactFollow(s_xml.GetBool(node, "exactFollow"))
  67.         , m_bForceReturnPartialPath(s_xml.GetBool(node, "forceReturnPartialPath"))
  68.         , m_lastPosition(ZERO)
  69.         , m_prevFrameStartTime(-1000ll)
  70.         , m_TimeStep(0.1f)
  71.         , m_looseAttentionId(0)
  72.         , m_fTotalTracingTime(0.f)
  73.         , m_inhibitPathRegen(false)
  74.         , m_bWaitingForPathResult(false)
  75.         , m_bWaitingForBusySmartObject(false)
  76.         , m_earlyPathRegen(false)
  77.         , m_bControlSpeed(true)
  78.         , m_fTravelDist(0.f)
  79.         , m_accumulatedFailureTime(0.0f)
  80.         , m_actorTargetRequester(eTATR_None)
  81.         , m_pendingActorTargetRequester(eTATR_None)
  82.         , m_stopOnAnimationStart(s_xml.GetBool(node, "stopOnAnimationStart"))
  83. {
  84.         node->getAttr("endAccuracy", m_fEndAccuracy);
  85.  
  86.         ++s_instanceCount;
  87. }
  88.  
  89. COPTrace::COPTrace(const COPTrace& rhs)
  90.         : m_Maneuver(eMV_None)
  91.         , m_ManeuverDir(eMVD_Clockwise)
  92.         , m_eTraceEndMode(eTEM_FixedDistance)
  93.         , m_fEndAccuracy(rhs.m_fEndAccuracy)
  94.         , m_passingStraightNavSO(false)
  95.         , m_bBlock_ExecuteTrace_untilFullUpdateThenReset(false)
  96.         , m_ManeuverDist(0.f)
  97.         //, m_ManeuverTime(0.f)
  98.         , m_landHeight(0.f)
  99.         , m_workingLandingHeightOffset(0.f)
  100.         , m_landingPos(ZERO)
  101.         , m_landingDir(ZERO)
  102.         , m_bExactFollow(rhs.m_bExactFollow)
  103.         , m_bForceReturnPartialPath(rhs.m_bForceReturnPartialPath)
  104.         , m_lastPosition(ZERO)
  105.         , m_prevFrameStartTime(-1000ll)
  106.         , m_TimeStep(0.1f)
  107.         , m_looseAttentionId(0)
  108.         , m_fTotalTracingTime(0.f)
  109.         , m_inhibitPathRegen(false)
  110.         , m_bWaitingForPathResult(false)
  111.         , m_bWaitingForBusySmartObject(false)
  112.         , m_earlyPathRegen(false)
  113.         , m_bControlSpeed(true)
  114.         , m_fTravelDist(0.f)
  115.         , m_accumulatedFailureTime(0.0f)
  116.         , m_actorTargetRequester(eTATR_None)
  117.         , m_pendingActorTargetRequester(eTATR_None)
  118.         , m_refNavTarget()
  119.         , m_stopOnAnimationStart(rhs.m_stopOnAnimationStart)
  120. {
  121.         ++s_instanceCount;
  122. }
  123.  
  124. //===================================================================
  125. // ~COPTrace
  126. //===================================================================
  127. COPTrace::~COPTrace()
  128. {
  129.         CCCPOINT(COPTrace_Destructor);
  130.  
  131.         CPipeUser* const pPipeUser = m_refPipeUser.GetAIObject();
  132.         if (pPipeUser)
  133.         {
  134.                 pPipeUser->CancelRequestedPath(false);
  135.                 pPipeUser->SetLooseAttentionTarget(NILREF, m_looseAttentionId);
  136.                 m_looseAttentionId = 0;
  137.  
  138.                 SOBJECTSTATE& state = pPipeUser->m_State;
  139.                 if (!state.continuousMotion)
  140.                         state.fDesiredSpeed = 0.f;
  141.  
  142.                 pPipeUser->ClearPath("COPTrace::~COPTrace m_Path");
  143.         }
  144.  
  145.         m_refPipeUser.Reset();
  146.         m_refNavTarget.Release();
  147.  
  148.         if (gAIEnv.CVars.DebugPathFinding)
  149.                 AILogAlways("COPTrace::~COPTrace %p %s", this, GetNameSafe(pPipeUser));
  150.  
  151.         --s_instanceCount;
  152.         if (s_instanceCount == 0)
  153.         {
  154.                 stl::free_container(s_tmpPredictedStates);
  155.         }
  156. }
  157.  
  158. //===================================================================
  159. // Reset
  160. //===================================================================
  161. void COPTrace::Reset(CPipeUser* pPipeUser)
  162. {
  163.         CCCPOINT(COPTrace_Reset);
  164.  
  165.         if (pPipeUser && gAIEnv.CVars.DebugPathFinding)
  166.                 AILogAlways("COPTrace::Reset %s", GetNameSafe(pPipeUser));
  167.  
  168.         if (pPipeUser)
  169.         {
  170.                 CCCPOINT(COPTrace_Reset_A);
  171.  
  172.                 pPipeUser->SetLooseAttentionTarget(NILREF, m_looseAttentionId);
  173.                 m_looseAttentionId = 0;
  174.  
  175.                 // If we have regenerated the path as part of the periodic regeneration
  176.                 // then the request must be cancelled. However, don't always cancel requests
  177.                 // because if stick is trying to regenerate the path and we're
  178.                 // resetting because we reached the end of the current one, then we'll stop
  179.                 // stick from getting its pathfind request.
  180.                 // Generally the m_Path.Empty() condition decides between these cases, but
  181.                 // Danny todo: not sure if it will always work.
  182.                 if (!pPipeUser->m_Path.Empty())
  183.                 {
  184.                         pPipeUser->CancelRequestedPath(false);
  185.                 }
  186.  
  187.                 pPipeUser->m_nPathDecision = PATHFINDER_ABORT;
  188.                 pPipeUser->m_State.fDesiredSpeed = 0.f;
  189.                 pPipeUser->ClearPath("COPTrace::Reset m_Path");
  190.         }
  191.  
  192.         // (MATT) Surely we should reset the stored operand here - but the dummy might best stay, if it exists already {2009/02/18}
  193.         m_refPipeUser.Reset();
  194.         m_refNavTarget.Release();
  195.  
  196.         m_fTotalTracingTime = 0.f;
  197.         m_Maneuver = eMV_None;
  198.         m_ManeuverDist = 0.f;
  199.         m_ManeuverTime = GetAISystem()->GetFrameStartTime();
  200.         m_landHeight = 0.f;
  201.         m_landingDir.zero();
  202.         m_workingLandingHeightOffset = 0.f;
  203.         m_inhibitPathRegen = false;
  204.         m_bBlock_ExecuteTrace_untilFullUpdateThenReset = false;
  205.         m_actorTargetRequester = eTATR_None;
  206.         m_pendingActorTargetRequester = eTATR_None;
  207.         m_bWaitingForPathResult = false;
  208.         m_bWaitingForBusySmartObject = false;
  209.         m_passingStraightNavSO = false;
  210.         m_fTravelDist = 0;
  211.  
  212.         m_TimeStep = 0.1f;
  213.         m_prevFrameStartTime = -1000ll;
  214.         m_accumulatedFailureTime = 0.0f;
  215.  
  216.         if (pPipeUser)
  217.         {
  218.                 if (m_bExactFollow)
  219.                 {
  220.                         pPipeUser->m_bLooseAttention = false;
  221.                 }
  222.  
  223.                 pPipeUser->ClearInvalidatedSOLinks();
  224.         }
  225. }
  226.  
  227. //===================================================================
  228. // Serialize
  229. //===================================================================
  230. void COPTrace::Serialize(TSerialize ser)
  231. {
  232.         ser.Value("m_bBlock_ExecuteTrace_untilFullUpdateThenReset", m_bBlock_ExecuteTrace_untilFullUpdateThenReset);
  233.         ser.Value("m_ManeuverDist", m_ManeuverDist);
  234.         ser.Value("m_ManeuverTime", m_ManeuverTime);
  235.         ser.Value("m_landHeight", m_landHeight);
  236.         ser.Value("m_workingLandingHeightOffset", m_workingLandingHeightOffset);
  237.         ser.Value("m_landingPos", m_landingPos);
  238.         ser.Value("m_landingDir", m_landingDir);
  239.  
  240.         ser.Value("m_bExactFollow", m_bExactFollow);
  241.         ser.Value("m_bForceReturnPartialPath", m_bForceReturnPartialPath);
  242.         ser.Value("m_lastPosition", m_lastPosition);
  243.         ser.Value("m_prevFrameStartTime", m_prevFrameStartTime);
  244.         ser.Value("m_fTravelDist", m_fTravelDist);
  245.         ser.Value("m_TimeStep", m_TimeStep);
  246.  
  247.         m_refPipeUser.Serialize(ser, "m_refPipeUser");
  248.  
  249.         ser.EnumValue("m_Maneuver", m_Maneuver, eMV_None, eMV_Fwd);
  250.         ser.EnumValue("m_ManeuverDir", m_ManeuverDir, eMVD_Clockwise, eMVD_AntiClockwise);
  251.  
  252.         ser.Value("m_fTotalTracingTime", m_fTotalTracingTime);
  253.         ser.Value("m_inhibitPathRegen", m_inhibitPathRegen);
  254.         ser.Value("m_fEndAccuracy", m_fEndAccuracy);
  255.         ser.Value("m_looseAttentionId", m_looseAttentionId);
  256.  
  257.         ser.Value("m_bWaitingForPathResult", m_bWaitingForPathResult);
  258.         ser.Value("m_bWaitingForBusySmartObject", m_bWaitingForBusySmartObject);
  259.         ser.Value("m_passingStraightNavSO", m_passingStraightNavSO);
  260.         ser.EnumValue("m_actorTargetRequester", m_actorTargetRequester, eTATR_None, eTATR_EndOfPath);
  261.         ser.EnumValue("m_pendingActorTargetRequester", m_pendingActorTargetRequester, eTATR_None, eTATR_EndOfPath);
  262.         ser.Value("m_stopOnAnimationStart", m_stopOnAnimationStart);
  263.  
  264.         m_refNavTarget.Serialize(ser, "m_refNavTarget");
  265. }
  266.  
  267. //===================================================================
  268. // Execute
  269. //===================================================================
  270. EGoalOpResult COPTrace::Execute(CPipeUser* pPipeUser)
  271. {
  272.         CCCPOINT(COPTrace_Execute);
  273.         FUNCTION_PROFILER(GetISystem(), PROFILE_AI);
  274.  
  275.         bool bTraceFinished = ExecuteTrace(pPipeUser, /* full update */ true);
  276.  
  277.         SOBJECTSTATE& pipeUserState = pPipeUser->m_State;
  278.  
  279.         if (pPipeUser->m_nPathDecision == PATHFINDER_STILLFINDING)
  280.         {
  281.                 if (bTraceFinished)
  282.                 {
  283.                         pipeUserState.fDesiredSpeed = 0.f;
  284.                 }
  285.                 return eGOR_IN_PROGRESS;
  286.         }
  287.         else
  288.         {
  289.                 if (bTraceFinished)
  290.                 {
  291.                         // Kevin - Clean up residual data that is causing problems elsewhere
  292.                         pipeUserState.fDistanceToPathEnd = 0.f;
  293.  
  294.                         // Done tracing, allow to try to use invalid objects again.
  295.                         pPipeUser->ClearInvalidatedSOLinks();
  296.  
  297.                         if (pipeUserState.curActorTargetPhase == eATP_Error)
  298.                         {
  299.                                 return eGOR_FAILED;
  300.                         }
  301.                 }
  302.                 return bTraceFinished ? eGOR_SUCCEEDED : eGOR_IN_PROGRESS;
  303.         }
  304. }
  305.  
  306. //===================================================================
  307. // ExecuteTrace
  308. // this is the same old COPTrace::Execute method
  309. // but now, smart objects should control when it
  310. // should be executed and how its return value
  311. // will be interpreted
  312. //===================================================================
  313. bool COPTrace::ExecuteTrace(CPipeUser* pPipeUser, bool bFullUpdate)
  314. {
  315.         FUNCTION_PROFILER(GetISystem(), PROFILE_AI);
  316.  
  317.         // The destructor needs to know the most recent pipe user
  318.         if (m_refPipeUser != pPipeUser)
  319.                 m_refPipeUser = GetWeakRef(pPipeUser);
  320.  
  321.         // HACK: Special case fix for drivers in fall&play
  322.         if (IsVehicleAndDriverIsFallen(pPipeUser))
  323.                 return false; // Trace not finished.
  324.  
  325.         bool bTraceFinished = false;
  326.  
  327.         if (m_bWaitingForPathResult)
  328.                 if (!HandlePathResult(pPipeUser, &bTraceFinished))
  329.                         return bTraceFinished;
  330.  
  331.         if (m_bBlock_ExecuteTrace_untilFullUpdateThenReset)
  332.         {
  333.                 if (bFullUpdate)
  334.                 {
  335.                         Reset(pPipeUser);
  336.                 }
  337.                 else
  338.                 {
  339.                         StopMovement(pPipeUser);
  340.                 }
  341.                 return true;  // Trace finished
  342.         }
  343.  
  344.         bool bForceRegeneratePath = false;
  345.         bool bExactPositioning = false;
  346.  
  347.         // Handle exact positioning and vaSOs.
  348.         if (!HandleAnimationPhase(pPipeUser, bFullUpdate, &bForceRegeneratePath, &bExactPositioning, &bTraceFinished))
  349.                 return bTraceFinished;
  350.  
  351.         // On first frame: [6/4/2010 evgeny]
  352.         if (m_prevFrameStartTime.GetValue() < 0ll)
  353.         {
  354.                 // Reset the action input before starting to move.
  355.                 // Calling SetAGInput instead of ResetAGInput since we want to reset
  356.                 // the input even if some other system has set it to non-idle
  357.                 pPipeUser->GetProxy()->SetAGInput(AIAG_ACTION, "idle");
  358.  
  359.                 // Change the SO state to match the movement.
  360.                 IEntity* pEntity = pPipeUser->GetEntity();
  361.                 IEntity* pNullEntity = 0;
  362.                 if (gAIEnv.pSmartObjectManager->SmartObjectEvent("OnMove", pEntity, pNullEntity) != 0)
  363.                         return false; // Trace not finished
  364.         }
  365.  
  366.         CTimeValue now = GetAISystem()->GetFrameStartTime();
  367.  
  368.         float ftimeStep = static_cast<float>((m_prevFrameStartTime.GetValue() > 0ll)
  369.                                              ? (now - m_prevFrameStartTime).GetMilliSecondsAsInt64()
  370.                                              : 0);
  371.         m_prevFrameStartTime = now;
  372.  
  373.         bool isUsing3DNavigation = pPipeUser->IsUsing3DNavigation();
  374.  
  375.         if (bExactPositioning)
  376.         {
  377.                 m_passingStraightNavSO = false;
  378.         }
  379.         else
  380.         {
  381.                 IPathFollower* pPathFollower = gAIEnv.CVars.PredictivePathFollowing ? pPipeUser->GetPathFollower() : 0;
  382.                 float distToSmartObject = pPathFollower ? pPathFollower->GetDistToSmartObject() : pPipeUser->m_Path.GetDistToSmartObject(!isUsing3DNavigation);
  383.                 m_passingStraightNavSO = distToSmartObject < 1.f;
  384.         }
  385.  
  386.         if (bFullUpdate)
  387.         {
  388.                 float fDistanceToPathEnd = pPipeUser->m_State.fDistanceToPathEnd;
  389.                 const float fExactPosTriggerDistance = 2.5f; //10.0f;
  390.  
  391.                 // Trigger the exact positioning when path is found (sometimes it is still in progress because of previous navSO usage),
  392.                 // and when close enough or just finished trace without following it.
  393.                 m_bWaitingForBusySmartObject = false;
  394.  
  395.                 if ((fDistanceToPathEnd >= 0.f && fDistanceToPathEnd <= fExactPosTriggerDistance) ||
  396.                     pPipeUser->m_Path.GetPathLength(!pPipeUser->IsUsing3DNavigation()) <= fExactPosTriggerDistance)
  397.                 {
  398.                         TriggerExactPositioning(pPipeUser, &bForceRegeneratePath, &bExactPositioning);
  399.                 }
  400.         }
  401.  
  402. #ifdef _DEBUG
  403.         ExecuteTraceDebugDraw(pPipeUser);
  404. #endif
  405.  
  406.         float timeStep = max(0.0f, ftimeStep * 0.001f);
  407.         m_fTotalTracingTime += timeStep;
  408.         m_TimeStep = timeStep;
  409.  
  410.         // If this path was generated with the pathfinder quietly regenerate the path
  411.         // periodically in case something has moved.
  412.         if (bForceRegeneratePath || (bFullUpdate && !m_inhibitPathRegen && !m_passingStraightNavSO && !m_bWaitingForBusySmartObject &&
  413.                                      pPipeUser->m_movementAbility.pathRegenIntervalDuringTrace > 0.01f &&
  414.                                      pPipeUser->m_movementAbility.pathRegenIntervalDuringTrace < m_fTotalTracingTime &&
  415.                                      !pPipeUser->m_Path.GetParams().precalculatedPath &&
  416.                                      !pPipeUser->m_Path.GetParams().inhibitPathRegeneration))
  417.         {
  418.                 if (gAIEnv.CVars.CrowdControlInPathfind != 0 || gAIEnv.CVars.AdjustPathsAroundDynamicObstacles != 0)
  419.                 {
  420.                         RegeneratePath(pPipeUser, &bForceRegeneratePath);
  421.                 }
  422.  
  423.                 // The path was forced to be regenerated when a navigational smartobject has been passed.
  424.                 if (bForceRegeneratePath)
  425.                 {
  426.                         m_bWaitingForPathResult = true;
  427.                         return false;   // Trace not finished
  428.                 }
  429.         }
  430.  
  431.         //////////////////////////////////////////////////////////////////////////
  432.         // ExecuteTrace Core
  433.         if (!m_bWaitingForPathResult && !m_bWaitingForBusySmartObject)
  434.         {
  435.                 IPathFollower* pPathFollower = gAIEnv.CVars.PredictivePathFollowing ? pPipeUser->GetPathFollower() : 0;
  436.                 bTraceFinished = pPathFollower ? ExecutePathFollower(pPipeUser, bFullUpdate, pPathFollower)
  437.                                  : isUsing3DNavigation ? Execute3D(pPipeUser, bFullUpdate) : Execute2D(pPipeUser, bFullUpdate);
  438.         }
  439.         //////////////////////////////////////////////////////////////////////////
  440.  
  441.         if (bExactPositioning)
  442.         {
  443.                 // If exact positioning is in motion, do not allow to finish the goal op, just yet.
  444.                 // This may happen in some cases when the exact positioning start position is just over
  445.                 // the starting point of a navSO, or during the animation playback to keep the
  446.                 // prediction warm.
  447.  
  448.                 bTraceFinished = false;
  449.         }
  450.  
  451.         // prevent future updates unless we get an external reset
  452.         if (bTraceFinished && pPipeUser->m_nPathDecision != PATHFINDER_STILLFINDING)
  453.         {
  454.                 if (bFullUpdate)
  455.                 {
  456.                         Reset(pPipeUser);
  457.                         return true;  // Full update, trace finished
  458.                 }
  459.                 else
  460.                 {
  461.                         StopMovement(pPipeUser);
  462.                         m_bBlock_ExecuteTrace_untilFullUpdateThenReset = true;
  463.                         return false; // Waiting for full update, trace not yet finished at the moment
  464.                 }
  465.         }
  466.  
  467.         return bTraceFinished;
  468. }
  469.  
  470. //===================================================================
  471. // ExecuteManeuver
  472. //===================================================================
  473. void COPTrace::ExecuteManeuver(CPipeUser* pPipeUser, const Vec3& steerDir)
  474. {
  475.         if (fabs(pPipeUser->m_State.fDesiredSpeed) < 0.001f)
  476.         {
  477.                 m_Maneuver = eMV_None;
  478.                 return;
  479.         }
  480.  
  481. #ifdef _DEBUG
  482.         // Update the debug movement reason.
  483.         pPipeUser->m_DEBUGmovementReason = CPipeUser::AIMORE_MANEUVER;
  484. #endif
  485.  
  486.         // first work out which direction to rotate (normally const over the whole
  487.         // maneuver). Subsequently work out fwd/backwards. Then steer based on
  488.         // the combination of the two
  489.  
  490.         float cosTrh = pPipeUser->m_movementAbility.maneuverTrh;
  491.         if (pPipeUser->m_movementAbility.maneuverTrh >= 1.f || pPipeUser->m_IsSteering)
  492.                 return;
  493.  
  494.         Vec3 myDir = pPipeUser->GetMoveDir();
  495.         if (pPipeUser->m_State.fMovementUrgency < 0.0f)
  496.                 myDir *= -1.0f;
  497.         myDir.z = 0.0f;
  498.         myDir.NormalizeSafe();
  499.         Vec3 reqDir = steerDir;
  500.         reqDir.z = 0.0f;
  501.         reqDir.NormalizeSafe();
  502.         Vec3 myVel = pPipeUser->GetVelocity();
  503.         Vec3 myPos = pPipeUser->GetPhysicsPos();
  504.  
  505.         float diffCos = reqDir.Dot(myDir);
  506.         // if not maneuvering then require a big angle change to enter it
  507.         if (diffCos > cosTrh && m_Maneuver == eMV_None)
  508.                 return;
  509.  
  510.         CTimeValue now(GetAISystem()->GetFrameStartTime());
  511.  
  512.         // prevent very small wiggles.
  513.         const int maneuverTimeMinLimitMs = 300;
  514.         const int maneuverTimeMaxLimitMs = 5000;
  515.         const int manTimeMs = (int)(m_Maneuver != eMV_None ? (now - m_ManeuverTime).GetMilliSecondsAsInt64() : 0);
  516.  
  517.         // if maneuvering only stop when closely lined up
  518.         static float exitDiffCos = 0.98f;
  519.         if (diffCos > exitDiffCos && m_Maneuver != eMV_None && manTimeMs > maneuverTimeMinLimitMs)
  520.         {
  521.                 m_Maneuver = eMV_None;
  522.                 return;
  523.         }
  524.  
  525.         // hack for instant turning
  526.         Vec3 camPos = GetISystem()->GetViewCamera().GetPosition();
  527.         Vec3 opPos = pPipeUser->GetPhysicsPos();
  528.         float distSq = Distance::Point_Point(camPos, opPos);
  529.         static float minDistSq = square(5.0f);
  530.         if (distSq > minDistSq)
  531.         {
  532.                 bool visible = GetISystem()->GetViewCamera().IsSphereVisible_F(Sphere(opPos, pPipeUser->GetRadius()));
  533.                 if (!visible)
  534.                 {
  535.                         float x = reqDir.Dot(myDir);
  536.                         float y = reqDir.Dot(Vec3(-myDir.y, myDir.x, 0.0f));
  537.                         // do it in steps to help physics resolve penetrations...
  538.                         float rotAngle = 0.02f * atan2f(y, x);
  539.                         Quat q;
  540.                         q.SetRotationAA(rotAngle, Vec3(0, 0, 1));
  541.  
  542.                         IEntity* pEntity = pPipeUser->GetEntity();
  543.                         Quat qCur = pEntity->GetRotation();
  544.                         pEntity->SetRotation(q * qCur);
  545.                         m_Maneuver = eMV_None;
  546.                         return;
  547.                 }
  548.         }
  549.  
  550.         // set the direction
  551.         Vec3 dirCross = myDir.Cross(reqDir);
  552.         m_ManeuverDir = dirCross.z > 0.0f ? eMVD_AntiClockwise : eMVD_Clockwise;
  553.  
  554.         bool movingFwd = myDir.Dot(myVel) > 0.0f;
  555.  
  556.         static float maneuverDistLimit = 5;
  557.  
  558.         // start a new maneuver?
  559.         if (m_Maneuver == eMV_None)
  560.         {
  561.                 m_Maneuver = eMV_Back;
  562.                 m_ManeuverDist = 0.5f * maneuverDistLimit;
  563.                 m_ManeuverTime = GetAISystem()->GetFrameStartTime();
  564.         }
  565.         else
  566.         {
  567.                 // reverse direction when we accumulate sufficient distance in the direction
  568.                 // we're supposed to be going in
  569.                 Vec3 delta = myPos - m_lastPosition;
  570.                 float dist = fabs(delta.Dot(myDir));
  571.                 if (movingFwd && m_Maneuver == eMV_Back)
  572.                         dist = 0.0f;
  573.                 else if (!movingFwd && m_Maneuver == eMV_Fwd)
  574.                         dist = 0.0f;
  575.                 m_ManeuverDist += dist;
  576.  
  577.                 if (manTimeMs > maneuverTimeMaxLimitMs)
  578.                 {
  579.                         m_Maneuver = m_Maneuver == eMV_Fwd ? eMV_Back : eMV_Fwd;
  580.                         m_ManeuverDist = 0.0f;
  581.                         m_ManeuverTime = now;
  582.                 }
  583.                 else if (m_Maneuver == eMV_Back)
  584.                 {
  585.                         if (fabsf(reqDir.Dot(myDir)) < cosf(DEG2RAD(85.0f)))
  586.                         {
  587.                                 m_Maneuver = eMV_Fwd;
  588.                                 m_ManeuverDist = 0.0f;
  589.                                 m_ManeuverTime = now;
  590.                         }
  591.                 }
  592.                 else
  593.                 {
  594.                         if (fabsf(reqDir.Dot(myDir)) > cosf(DEG2RAD(5.0f)))
  595.                         {
  596.                                 m_Maneuver = eMV_Back;
  597.                                 m_ManeuverDist = 0.0f;
  598.                                 m_ManeuverTime = now;
  599.                         }
  600.                 }
  601.  
  602.         }
  603.  
  604.         // now turn these into actual requests
  605.         float normalSpeed, minSpeed, maxSpeed;
  606.         pPipeUser->GetMovementSpeedRange(AISPEED_WALK, false, normalSpeed, minSpeed, maxSpeed);
  607.  
  608.         pPipeUser->m_State.fDesiredSpeed = minSpeed; //pPipeUser->GetManeuverMovementSpeed();
  609.         if (m_Maneuver == eMV_Back)
  610.                 pPipeUser->m_State.fDesiredSpeed = -5.0;
  611.  
  612.         Vec3 leftDir(-myDir.y, myDir.x, 0.0f);
  613.  
  614.         if (m_ManeuverDir == eMVD_AntiClockwise)
  615.                 pPipeUser->m_State.vMoveDir = leftDir;
  616.         else
  617.                 pPipeUser->m_State.vMoveDir = -leftDir;
  618.  
  619.         if (pPipeUser->m_State.fMovementUrgency < 0.0f)
  620.                 pPipeUser->m_State.vMoveDir *= -1.0f;
  621. }
  622.  
  623. //===================================================================
  624. // ExecutePreamble
  625. //===================================================================
  626. bool COPTrace::ExecutePreamble(CPipeUser* pPipeUser)
  627. {
  628.         CCCPOINT(COPTrace_ExecutePreamble);
  629.         FUNCTION_PROFILER(GetISystem(), PROFILE_AI);
  630.  
  631.         if (m_lastPosition.IsZero())
  632.                 m_lastPosition = pPipeUser->GetPhysicsPos();
  633.  
  634.         if (!m_refNavTarget.GetAIObject())
  635.         {
  636.                 if (pPipeUser->m_Path.Empty())
  637.                 {
  638.                         pPipeUser->m_State.fDesiredSpeed = 0.f;
  639.                         m_inhibitPathRegen = true;
  640.                 }
  641.                 else
  642.                 {
  643.                         // Obtain a NavTarget
  644.                         stack_string name("navTarget_");
  645.                         name += GetNameSafe(pPipeUser);
  646.  
  647.                         gAIEnv.pAIObjectManager->CreateDummyObject(m_refNavTarget, name, CAIObject::STP_REFPOINT);
  648.                         m_refNavTarget.GetAIObject()->SetPos(pPipeUser->GetPhysicsPos());
  649.  
  650.                         m_inhibitPathRegen = false;
  651.                 }
  652.         }
  653.         else
  654.         {
  655.                 m_inhibitPathRegen = false;
  656.         }
  657.  
  658.         return m_inhibitPathRegen;
  659. }
  660.  
  661. //===================================================================
  662. // ExecutePostamble
  663. //===================================================================
  664. bool COPTrace::ExecutePostamble(CPipeUser* pPipeUser, bool& reachedEnd, bool fullUpdate, bool b2D)
  665. {
  666.         FUNCTION_PROFILER(GetISystem(), PROFILE_AI);
  667.  
  668.         // do this after maneuver since that needs to track how far we moved
  669.         Vec3 opPos = pPipeUser->GetPhysicsPos();
  670.         m_fTravelDist += b2D ? Distance::Point_Point2D(opPos, m_lastPosition) : Distance::Point_Point(opPos, m_lastPosition);
  671.         m_lastPosition = opPos;
  672.  
  673.         SOBJECTSTATE& pipeUserState = pPipeUser->m_State;
  674.  
  675.         // only consider trace to be done once the agent has stopped.
  676.         if (reachedEnd && m_fEndAccuracy >= 0.f)
  677.         {
  678.                 Vec3 vel = pPipeUser->GetVelocity();
  679.                 vel.z = 0.f;
  680.                 float speed = vel.Dot(pipeUserState.vMoveDir);
  681.                 const float criticalSpeed = 0.01f;
  682.                 if (speed > criticalSpeed)
  683.                 {
  684.  
  685.                         if (gAIEnv.CVars.DebugPathFinding)
  686.                                 AILogAlways("COPTrace reached end but waiting for speed %5.2f to fall below %5.2f %s",
  687.                                             speed, criticalSpeed, GetNameSafe(pPipeUser));
  688.  
  689.                         reachedEnd = false;
  690.                         pipeUserState.fDesiredSpeed = 0.f;
  691.                         m_inhibitPathRegen = true;
  692.                 }
  693.         }
  694.  
  695.         // only consider trace to be done once the agent has stopped.
  696.         if (reachedEnd)
  697.         {
  698.                 pipeUserState.fDesiredSpeed = 0.f;
  699.                 m_inhibitPathRegen = true;
  700.                 return true;  // Trace finished
  701.         }
  702.  
  703.         // code below here checks/handles dynamic objects
  704.         if (pPipeUser->m_Path.GetParams().precalculatedPath)
  705.                 return false;
  706.  
  707.         return false;
  708. }
  709.  
  710. //===================================================================
  711. // ExecutePathFollower
  712. //===================================================================
  713. bool COPTrace::ExecutePathFollower(CPipeUser* pPipeUser, bool fullUpdate, IPathFollower* pPathFollower)
  714. {
  715.         FUNCTION_PROFILER(GetISystem(), PROFILE_AI);
  716.  
  717.         AIAssert(pPathFollower);
  718.         if (!pPathFollower)
  719.                 return true;
  720.  
  721.         if (m_TimeStep <= 0.f)
  722.                 return false;
  723.  
  724.         if (ExecutePreamble(pPipeUser))
  725.         {
  726.                 // Path empty, nav target nil, path regeneration inhibited, trace finished [6/5/2010 evgeny]
  727.                 return true;
  728.         }
  729.  
  730.         CCCPOINT(COPTrace_ExecutePathFollower);
  731.  
  732.         SOBJECTSTATE& pipeUserState = pPipeUser->m_State;
  733.  
  734.         float fNormalSpeed, fMinSpeed, fMaxSpeed;
  735.         pPipeUser->GetMovementSpeedRange(pipeUserState.fMovementUrgency, pipeUserState.allowStrafing,
  736.                                          fNormalSpeed, fMinSpeed, fMaxSpeed);
  737.  
  738.         // Update the path follower - really these things shouldn't change
  739.         // TODO: Leaving const_cast here it indicate how awful this is!
  740.         PathFollowerParams& params = const_cast<PathFollowerParams&>(pPathFollower->GetParams());
  741.         params.minSpeed = fMinSpeed;
  742.         params.maxSpeed = fMaxSpeed;
  743.         params.normalSpeed = clamp_tpl(fNormalSpeed, params.minSpeed, params.maxSpeed);
  744.  
  745.         params.endDistance = 0.f;
  746.  
  747.         bool bContinueMovingAtEnd = pPipeUser->m_Path.GetParams().continueMovingAtEnd;
  748.  
  749.         // [Mikko] Slight hack to make the formation following better.
  750.         // When following formation, the agent is often very close to the formation.
  751.         // This code forces the actor to lag a bit behind, which helps to follow the formation much more smoothly.
  752.         // TODO: Revive approach-at-distance without cutting the path and add that as extra parameter for stick.
  753.         if (bContinueMovingAtEnd && m_pendingActorTargetRequester == eTATR_None)
  754.         {
  755.                 CAIObject* pPathFindTarget = pPipeUser->m_refPathFindTarget.GetAIObject();
  756.                 if (pPathFindTarget && (pPathFindTarget->GetSubType() == IAIObject::STP_FORMATION))
  757.                 {
  758.                         params.endDistance = 1.f;
  759.                 }
  760.         }
  761.  
  762.         params.maxAccel = pPipeUser->m_movementAbility.maxAccel;
  763.         params.maxDecel = pPipeUser->m_movementAbility.maxDecel;
  764.         params.stopAtEnd = !bContinueMovingAtEnd;
  765.         params.isAllowedToShortcut = true;
  766.  
  767.         PathFollowResult result;
  768.  
  769.         PathFollowResult::TPredictedStates& predictedStates = s_tmpPredictedStates;
  770.  
  771.         // Lower the prediction calculations for puppets which have lo update priority (means invisible or distant).
  772.         bool highPriority;
  773.         if (CPuppet* pPuppet = pPipeUser->CastToCPuppet())
  774.         {
  775.                 EPuppetUpdatePriority ePuppetUpdatePriority = pPuppet->GetUpdatePriority();
  776.                 highPriority = (ePuppetUpdatePriority == AIPUP_VERY_HIGH) || (ePuppetUpdatePriority == AIPUP_HIGH);
  777.         }
  778.         else
  779.         {
  780.                 highPriority = true;
  781.         }
  782.  
  783.         const float PREDICTION_DELTA_TIME = 0.1f;
  784.         const float PREDICTION_TIME = 1.f;
  785.  
  786.         if (highPriority)
  787.         {
  788.                 result.desiredPredictionTime = PREDICTION_TIME;
  789.                 predictedStates.resize(size_t(PREDICTION_TIME / PREDICTION_DELTA_TIME + 0.5f));
  790.                 result.predictedStates = &predictedStates;
  791.         }
  792.         else
  793.         {
  794.                 result.desiredPredictionTime = 0.f;
  795.                 predictedStates.clear();
  796.                 result.predictedStates = 0;
  797.         }
  798.  
  799.         result.predictionDeltaTime = PREDICTION_DELTA_TIME;
  800.  
  801.         Vec3 curPos = pPipeUser->GetPhysicsPos();
  802.  
  803.         // If there's an animation in progress (typically SO playing)
  804.         bool runningSO = false;
  805.         if (m_actorTargetRequester == eTATR_NavSO)
  806.         {
  807.                 m_stuckDetector.Reset();
  808.  
  809.                 switch (pipeUserState.curActorTargetPhase)
  810.                 {
  811.                 case eATP_Playing:
  812.                 case eATP_Finished:
  813.                 case eATP_StartedAndFinished:
  814.                         // Path follow from the starting position of the path
  815.                         assert(!pipeUserState.curActorTargetFinishPos.IsZero());
  816.                         curPos = pipeUserState.curActorTargetFinishPos;
  817.                         runningSO = true;
  818.                         //pPipeUser->m_Path.GetPosAlongPath(curPos, 0.0f);
  819.                 }
  820.         }
  821.  
  822.         const Vec3 curVel = pPipeUser->GetVelocity();
  823.  
  824.         const bool targetReachable = pPathFollower->Update(result, curPos, curVel, m_TimeStep);
  825.  
  826.         const float distToEnd = pPathFollower->GetDistToEnd(&curPos);
  827.         //  if (m_stuckDetector.Update(distToEnd) == StuckDetector::UserIsStuck)
  828.         //  {
  829.         //    const CNavPath& path = pPipeUser->m_Path;
  830.         //
  831.         //    if (!path.Empty())
  832.         //    {
  833.         //      const Vec3& endPos = path.GetLastPathPos();
  834.         //
  835.         //      const bool playerIsLooking =
  836.         //        GetAISystem()->WouldHumanBeVisible(curPos, false) ||
  837.         //        GetAISystem()->WouldHumanBeVisible(endPos, false);
  838.         //
  839.         //      if (playerIsLooking)
  840.         //        StopMovement(pPipeUser);
  841.         //      else
  842.         //        Teleport(*pPipeUser, endPos);
  843.         //
  844.         //      return StillTracing;
  845.         //    }
  846.         //  }
  847.  
  848.         if (targetReachable)
  849.         {
  850.                 Vec3 desiredMoveDir = result.velocityOut;
  851.                 float desiredSpeed = desiredMoveDir.NormalizeSafe();
  852.  
  853.                 pipeUserState.fDesiredSpeed = desiredSpeed;
  854.                 pipeUserState.vMoveDir = desiredMoveDir;
  855.                 pipeUserState.fDistanceToPathEnd = distToEnd;
  856.  
  857.                 int num = min<int>(predictedStates.size(), SAIPredictedCharacterStates::maxStates);
  858.                 pipeUserState.predictedCharacterStates.nStates = num;
  859.                 for (int i = 0; i < num; ++i)
  860.                 {
  861.                         const PathFollowResult::SPredictedState& state = predictedStates[i];
  862.                         pipeUserState.predictedCharacterStates.states[i].Set(state.pos, state.vel, (1 + i) * PREDICTION_DELTA_TIME);
  863.                 }
  864.  
  865.                 // Precision movement support: A replacement for the old velocity based movement system above.
  866.                 // NOTE: If the move target and inflection point are equal (and non-zero) they mark the end of the path.
  867.                 pipeUserState.vMoveTarget = result.followTargetPos;
  868.                 pipeUserState.vInflectionPoint = result.inflectionPoint;
  869.  
  870.                 return ExecutePostamble(pPipeUser, result.reachedEnd, fullUpdate, params.use2D);
  871.         }
  872.         else
  873.         {
  874.                 if (!runningSO) // do not regenerate path while running SO
  875.                 {
  876.                         m_accumulatedFailureTime += gEnv->pTimer->GetFrameTime();
  877.  
  878.                         if (m_accumulatedFailureTime > 0.5f)
  879.                         {
  880.                                 m_accumulatedFailureTime = 0.0f;
  881.  
  882.                                 bool forceRegeneratePath = true;
  883.                                 RegeneratePath(pPipeUser, &forceRegeneratePath);
  884.                                 m_bWaitingForPathResult = true;
  885.                         }
  886.                 }
  887.  
  888.                 return StillTracing;
  889.         }
  890. }
  891.  
  892. //====================================================================
  893. // Execute2D
  894. //====================================================================
  895. bool COPTrace::Execute2D(CPipeUser* const pPipeUser, bool fullUpdate)
  896. {
  897.         if (ExecutePreamble(pPipeUser))
  898.                 return true;
  899.  
  900.         // input
  901.         Vec3 fwdDir = pPipeUser->GetMoveDir();
  902.         if (pPipeUser->m_State.fMovementUrgency < 0.0f)
  903.                 fwdDir *= -1.0f;
  904.         Vec3 opPos = pPipeUser->GetPhysicsPos();
  905.         pe_status_dynamics dSt;
  906.         pPipeUser->GetPhysics()->GetStatus(&dSt);
  907.         Vec3 opVel = m_Maneuver == eMV_None ? dSt.v : fwdDir * 5.0f;
  908.         float lookAhead = pPipeUser->m_movementAbility.pathLookAhead;
  909.         float pathRadius = pPipeUser->m_movementAbility.pathRadius;
  910.         bool resolveSticking = pPipeUser->m_movementAbility.resolveStickingInTrace;
  911.  
  912.         // output
  913.         Vec3 steerDir(ZERO);
  914.         float distToEnd = 0.0f;
  915.         float distToPath = 0.0f;
  916.         Vec3 pathDir(ZERO);
  917.         Vec3 pathAheadDir(ZERO);
  918.         Vec3 pathAheadPos(ZERO);
  919.  
  920.         bool isResolvingSticking = false;
  921.  
  922.         bool stillTracingPath = pPipeUser->m_Path.UpdateAndSteerAlongPath(
  923.           steerDir, distToEnd, distToPath, isResolvingSticking,
  924.           pathDir, pathAheadDir, pathAheadPos,
  925.           opPos, opVel, lookAhead, pathRadius, m_TimeStep, resolveSticking, true);
  926.         pPipeUser->m_State.fDistanceToPathEnd = max(0.0f, distToEnd);
  927.         pPipeUser->m_Path.GetDirectionToPathFromPoint(opPos, pPipeUser->m_State.vDirOffPath);
  928.  
  929.         pathAheadDir.z = 0.0f;
  930.         pathAheadDir.NormalizeSafe();
  931.         Vec3 steerDir2D(steerDir);
  932.         steerDir2D.z = 0.0f;
  933.         steerDir2D.NormalizeSafe();
  934.  
  935. #ifdef _DEBUG
  936.         // Update the debug movement reason.
  937.         pPipeUser->m_DEBUGmovementReason = CPipeUser::AIMORE_TRACE;
  938. #endif
  939.  
  940.         distToEnd -= /*m_fEndDistance*/ -pPipeUser->m_Path.GetDiscardedPathLength();
  941.         bool reachedEnd = false;
  942.         if (stillTracingPath && distToEnd > .1f)
  943.         {
  944.                 Vec3 targetPos;
  945.                 if (m_refNavTarget && pPipeUser->m_Path.GetPosAlongPath(targetPos, lookAhead, true, true))
  946.                         m_refNavTarget->SetPos(targetPos);
  947.  
  948.                 //turning maneuvering
  949.                 //FIXME: Investigate if this is necessary anymore with new smart path follower
  950.                 const bool doManeuver = (gAIEnv.configuration.eCompatibilityMode != ECCM_CRYSIS2);
  951.                 if (doManeuver)
  952.                         ExecuteManeuver(pPipeUser, steerDir);
  953.  
  954.                 if (m_Maneuver != eMV_None)
  955.                 {
  956.                         Vec3 curPos = pPipeUser->GetPhysicsPos();
  957.                         m_fTravelDist += Distance::Point_Point2D(curPos, m_lastPosition);
  958.                         m_lastPosition = curPos;
  959.                         // prevent path regen
  960.                         m_fTotalTracingTime = 0.0f;
  961.                         return false;
  962.                 }
  963.  
  964.                 //    float normalSpeed = pPipeUser->GetNormalMovementSpeed(pPipeUser->m_State.fMovementUrgency, true);
  965.                 //    float slowSpeed = pPipeUser->GetManeuverMovementSpeed();
  966.                 //    if (slowSpeed > normalSpeed) slowSpeed = normalSpeed;
  967.                 float normalSpeed, minSpeed, maxSpeed;
  968.                 pPipeUser->GetMovementSpeedRange(pPipeUser->m_State.fMovementUrgency, pPipeUser->m_State.allowStrafing, normalSpeed, minSpeed, maxSpeed);
  969.  
  970.                 // These will be adjusted to the range 0-1 to select a speed between slow and normal
  971.                 float dirSpeedMod = 1.0f;
  972.                 float curveSpeedMod = 1.0f;
  973.                 float endSpeedMod = 1.0f;
  974.                 float slopeMod = 1.0f;
  975.                 float moveDirMod = 1.0f;
  976.  
  977.                 // speed falloff - slow down if current direction is too different from desired
  978.                 if (pPipeUser->GetType() == AIOBJECT_VEHICLE)
  979.                 {
  980.                         static float offset = 1.0f; // if this is > 1 then there is a "window" where no slow-down occurs
  981.                         float velFalloff = offset * pathAheadDir.Dot(fwdDir);
  982.                         float velFalloffD = 1 - velFalloff;
  983.                         if (velFalloffD > 0.0f && pPipeUser->m_movementAbility.velDecay > 0.0f)
  984.                                 dirSpeedMod = velFalloff / (velFalloffD * pPipeUser->m_movementAbility.velDecay);
  985.                 }
  986.  
  987.                 // slow down due to the path curvature
  988.                 float lookAheadForSpeedControl;
  989.                 if (pPipeUser->m_movementAbility.pathSpeedLookAheadPerSpeed < 0.0f)
  990.                         lookAheadForSpeedControl = -pPipeUser->m_movementAbility.pathSpeedLookAheadPerSpeed * lookAhead * pPipeUser->m_State.fMovementUrgency;
  991.                 else
  992.                         lookAheadForSpeedControl = pPipeUser->m_movementAbility.pathSpeedLookAheadPerSpeed * pPipeUser->GetVelocity().GetLength();
  993.  
  994.                 if (lookAheadForSpeedControl > 0.0f)
  995.                 {
  996.                         Vec3 pos, dir;
  997.                         float lowestPathDot = 0.0f;
  998.                         bool curveOK = pPipeUser->m_Path.GetPathPropertiesAhead(lookAheadForSpeedControl, true, pos, dir, 0, lowestPathDot, true);
  999.                         Vec3 thisPathSegDir = (pPipeUser->m_Path.GetNextPathPoint()->vPos - pPipeUser->m_Path.GetPrevPathPoint()->vPos);
  1000.                         thisPathSegDir.z = 0.0f;
  1001.                         thisPathSegDir.NormalizeSafe();
  1002.                         float thisDot = thisPathSegDir.Dot(steerDir2D);
  1003.                         if (thisDot < lowestPathDot)
  1004.                                 lowestPathDot = thisDot;
  1005.                         if (curveOK)
  1006.                         {
  1007.                                 float a = 1.0f - 2.0f * pPipeUser->m_movementAbility.cornerSlowDown; // decrease this to make the speed drop off quicker with angle
  1008.                                 float b = 1.0f - a;
  1009.                                 curveSpeedMod = a + b * lowestPathDot;
  1010.                         }
  1011.  
  1012.                         // slow down at end
  1013.                         if (m_fEndAccuracy >= 0.0f && m_eTraceEndMode != eTEM_MinimumDistance)
  1014.                         {
  1015.                                 static float slowDownDistScale = 2.0f;
  1016.                                 static float minEndSpeedMod = 0.1f;
  1017.                                 float slowDownDist = slowDownDistScale * lookAheadForSpeedControl;
  1018.                                 float workingDistToEnd = m_fEndAccuracy + distToEnd - 0.2f * lookAheadForSpeedControl;
  1019.                                 if (slowDownDist > 0.1f && workingDistToEnd < slowDownDist)
  1020.                                 {
  1021.                                         endSpeedMod = workingDistToEnd / slowDownDist;
  1022.                                         Limit(endSpeedMod, minEndSpeedMod, 1.0f);
  1023.                                 }
  1024.                         }
  1025.                 }
  1026.  
  1027.                 float slopeModCoeff = pPipeUser->m_movementAbility.slopeSlowDown;
  1028.                 // slow down when going down steep slopes (especially stairs!)
  1029.                 int buildingID = -1;
  1030.                 if ((slopeModCoeff > 0) &&
  1031.                     (gAIEnv.pNavigation->CheckNavigationType(pPipeUser->GetPos(), buildingID,
  1032.                                                              pPipeUser->GetMovementAbility().pathfindingProperties.navCapMask) == IAISystem::NAV_WAYPOINT_HUMAN))
  1033.                 {
  1034.                         static float slowDownSlope = 0.5f;
  1035.                         float pathHorDist = steerDir.GetLength2D();
  1036.                         if (pathHorDist > 0.0f && steerDir.z < 0.0f)
  1037.                         {
  1038.                                 float slope = -steerDir.z / pathHorDist * slopeModCoeff;
  1039.                                 slopeMod = 1.0f - slope / slowDownSlope;
  1040.                                 static float minSlopeMod = 0.5f;
  1041.                                 Limit(slopeMod, minSlopeMod, 1.0f);
  1042.                         }
  1043.                 }
  1044.  
  1045.                 // slow down when going up steep slopes
  1046.                 if (slopeModCoeff > 0)
  1047.                 {
  1048.                         IPhysicalEntity* pPhysics = pPipeUser->GetPhysics();
  1049.                         pe_status_living status;
  1050.                         int valid = pPhysics->GetStatus(&status);
  1051.                         if (valid)
  1052.                         {
  1053.                                 if (!status.bFlying)
  1054.                                 {
  1055.                                         Vec3 sideDir(-steerDir2D.y, steerDir2D.x, 0.0f);
  1056.                                         Vec3 slopeN = status.groundSlope - status.groundSlope.Dot(sideDir) * sideDir;
  1057.                                         slopeN.NormalizeSafe();
  1058.                                         // d is -ve for uphill
  1059.                                         float d = steerDir2D.Dot(status.groundSlope);
  1060.                                         Limit(d, -0.99f, 0.99f);
  1061.                                         // map d=-1 -> -inf, d=0 -> 1, d=1 -> inf
  1062.                                         float uphillSlopeMod = (1 + d / (1.0f - square(d))) * slopeModCoeff;
  1063.                                         static float minUphillSlopeMod = 0.5f;
  1064.                                         if (uphillSlopeMod < minUphillSlopeMod)
  1065.                                                 uphillSlopeMod = minUphillSlopeMod;
  1066.                                         if (uphillSlopeMod < 1.0f)
  1067.                                                 slopeMod = min(slopeMod, uphillSlopeMod);
  1068.                                 }
  1069.                         }
  1070.                 }
  1071.  
  1072.                 float maxMod = min(min(min(min(dirSpeedMod, curveSpeedMod), endSpeedMod), slopeMod), moveDirMod);
  1073.                 Limit(maxMod, 0.0f, 1.0f);
  1074.                 //    maxMod = pow(maxMod, 2.0f);
  1075.  
  1076.                 if (m_bControlSpeed == true)
  1077.                 {
  1078.                         float newDesiredSpeed = (1.0f - maxMod) * minSpeed + maxMod * normalSpeed;
  1079.  
  1080.                         float change = newDesiredSpeed - pPipeUser->m_State.fDesiredSpeed;
  1081.                         if (change > m_TimeStep * pPipeUser->m_movementAbility.maxAccel)
  1082.                                 change = m_TimeStep * pPipeUser->m_movementAbility.maxAccel;
  1083.                         else if (change < -m_TimeStep * pPipeUser->m_movementAbility.maxDecel)
  1084.                                 change = -m_TimeStep * pPipeUser->m_movementAbility.maxDecel;
  1085.                         pPipeUser->m_State.fDesiredSpeed += change;
  1086.                 }
  1087.  
  1088.                 pPipeUser->m_State.vMoveDir = steerDir2D;
  1089.                 if (pPipeUser->m_State.fMovementUrgency < 0.0f)
  1090.                         pPipeUser->m_State.vMoveDir *= -1.0f;
  1091.  
  1092.                 // prediction
  1093.                 //    static bool doPrediction = true;
  1094.                 pPipeUser->m_State.predictedCharacterStates.nStates = 0;
  1095.         }
  1096.         else
  1097.         {
  1098.                 reachedEnd = true;
  1099.         }
  1100.  
  1101.         return ExecutePostamble(pPipeUser, reachedEnd, fullUpdate, true);
  1102. }
  1103.  
  1104. //====================================================================
  1105. // Execute3D
  1106. //====================================================================
  1107. bool COPTrace::Execute3D(CPipeUser* pPipeUser, bool fullUpdate)
  1108. {
  1109.         FUNCTION_PROFILER(GetISystem(), PROFILE_AI);
  1110.  
  1111.         if (ExecutePreamble(pPipeUser))
  1112.                 return true;
  1113.  
  1114.         // Ideally do this check less... but beware we might regen the path and the end might change a bit(?)
  1115.         if (fullUpdate)
  1116.         {
  1117.                 if (pPipeUser->GetType() == AIOBJECT_VEHICLE && m_fEndAccuracy == 0.0f && !pPipeUser->m_Path.GetPath().empty())
  1118.                 {
  1119.                         Vec3 endPt = pPipeUser->m_Path.GetPath().back().vPos;
  1120.                         // ideally we would use AICE_ALL here, but that can result in intersection with the heli when it
  1121.                         // gets to the end of the path...
  1122.                         bool gotFloor = GetFloorPos(m_landingPos, endPt, 0.5f, 1.0f, 1.0f, AICE_STATIC);
  1123.                         if (gotFloor)
  1124.                                 m_landHeight = 2.0f;
  1125.                         else
  1126.                                 m_landHeight = 0.0f;
  1127.                         if (m_workingLandingHeightOffset > 0.0f)
  1128.                                 m_inhibitPathRegen = true;
  1129.                 }
  1130.                 else
  1131.                 {
  1132.                         m_landHeight = 0.0f;
  1133.                         m_inhibitPathRegen = false;
  1134.                 }
  1135.         }
  1136.  
  1137.         // input
  1138.         Vec3 opPos = pPipeUser->GetPhysicsPos();
  1139.         Vec3 fakeOpPos = opPos;
  1140.         fakeOpPos.z -= m_workingLandingHeightOffset;
  1141.         if (pPipeUser->m_IsSteering)
  1142.                 fakeOpPos.z -= pPipeUser->m_flightSteeringZOffset;
  1143.  
  1144.         pe_status_dynamics dSt;
  1145.         pPipeUser->GetPhysics()->GetStatus(&dSt);
  1146.         Vec3 opVel = dSt.v;
  1147.         float lookAhead = pPipeUser->m_movementAbility.pathLookAhead;
  1148.         float pathRadius = pPipeUser->m_movementAbility.pathRadius;
  1149.         bool resolveSticking = pPipeUser->m_movementAbility.resolveStickingInTrace;
  1150.  
  1151.         // output
  1152.         Vec3 steerDir(ZERO);
  1153.         float distToEnd = 0.0f;
  1154.         float distToPath = 0.0f;
  1155.         Vec3 pathDir(ZERO);
  1156.         Vec3 pathAheadDir(ZERO);
  1157.         Vec3 pathAheadPos(ZERO);
  1158.  
  1159.         bool isResolvingSticking = false;
  1160.  
  1161.         bool stillTracingPath = pPipeUser->m_Path.UpdateAndSteerAlongPath(steerDir, distToEnd, distToPath, isResolvingSticking,
  1162.                                                                           pathDir, pathAheadDir, pathAheadPos,
  1163.                                                                           fakeOpPos, opVel, lookAhead, pathRadius, m_TimeStep, resolveSticking, false);
  1164.         pPipeUser->m_State.fDistanceToPathEnd = max(0.0f, distToEnd);
  1165.  
  1166. #ifdef _DEBUG
  1167.         // Update the debug movement reason.
  1168.         pPipeUser->m_DEBUGmovementReason = CPipeUser::AIMORE_TRACE;
  1169. #endif
  1170.  
  1171.         distToEnd -= distToPath;
  1172.         distToEnd -= m_landHeight * 2.0f;
  1173.         if (distToEnd < 0.0f)
  1174.                 stillTracingPath = false;
  1175.  
  1176.         if (!stillTracingPath && m_landHeight > 0.0f)
  1177.         {
  1178.                 return ExecuteLanding(pPipeUser, m_landingPos);
  1179.         }
  1180.  
  1181.         distToEnd -= /*m_fEndDistance*/ -pPipeUser->m_Path.GetDiscardedPathLength();
  1182.         bool reachedEnd = !stillTracingPath;
  1183.         if (stillTracingPath && distToEnd > 0.0f)
  1184.         {
  1185.                 Vec3 targetPos;
  1186.                 if (m_refNavTarget && pPipeUser->m_Path.GetPosAlongPath(targetPos, lookAhead, true, true))
  1187.                         m_refNavTarget->SetPos(targetPos);
  1188.  
  1189.                 //    float normalSpeed = pPipeUser->GetNormalMovementSpeed(pPipeUser->m_State.fMovementUrgency, true);
  1190.                 //    float slowSpeed = pPipeUser->GetManeuverMovementSpeed();
  1191.                 //    if (slowSpeed > normalSpeed) slowSpeed = normalSpeed;
  1192.                 float normalSpeed, minSpeed, maxSpeed;
  1193.                 pPipeUser->GetMovementSpeedRange(pPipeUser->m_State.fMovementUrgency, pPipeUser->m_State.allowStrafing, normalSpeed, minSpeed, maxSpeed);
  1194.  
  1195.                 // These will be adjusted to the range 0-1 to select a speed between slow and normal
  1196.                 float dirSpeedMod = 1.0f;
  1197.                 float curveSpeedMod = 1.0f;
  1198.                 float endSpeedMod = 1.0f;
  1199.                 float moveDirMod = 1.0f;
  1200.  
  1201.                 // slow down due to the path curvature
  1202.                 float lookAheadForSpeedControl;
  1203.                 if (pPipeUser->m_movementAbility.pathSpeedLookAheadPerSpeed < 0.0f)
  1204.                         lookAheadForSpeedControl = lookAhead * pPipeUser->m_State.fMovementUrgency;
  1205.                 else
  1206.                         lookAheadForSpeedControl = pPipeUser->m_movementAbility.pathSpeedLookAheadPerSpeed * pPipeUser->GetVelocity().GetLength();
  1207.  
  1208.                 lookAheadForSpeedControl -= distToPath;
  1209.                 if (lookAheadForSpeedControl < 0.0f)
  1210.                         lookAheadForSpeedControl = 0.0f;
  1211.  
  1212.                 if (lookAheadForSpeedControl > 0.0f)
  1213.                 {
  1214.                         Vec3 pos, dir;
  1215.                         float lowestPathDot = 0.0f;
  1216.                         bool curveOK = pPipeUser->m_Path.GetPathPropertiesAhead(lookAheadForSpeedControl, true, pos, dir, 0, lowestPathDot, true);
  1217.                         Vec3 thisPathSegDir = (pPipeUser->m_Path.GetNextPathPoint()->vPos - pPipeUser->m_Path.GetPrevPathPoint()->vPos).GetNormalizedSafe();
  1218.                         float thisDot = thisPathSegDir.Dot(steerDir);
  1219.                         if (thisDot < lowestPathDot)
  1220.                                 lowestPathDot = thisDot;
  1221.                         if (curveOK)
  1222.                         {
  1223.                                 float a = 1.0f - 2.0f * pPipeUser->m_movementAbility.cornerSlowDown; // decrease this to make the speed drop off quicker with angle
  1224.                                 float b = 1.0f - a;
  1225.                                 curveSpeedMod = a + b * lowestPathDot;
  1226.                         }
  1227.                 }
  1228.  
  1229.                 // slow down at end
  1230.                 if (m_fEndAccuracy >= 0.0f)
  1231.                 {
  1232.                         static float slowDownDistScale = 1.0f;
  1233.                         float slowDownDist = slowDownDistScale * lookAheadForSpeedControl;
  1234.                         float workingDistToEnd = m_fEndAccuracy + distToEnd - 0.2f * lookAheadForSpeedControl;
  1235.                         if (slowDownDist > 0.1f && workingDistToEnd < slowDownDist)
  1236.                         {
  1237.                                 // slow speeds are for manouevering - here we want something that will actually be almost stationary
  1238.                                 minSpeed *= 0.1f;
  1239.                                 endSpeedMod = workingDistToEnd / slowDownDist;
  1240.                                 Limit(endSpeedMod, 0.0f, 1.0f);
  1241.                                 m_workingLandingHeightOffset = (1.0f - endSpeedMod) * m_landHeight;
  1242.                         }
  1243.                         else
  1244.                         {
  1245.                                 m_workingLandingHeightOffset = 0.0f;
  1246.                         }
  1247.                 }
  1248.  
  1249.                 float maxMod = min(min(min(dirSpeedMod, curveSpeedMod), endSpeedMod), moveDirMod);
  1250.                 Limit(maxMod, 0.0f, 1.0f);
  1251.  
  1252.                 float newDesiredSpeed = (1.0f - maxMod) * minSpeed + maxMod * normalSpeed;
  1253.                 float change = newDesiredSpeed - pPipeUser->m_State.fDesiredSpeed;
  1254.                 if (change > m_TimeStep * pPipeUser->m_movementAbility.maxAccel)
  1255.                         change = m_TimeStep * pPipeUser->m_movementAbility.maxAccel;
  1256.                 else if (change < -m_TimeStep * pPipeUser->m_movementAbility.maxDecel)
  1257.                         change = -m_TimeStep * pPipeUser->m_movementAbility.maxDecel;
  1258.                 pPipeUser->m_State.fDesiredSpeed += change;
  1259.  
  1260.                 pPipeUser->m_State.vMoveDir = steerDir;
  1261.                 if (pPipeUser->m_State.fMovementUrgency < 0.0f)
  1262.                         pPipeUser->m_State.vMoveDir *= -1.0f;
  1263.  
  1264.                 // prediction
  1265.                 //    static bool doPrediction = true;
  1266.                 pPipeUser->m_State.predictedCharacterStates.nStates = 0;
  1267.         }
  1268.         else
  1269.         {
  1270.                 reachedEnd = true;
  1271.         }
  1272.  
  1273.         return ExecutePostamble(pPipeUser, reachedEnd, fullUpdate, false);
  1274. }
  1275.  
  1276. //===================================================================
  1277. // ExecuteLanding
  1278. //===================================================================
  1279. bool COPTrace::ExecuteLanding(CPipeUser* pPipeUser, const Vec3& pathEnd)
  1280. {
  1281.         m_inhibitPathRegen = true;
  1282.         float normalSpeed, minSpeed, maxSpeed;
  1283.         pPipeUser->GetMovementSpeedRange(pPipeUser->m_State.fMovementUrgency, false, normalSpeed, minSpeed, maxSpeed);
  1284.         //  float slowSpeed = pPipeUser->GetManeuverMovementSpeed();
  1285.         Vec3 opPos = pPipeUser->GetPhysicsPos();
  1286.  
  1287.         Vec3 horMoveDir = pathEnd - opPos;
  1288.         horMoveDir.z = 0.0f;
  1289.         float error = horMoveDir.NormalizeSafe();
  1290.  
  1291.         Limit(error, 0.0f, 1.0f);
  1292.         float horSpeed = 0.3f * minSpeed * error;
  1293.         float verSpeed = 1.0f;
  1294.  
  1295.         pPipeUser->m_State.vMoveDir = horSpeed * horMoveDir - Vec3(0, 0, verSpeed);
  1296.         pPipeUser->m_State.vMoveDir.NormalizeSafe();
  1297.         pPipeUser->m_State.fDesiredSpeed = sqrtf(square(horSpeed) + square(verSpeed));
  1298.  
  1299.         if (pPipeUser->m_State.fMovementUrgency < 0.0f)
  1300.                 pPipeUser->m_State.vMoveDir *= -1.0f;
  1301.  
  1302.         // set look dir
  1303.         if (m_landingDir.IsZero())
  1304.         {
  1305.  
  1306.                 if (gAIEnv.CVars.DebugPathFinding)
  1307.                         AILogAlways("COPTrace::ExecuteLanding starting final landing %s", GetNameSafe(pPipeUser));
  1308.  
  1309.                 m_landingDir = pPipeUser->GetMoveDir();
  1310.                 m_landingDir.z = 0.0f;
  1311.                 m_landingDir.NormalizeSafe(Vec3Constants<float>::fVec3_OneX);
  1312.         }
  1313.         Vec3 navTargetPos = opPos + 100.0f * m_landingDir;
  1314.         m_refNavTarget->SetPos(navTargetPos);
  1315.  
  1316.         if (!pPipeUser->m_bLooseAttention)
  1317.         {
  1318.                 m_looseAttentionId = pPipeUser->SetLooseAttentionTarget(m_refNavTarget);
  1319.         }
  1320.  
  1321.         //
  1322.         pe_status_collisions stat;
  1323.         stat.pHistory = 0;
  1324.         int collisions = pPipeUser->GetPhysics()->GetStatus(&stat);
  1325.         if (collisions > 0)
  1326.                 return true;
  1327.         else
  1328.                 return false;
  1329. }
  1330.  
  1331. //===================================================================
  1332. // DebugDraw
  1333. //===================================================================
  1334. void COPTrace::DebugDraw(CPipeUser* pPipeUser) const
  1335. {
  1336.         if (IsPathRegenerationInhibited())
  1337.         {
  1338.                 CDebugDrawContext dc;
  1339.                 dc->Draw3dLabel(pPipeUser->GetPhysicsPos(), 1.5f, "PATH LOCKED\n%s %s",
  1340.                                 m_inhibitPathRegen ? "Inhibit" : "", m_passingStraightNavSO ? "NavSO" : "");
  1341.         }
  1342. }
  1343.  
  1344. void COPTrace::ExecuteTraceDebugDraw(CPipeUser* pPipeUser)
  1345. {
  1346.         if (gAIEnv.CVars.DebugPathFinding)
  1347.         {
  1348.                 if (IAIDebugRenderer* pRenderer = gAIEnv.GetDebugRenderer())
  1349.                 {
  1350.                         if (m_bWaitingForPathResult)
  1351.                         {
  1352.                                 pRenderer->DrawSphere(pPipeUser->GetPos() + Vec3(0, 0, 1.f), .5f, ColorB(255, 255, 0));
  1353.                         }
  1354.  
  1355.                         if (m_bWaitingForBusySmartObject)
  1356.                         {
  1357.                                 pRenderer->DrawSphere(pPipeUser->GetPos() + Vec3(0, 0, 1.2f), .5f, ColorB(255, 0, 0));
  1358.                         }
  1359.                 }
  1360.         }
  1361. }
  1362.  
  1363. bool COPTrace::HandleAnimationPhase(CPipeUser* pPipeUser, bool bFullUpdate, bool* pbForceRegeneratePath, bool* pbExactPositioning, bool* pbTraceFinished)
  1364. {
  1365.         SOBJECTSTATE& pipeUserState = pPipeUser->m_State;
  1366.  
  1367.         switch (pipeUserState.curActorTargetPhase)
  1368.         {
  1369.         case eATP_Error:
  1370.                 {
  1371.                         if (m_actorTargetRequester == eTATR_None)
  1372.                         {
  1373.                                 m_actorTargetRequester = m_pendingActorTargetRequester;
  1374.                                 m_pendingActorTargetRequester = eTATR_None;
  1375.                         }
  1376.  
  1377.                         switch (m_actorTargetRequester)
  1378.                         {
  1379.                         case eTATR_EndOfPath:
  1380.  
  1381.                                 if (gAIEnv.CVars.DebugPathFinding)
  1382.                                         AILogAlways("COPTrace::ExecuteTrace resetting since error occurred during exact positioning %s", GetNameSafe(pPipeUser));
  1383.  
  1384.                                 if (bFullUpdate)
  1385.                                 {
  1386.                                         Reset(pPipeUser);
  1387.                                 }
  1388.                                 else
  1389.                                 {
  1390.                                         // TODO: Handle better the error case!
  1391.                                         StopMovement(pPipeUser);
  1392.                                         m_bBlock_ExecuteTrace_untilFullUpdateThenReset = true;
  1393.                                 }
  1394.                                 *pbTraceFinished = true;
  1395.                                 return false;
  1396.  
  1397.                         case eTATR_NavSO:
  1398.                                 // Exact positioning has been failed at navigation smart object, regenerate path.
  1399.                                 *pbForceRegeneratePath = true;
  1400.                                 m_inhibitPathRegen = false;
  1401.                                 break;
  1402.                         }
  1403.  
  1404.                         m_actorTargetRequester = eTATR_None;
  1405.                         m_pendingActorTargetRequester = eTATR_None;
  1406.                 }
  1407.                 // END eATP_Error
  1408.                 break;
  1409.  
  1410.         case eATP_Waiting:
  1411.                 *pbExactPositioning = true;
  1412.                 break;
  1413.  
  1414.         case eATP_Playing:
  1415.                 // While playing, keep the trace & prediction running.
  1416.                 *pbExactPositioning = true;
  1417.  
  1418.                 // Resurrect any remaining path section while we're playing the animation.
  1419.                 // This allows path following to continue based on the next path's start position.
  1420.                 pPipeUser->m_Path.ResurrectRemainingPath();
  1421.                 break;
  1422.  
  1423.         case eATP_Starting:
  1424.         case eATP_Started:
  1425.                 *pbExactPositioning = true;
  1426.  
  1427.                 if (m_pendingActorTargetRequester != eTATR_None)
  1428.                 {
  1429.                         m_actorTargetRequester = m_pendingActorTargetRequester;
  1430.                         m_pendingActorTargetRequester = eTATR_None;
  1431.                 }
  1432.  
  1433.                 if (m_stopOnAnimationStart && m_actorTargetRequester == eTATR_EndOfPath)
  1434.                 {
  1435.                         if (bFullUpdate)
  1436.                         {
  1437.                                 Reset(pPipeUser);
  1438.                         }
  1439.                         else
  1440.                         {
  1441.                                 StopMovement(pPipeUser);
  1442.                                 m_bBlock_ExecuteTrace_untilFullUpdateThenReset = true;
  1443.                         }
  1444.                         *pbTraceFinished = true;
  1445.                         return false;
  1446.                 }
  1447.                 break;
  1448.  
  1449.         case eATP_Finished:
  1450.         case eATP_StartedAndFinished:
  1451.                 switch (m_actorTargetRequester)
  1452.                 {
  1453.                 case eTATR_EndOfPath:
  1454.                         m_actorTargetRequester = eTATR_None;
  1455.                         // Exact positioning has been finished at the end of the path, the trace is completed.
  1456.  
  1457.                         if (gAIEnv.CVars.DebugPathFinding)
  1458.                                 AILogAlways("COPTrace::ExecuteTrace resetting since exact position reached/animation finished %s", GetNameSafe(pPipeUser));
  1459.  
  1460.                         if (bFullUpdate)
  1461.                         {
  1462.                                 Reset(pPipeUser);
  1463.                         }
  1464.                         else
  1465.                         {
  1466.                                 StopMovement(pPipeUser);
  1467.                                 m_bBlock_ExecuteTrace_untilFullUpdateThenReset = true;
  1468.                         }
  1469.                         *pbTraceFinished = true;
  1470.                         return false;
  1471.  
  1472.                 case eTATR_NavSO:
  1473.                         {
  1474.                                 // Exact positioning and animation has been finished at navigation smart object, resurrect path.
  1475.                                 pPipeUser->m_State.fDistanceToPathEnd = pPipeUser->m_Path.GetDiscardedPathLength();
  1476.                                 pPipeUser->m_Path.ResurrectRemainingPath();
  1477.                                 pPipeUser->m_Path.PrepareNavigationalSmartObjectsForMNM(pPipeUser);
  1478.                                 pPipeUser->AdjustPath();
  1479.                                 *pbForceRegeneratePath = false;
  1480.  
  1481.                                 m_actorTargetRequester = eTATR_None;
  1482.                                 m_prevFrameStartTime.SetValue(0ll);
  1483.  
  1484.                                 // Update distance traveled during the exact-pos anim.
  1485.                                 Vec3 opPos = pPipeUser->GetPhysicsPos();
  1486.                                 m_fTravelDist += !pPipeUser->IsUsing3DNavigation() ?
  1487.                                                  Distance::Point_Point2D(opPos, m_lastPosition) : Distance::Point_Point(opPos, m_lastPosition);
  1488.                                 m_lastPosition = opPos;
  1489.  
  1490.                                 m_bWaitingForPathResult = false;
  1491.                                 m_inhibitPathRegen = true;
  1492.                         }
  1493.                         break;
  1494.  
  1495.                 default:
  1496.                         // A pending exact positioning request, maybe from previously interrupted trace.
  1497.                         // Regenerate path, since the current path may be bogus because it was generated
  1498.                         // before the animation had finished.
  1499.                         *pbForceRegeneratePath = true;
  1500.                         m_actorTargetRequester = eTATR_None;
  1501.                         m_bWaitingForPathResult = true;
  1502.                         m_bWaitingForBusySmartObject = false;
  1503.                         m_inhibitPathRegen = false;
  1504.                 }
  1505.                 // END eATP_Finished & eATP_StartedAndFinished:
  1506.                 break;
  1507.         }
  1508.  
  1509.         return true;
  1510. }
  1511.  
  1512. bool COPTrace::HandlePathResult(CPipeUser* pPipeUser, bool* pbReturnValue)
  1513. {
  1514.         switch (pPipeUser->m_nPathDecision)
  1515.         {
  1516.         case PATHFINDER_PATHFOUND:
  1517.                 // Path found, continue.
  1518.                 m_bWaitingForPathResult = false;
  1519.                 return true;
  1520.  
  1521.         case PATHFINDER_NOPATH:
  1522.                 // Could not find path, fail.
  1523.                 m_bWaitingForPathResult = false;
  1524.                 m_bBlock_ExecuteTrace_untilFullUpdateThenReset = true;
  1525.                 *pbReturnValue = true;
  1526.                 return false;
  1527.  
  1528.         default:
  1529.                 // Wait for the path finder result, disable movement and wait.
  1530.                 StopMovement(pPipeUser);
  1531.                 *pbReturnValue = false;
  1532.                 return false;
  1533.         }
  1534. }
  1535.  
  1536. bool COPTrace::IsVehicleAndDriverIsFallen(CPipeUser* pPipeUser)
  1537. {
  1538.         if (pPipeUser->GetType() == AIOBJECT_VEHICLE)
  1539.         {
  1540.                 // Check if the vehicle driver is tranq'd and do not move if it is.
  1541.                 if (EntityId driverId = pPipeUser->GetProxy()->GetLinkedDriverEntityId())
  1542.                 {
  1543.                         if (IEntity* pDriverEntity = gEnv->pEntitySystem->GetEntity(driverId))
  1544.                         {
  1545.                                 if (IAIObject* pDriverAI = pDriverEntity->GetAI())
  1546.                                 {
  1547.                                         if (CAIActor* pDriverActor = pDriverAI->CastToCAIActor())
  1548.                                         {
  1549.                                                 if (IAIActorProxy* pDriverProxy = pDriverActor->GetProxy())
  1550.                                                 {
  1551.                                                         if (pDriverProxy->GetActorIsFallen())
  1552.                                                         {
  1553.                                                                 // The driver is unable to drive, do not drive.
  1554.                                                                 StopMovement(pPipeUser);
  1555.                                                                 return true;
  1556.                                                         }
  1557.                                                 }
  1558.                                         }
  1559.                                 }
  1560.                         }
  1561.                 }
  1562.         }
  1563.  
  1564.         return false;
  1565. }
  1566.  
  1567. void COPTrace::RegeneratePath(CPipeUser* pPipeUser, bool* pbForceRegeneratePath)
  1568. {
  1569.         gEnv->pAISystem->LogComment("COPTrace::RegeneratePath", "Currently regenerate the path in the GoalOp trace is not supported by the MNM Navigation System.");
  1570. }
  1571.  
  1572. void COPTrace::StopMovement(CPipeUser* pPipeUser)
  1573. {
  1574.         SOBJECTSTATE& pipeUserState = pPipeUser->m_State;
  1575.  
  1576.         pipeUserState.vMoveDir.zero();
  1577.         pipeUserState.fDesiredSpeed = 0.f;
  1578.         pipeUserState.predictedCharacterStates.nStates = 0;
  1579. }
  1580.  
  1581. void COPTrace::TriggerExactPositioning(CPipeUser* pPipeUser, bool* pbForceRegeneratePath, bool* pbExactPositioning)
  1582. {
  1583.         SOBJECTSTATE& pipeUserState = pPipeUser->m_State;
  1584.         SAIActorTargetRequest& pipeUserActorTargetRequest = pipeUserState.actorTargetReq;
  1585.  
  1586.         switch (pipeUserState.curActorTargetPhase)
  1587.         {
  1588.         case eATP_None:
  1589.                 {
  1590.                         if (gAIEnv.CVars.DebugPathFinding)
  1591.                         {
  1592.                                 SNavSOStates& pipeUserPendingNavSOStates = pPipeUser->m_pendingNavSOStates;
  1593.                                 if (!pipeUserPendingNavSOStates.IsEmpty())
  1594.                                 {
  1595.                                         IEntity* pEntity = gEnv->pEntitySystem->GetEntity(pipeUserPendingNavSOStates.objectEntId);
  1596.                                         if (pEntity)
  1597.                                         {
  1598.                                                 AILogAlways("COPTrace::ExecuteTrace %s trying to use exact positioning while a navSO (entity=%s) is still active.",
  1599.                                                             GetNameSafe(pPipeUser), pEntity->GetName());
  1600.                                         }
  1601.                                         else
  1602.                                         {
  1603.                                                 AILogAlways("COPTrace::ExecuteTrace %s trying to use exact positioning while a navSO (entityId=%d) is still active.",
  1604.                                                             GetNameSafe(pPipeUser), pipeUserPendingNavSOStates.objectEntId);
  1605.                                         }
  1606.                                 }
  1607.                         }
  1608.  
  1609.                         // Handle the exact positioning request
  1610.                         const PathPointDescriptor::OffMeshLinkData* pSmartObjectMNMData = pPipeUser->m_Path.GetLastPathPointMNNSOData();
  1611.                         const bool smartObject = (pSmartObjectMNMData && pSmartObjectMNMData->offMeshLinkID != MNM::Constants::eOffMeshLinks_InvalidOffMeshLinkID);
  1612.  
  1613.                         if (smartObject)
  1614.                         {
  1615.                                 MNM::OffMeshLink* pOffMeshLink = gAIEnv.pNavigationSystem->GetOffMeshNavigationManager()->GetOffMeshLink(pSmartObjectMNMData->offMeshLinkID);
  1616.                                 OffMeshLink_SmartObject* pSOLink = pOffMeshLink ? pOffMeshLink->CastTo<OffMeshLink_SmartObject>() : NULL;
  1617.  
  1618.                                 assert(pSOLink);
  1619.                                 if (pSOLink)
  1620.                                 {
  1621.                                         CSmartObjectManager* pSmartObjectManager = gAIEnv.pSmartObjectManager;
  1622.                                         CSmartObject* pSmartObject = pSOLink->m_pSmartObject;
  1623.  
  1624.                                         const EntityId smartObjectId = pSmartObject->GetEntityId();
  1625.  
  1626.                                         // If the smart object isn't busy
  1627.                                         if (pSmartObjectManager->IsSmartObjectBusy(pSmartObject))
  1628.                                         {
  1629.                                                 // Attempt to wait for the SO to become free
  1630.                                                 m_bWaitingForBusySmartObject = true;
  1631.                                         }
  1632.                                         else
  1633.                                         {
  1634.                                                 const Vec3 smartObjectStart = pSmartObject->GetHelperPos(pSOLink->m_pFromHelper);
  1635.                                                 CAIActor* closestActor = pPipeUser->CastToCAIActor();
  1636.  
  1637.                                                 // Find the closest of all actors trying to use this SmartObject
  1638.                                                 {
  1639.                                                         ActorLookUp& lookUp = *gAIEnv.pActorLookUp;
  1640.                                                         size_t activeCount = lookUp.GetActiveCount();
  1641.  
  1642.                                                         float distanceClosestSq = Distance::Point_PointSq(closestActor->GetPos(), smartObjectStart);
  1643.  
  1644.                                                         for (size_t actorIndex = 0; actorIndex < activeCount; ++actorIndex)
  1645.                                                         {
  1646.                                                                 const Vec3 position = lookUp.GetPosition(actorIndex);
  1647.                                                                 const float distanceSq = Distance::Point_PointSq(position, smartObjectStart);
  1648.  
  1649.                                                                 if (distanceSq < distanceClosestSq)
  1650.                                                                 {
  1651.                                                                         if (CPipeUser* closerActor = lookUp.GetActor<CPipeUser>(actorIndex))
  1652.                                                                         {
  1653.                                                                                 if (closerActor->GetPendingSmartObjectID() == smartObjectId)
  1654.                                                                                 {
  1655.                                                                                         distanceClosestSq = distanceSq;
  1656.  
  1657.                                                                                         closestActor = closerActor;
  1658.                                                                                 }
  1659.                                                                         }
  1660.                                                                 }
  1661.                                                         }
  1662.                                                 }
  1663.  
  1664.                                                 assert(closestActor);
  1665.  
  1666.                                                 // Are we the closest candidate?
  1667.                                                 if (closestActor && (closestActor == pPipeUser->CastToCAIActor()))
  1668.                                                 {
  1669.                                                         // Fill in the actor target request, and figure out the navSO method.
  1670.                                                         if (pSmartObjectManager->PrepareNavigateSmartObject(pPipeUser, pSmartObject, pSOLink->m_pSmartObjectClass, pSOLink->m_pFromHelper, pSOLink->m_pToHelper) && pPipeUser->m_eNavSOMethod != nSOmNone)
  1671.                                                         {
  1672.                                                                 pipeUserActorTargetRequest.id = ++pPipeUser->m_actorTargetReqId;
  1673.                                                                 pipeUserActorTargetRequest.lowerPrecision = true;
  1674.  
  1675.                                                                 m_pendingActorTargetRequester = eTATR_NavSO;
  1676.  
  1677.                                                                 // In case we hit here because the path following has finished, keep the trace alive.
  1678.                                                                 *pbExactPositioning = true;
  1679.  
  1680.                                                                 // Enforce to use the current path.
  1681.                                                                 pPipeUser->m_Path.GetParams().inhibitPathRegeneration = true;
  1682.                                                                 pPipeUser->CancelRequestedPath(false);
  1683.  
  1684. #ifdef _DEBUG
  1685.                                                                 // TODO: these are debug variables, should be perhaps initialised somewhere else.
  1686.                                                                 pPipeUser->m_DEBUGCanTargetPointBeReached.clear();
  1687.                                                                 pPipeUser->m_DEBUGUseTargetPointRequest.zero();
  1688. #endif
  1689.  
  1690.                                                                 m_bWaitingForBusySmartObject = false;
  1691.                                                         }
  1692.                                                         else // Can't navigate using this SO for some reason
  1693.                                                         {
  1694.                                                                 // Failed to use the navSO. Instead of resetting the goalop, set the state
  1695.                                                                 // to error, to prevent the link being reused.
  1696.                                                                 *pbForceRegeneratePath = true;
  1697.                                                                 pipeUserActorTargetRequest.Reset();
  1698.                                                                 m_actorTargetRequester = eTATR_None;
  1699.                                                                 m_pendingActorTargetRequester = eTATR_None;
  1700.  
  1701.                                                                 //Should this be used for MNM case?
  1702.                                                                 pPipeUser->InvalidateSOLink(pSmartObject, pSOLink->m_pFromHelper, pSOLink->m_pToHelper);
  1703.                                                         }
  1704.                                                 }
  1705.                                                 else // We are not the closest in line
  1706.                                                 {
  1707.                                                         // Attempt to wait for the SO to become free
  1708.                                                         m_bWaitingForBusySmartObject = true;
  1709.                                                 }
  1710.                                         }
  1711.                                 }
  1712.                         }
  1713.                         // No SO nav data
  1714.                         else if (const SAIActorTargetRequest* pActiveActorTargetRequest = pPipeUser->GetActiveActorTargetRequest())
  1715.                         {
  1716.                                 // Actor target requested at the end of the path.
  1717.                                 pipeUserActorTargetRequest = *pActiveActorTargetRequest;
  1718.                                 pipeUserActorTargetRequest.id = ++pPipeUser->m_actorTargetReqId;
  1719.                                 pipeUserActorTargetRequest.lowerPrecision = false;
  1720.                                 m_pendingActorTargetRequester = eTATR_EndOfPath;
  1721.  
  1722.                                 // In case we hit here because the path following has finished, keep the trace alive.
  1723.                                 *pbExactPositioning = true;
  1724.  
  1725.                                 // Enforce to use the current path.
  1726.                                 pPipeUser->m_Path.GetParams().inhibitPathRegeneration = true;
  1727.                                 pPipeUser->CancelRequestedPath(false);
  1728.  
  1729. #ifdef _DEBUG
  1730.                                 // TODO: these are debug variables, should be perhaps initialised somewhere else.
  1731.                                 pPipeUser->m_DEBUGCanTargetPointBeReached.clear();
  1732.                                 pPipeUser->m_DEBUGUseTargetPointRequest.zero();
  1733. #endif
  1734.                         }
  1735.                         break;
  1736.                 }
  1737.  
  1738.         case eATP_Error:
  1739.                 break;
  1740.  
  1741.         default:
  1742.                 // The exact positioning is in motion but not yet playing, keep the trace alive.
  1743.                 *pbExactPositioning = true;
  1744.         }
  1745. }
  1746.  
  1747. void COPTrace::Teleport(CPipeUser& pipeUser, const Vec3& teleportDestination)
  1748. {
  1749.         if (IEntity* entity = pipeUser.GetEntity())
  1750.         {
  1751.                 Matrix34 transform = entity->GetWorldTM();
  1752.                 transform.SetTranslation(teleportDestination);
  1753.                 entity->SetWorldTM(transform);
  1754.                 m_stuckDetector.Reset();
  1755.                 bool forceGeneratePath = true;
  1756.                 RegeneratePath(&pipeUser, &forceGeneratePath);
  1757.                 m_bWaitingForPathResult = true;
  1758.         }
  1759. }
  1760.  
downloadGoalOpTrace.cpp Source code - Download CRYENGINE Source code
Related Source Codes/Software:
postal - 2017-06-11
reactide - Reactide is the first dedicated IDE for React web ... 2017-06-11
rkt - rkt is a pod-native container engine for Linux. It... 2017-06-11
uWebSockets - Tiny WebSockets https://for... 2017-06-11
realworld - TodoMVC for the RealWorld - Exemplary fullstack Me... 2017-06-11
CRYENGINE - CRYENGINE is a powerful real-time game development... 2017-06-11
goreplay - GoReplay is an open-source tool for capturing and ... 2017-06-10
pyenv - Simple Python version management 2017-06-10
redux-saga - An alternative side effect model for Redux apps ... 2017-06-10
angular-starter - 2017-06-10

 Back to top