BVB Source Codes

CRYENGINE Show GoalOpStick.cpp Source code

Return Download CRYENGINE: download GoalOpStick.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 "GoalOpStick.h"
  5. #include "GoalOpTrace.h"
  6. #include "NavRegion.h"
  7. #include "Puppet.h"
  8. #include "DebugDrawContext.h"
  9.  
  10. // Ugly
  11. #define C_MaxDistanceForPathOffset 2 // threshold (in m) used in COPStick and COPApproach, to detect if the returned path
  12. // is bringing the agent too far from the expected destination
  13.  
  14. //
  15. //----------------------------------------------------------------------------------------------------------
  16. COPStick::COPStick(float fStickDistance, float fEndAccuracy, float fDuration, int nFlags, int nFlagsAux, ETraceEndMode eTraceEndMode) :
  17.         m_vLastUsedTargetPos(ZERO),
  18.         m_fTrhDistance(1.f),  // regenerate path if target moved for more than this
  19.         m_eTraceEndMode(eTraceEndMode),
  20.         m_fApproachTime(-1.f),
  21.         m_fHijackDistance(-1.f),
  22.         m_fStickDistance(fStickDistance),
  23.         m_fEndAccuracy(fEndAccuracy),
  24.         m_fDuration(fDuration),
  25.         m_bContinuous((nFlagsAux & 0x01) == 0),
  26.         m_bTryShortcutNavigation((nFlagsAux & 0x02) != 0),
  27.         m_bUseLastOpResult((nFlags & AILASTOPRES_USE) != 0),
  28.         m_bLookAtLastOp((nFlags & AILASTOPRES_LOOKAT) != 0),
  29.         m_bInitialized(false),
  30.         m_bForceReturnPartialPath((nFlags & AI_REQUEST_PARTIAL_PATH) != 0),
  31.         m_bStopOnAnimationStart((nFlags & AI_STOP_ON_ANIMATION_START) != 0),
  32.         m_targetPredictionTime(0.f),
  33.         m_pTraceDirective(NULL),
  34.         m_pPathfindDirective(NULL),
  35.         m_looseAttentionId(0),
  36.         m_bPathFound(false),
  37.         m_bBodyIsAligned(false),
  38.         m_bAlignBodyBeforeMove(false),
  39.         m_fCorrectBodyDirTime(0.0f),
  40.         m_fTimeSpentAligning(0.0f)
  41. {
  42.         if (m_fStickDistance < 0.f)
  43.         {
  44.                 AIWarning("COPStick::COPStick: Negative stick distance provided.");
  45.         }
  46.  
  47.         if (gAIEnv.CVars.DebugPathFinding)
  48.                 AILogAlways("COPStick::COPStick %p", this);
  49.  
  50.         m_smoothedTargetVel.zero();
  51.         m_lastTargetPos.zero();
  52.         m_safePointInterval = 1.0f;
  53.         m_maxTeleportSpeed = 10.0f;
  54.         m_pathLengthForTeleport = 20.0f;
  55.         m_playerDistForTeleport = 3.0f;
  56.  
  57.         m_lastVisibleTime.SetValue(0);
  58.         ClearTeleportData();
  59.  
  60.         if (m_bContinuous)
  61.         {
  62.                 // Continuous stick defaults to speed adjustment, allow to make it constant.
  63.                 m_bConstantSpeed = (nFlags & AI_CONSTANT_SPEED) != 0;
  64.         }
  65.         else
  66.         {
  67.                 // Non-continuous stick defaults to constant speed, allow to enable adjustment.
  68.                 m_bConstantSpeed = (nFlags & AI_ADJUST_SPEED) == 0;
  69.         }
  70. }
  71.  
  72. //
  73. //----------------------------------------------------------------------------------------------------------
  74. COPStick::COPStick(const XmlNodeRef& node) :
  75.         m_vLastUsedTargetPos(ZERO),
  76.         m_fTrhDistance(1.f),  // regenerate path if target moved for more than this
  77.  
  78.         // [9/21/2010 evgeny] eTEM_FixedDistance for goalop "Stick", eTEM_MinimumDistance for goalop "StickMinimumDistance",
  79.         // which uses the same class, COPStick
  80.         m_eTraceEndMode(stricmp(node->getTag(), "Stick") ? eTEM_MinimumDistance : eTEM_FixedDistance),
  81.  
  82.         m_fApproachTime(-1.f),
  83.         m_fHijackDistance(-1.f),
  84.         m_fStickDistance(0.f),
  85.         m_fEndAccuracy(0.f),
  86.         m_fDuration(0.f),
  87.         m_bContinuous(s_xml.GetBool(node, "continuous", false)),
  88.         m_bTryShortcutNavigation(s_xml.GetBool(node, "tryShortcutNavigation")),
  89.         m_bUseLastOpResult(s_xml.GetBool(node, "useLastOp")),
  90.         m_bLookAtLastOp(s_xml.GetBool(node, "lookAtLastOp")),
  91.         m_bInitialized(false),
  92.         m_bForceReturnPartialPath(s_xml.GetBool(node, "requestPartialPath")),
  93.         m_bStopOnAnimationStart(s_xml.GetBool(node, "stopOnAnimationStart")),
  94.         m_targetPredictionTime(0.f),
  95.         m_pTraceDirective(0),
  96.         m_pPathfindDirective(0),
  97.         m_looseAttentionId(0),
  98.         m_bPathFound(false),
  99.         m_smoothedTargetVel(ZERO),
  100.         m_lastTargetPos(ZERO),
  101.         m_safePointInterval(1.f),
  102.         m_maxTeleportSpeed(10.f),
  103.         m_pathLengthForTeleport(20.f),
  104.         m_playerDistForTeleport(3.f),
  105.         m_sLocateName(node->getAttr("locateName")),
  106.         m_bBodyIsAligned(false),
  107.         m_bAlignBodyBeforeMove(s_xml.GetBool(node, "alignBeforeMove")),
  108.         m_fCorrectBodyDirTime(0.0f),
  109.         m_fTimeSpentAligning(0.0f)
  110. {
  111.         if (node->getAttr("duration", m_fDuration))
  112.         {
  113.                 m_fDuration = fabsf(m_fDuration);
  114.         }
  115.         else
  116.         {
  117.                 node->getAttr("distance", m_fStickDistance);
  118.                 if (m_fStickDistance < 0.f)
  119.                 {
  120.                         AIWarning("COPStick::COPStick: Negative stick distance provided.");
  121.                 }
  122.         }
  123.  
  124.         if (!node->getAttr("endAccuracy", m_fEndAccuracy))
  125.         {
  126.                 m_fEndAccuracy = m_fStickDistance;
  127.         }
  128.  
  129.         // Random variation on the end distance.
  130.         float fDistanceVariation;
  131.         if (node->getAttr("distanceVariation", fDistanceVariation))
  132.         {
  133.                 if (fDistanceVariation > 0.01f)
  134.                 {
  135.                         float u = cry_random(0, 9) / 9.f;
  136.                         m_fStickDistance = (m_fStickDistance > 0.f) ? max(0.f, m_fStickDistance - u * fDistanceVariation)
  137.                                            : min(0.f, m_fStickDistance + u * fDistanceVariation);
  138.                 }
  139.         }
  140.  
  141.         if (gAIEnv.CVars.DebugPathFinding)
  142.                 AILogAlways("COPStick::COPStick %p", this);
  143.  
  144.         m_lastVisibleTime.SetValue(0);
  145.         ClearTeleportData();
  146.  
  147.         if (m_bContinuous)
  148.         {
  149.                 // Continuous stick defaults to speed adjustment, allow to make it constant.
  150.                 m_bConstantSpeed = s_xml.GetBool(node, "constantSpeed");
  151.         }
  152.         else
  153.         {
  154.                 // Non-continuous stick defaults to constant speed, allow to enable adjustment.
  155.                 m_bConstantSpeed = !s_xml.GetBool(node, "adjustSpeed");
  156.         }
  157.  
  158.         node->getAttr("regenDistThreshold", m_fTrhDistance);
  159. }
  160.  
  161. //
  162. //----------------------------------------------------------------------------------------------------------
  163. COPStick::~COPStick()
  164. {
  165.         SAFE_DELETE(m_pPathfindDirective);
  166.         SAFE_DELETE(m_pTraceDirective);
  167.  
  168.         if (gAIEnv.CVars.DebugPathFinding)
  169.                 AILogAlways("COPStick::~COPStick %p", this);
  170. }
  171.  
  172. //
  173. //----------------------------------------------------------------------------------------------------------
  174. void COPStick::Reset(CPipeUser* pPipeUser)
  175. {
  176.         if (gAIEnv.CVars.DebugPathFinding)
  177.                 AILogAlways("COPStick::Reset %s", GetNameSafe(pPipeUser));
  178.  
  179.         m_refStickTarget.Reset();
  180.         m_refSightTarget.Reset();
  181.  
  182.         SAFE_DELETE(m_pPathfindDirective);
  183.         SAFE_DELETE(m_pTraceDirective);
  184.  
  185.         m_bBodyIsAligned = false;
  186.         m_fCorrectBodyDirTime = 0.0f;
  187.         m_fTimeSpentAligning = 0.0f;
  188.  
  189.         m_bPathFound = false;
  190.         m_vLastUsedTargetPos.zero();
  191.  
  192.         m_smoothedTargetVel.zero();
  193.         m_lastTargetPos.zero();
  194.  
  195.         ClearTeleportData();
  196.  
  197.         if (pPipeUser)
  198.         {
  199.                 pPipeUser->ClearPath("COPStick::Reset m_Path");
  200.                 if (m_bLookAtLastOp)
  201.                 {
  202.                         pPipeUser->SetLooseAttentionTarget(NILREF, m_looseAttentionId);
  203.                         m_looseAttentionId = 0;
  204.                 }
  205.  
  206.                 // Clear the movement information so that the agent doesn't move
  207.                 SOBJECTSTATE& state = pPipeUser->m_State;
  208.                 state.vMoveDir.zero();
  209.                 state.vMoveTarget.zero();
  210.                 state.vInflectionPoint.zero();
  211.                 state.fDesiredSpeed = 0.0f;
  212.                 state.fDistanceToPathEnd = 0.0f;
  213.                 state.predictedCharacterStates.nStates = 0;
  214.         }
  215. }
  216.  
  217. //
  218. //----------------------------------------------------------------------------------------------------------
  219. void COPStick::SSafePoint::Serialize(TSerialize ser)
  220. {
  221.         ser.BeginGroup("StickSafePoint");
  222.         ser.Value("pos", pos);
  223.         ser.Value("time", time);
  224.         ser.Value("navCapMask", navCapMask);
  225.         ser.Value("passRadius", passRadius);
  226.         ser.Value("requesterName", requesterName); // is this needed?
  227.         ser.EndGroup();
  228. }
  229.  
  230. //
  231. //----------------------------------------------------------------------------------------------------------
  232. COPStick::SSafePoint::SSafePoint(const Vec3& pos_, CPipeUser& pipeUser, unsigned lastNavNodeIndex)
  233.         : pos(pos_)
  234.         , time(GetAISystem()->GetFrameStartTime())
  235.         , requesterName(pipeUser.GetName())
  236.         , navCapMask(pipeUser.m_movementAbility.pathfindingProperties.navCapMask)
  237.         , passRadius(pipeUser.m_Parameters.m_fPassRadius)
  238. {
  239.         Reset(lastNavNodeIndex);
  240. }
  241.  
  242. //
  243. //----------------------------------------------------------------------------------------------------------
  244. void COPStick::SSafePoint::Reset(unsigned lastNavNodeIndex)
  245. {
  246.         nodeIndex = 0;
  247.         safe = false;
  248. }
  249.  
  250. //
  251. //----------------------------------------------------------------------------------------------------------
  252. void COPStick::Serialize(TSerialize ser)
  253. {
  254.  
  255.         ser.BeginGroup("COPStick");
  256.         {
  257.                 ser.Value("m_vLastUsedTargetPos", m_vLastUsedTargetPos);
  258.                 ser.Value("m_fTrhDistance", m_fTrhDistance);
  259.                 ser.Value("m_fStickDistance", m_fStickDistance);
  260.                 ser.Value("m_fEndAccuracy", m_fEndAccuracy);
  261.                 ser.Value("m_fDuration", m_fDuration);
  262.                 ser.Value("m_bContinuous", m_bContinuous);
  263.                 ser.Value("m_bLookAtLastOp", m_bLookAtLastOp);
  264.                 ser.Value("m_bTryShortcutNavigation", m_bTryShortcutNavigation);
  265.                 ser.Value("m_bUseLastOpResult", m_bUseLastOpResult);
  266.                 ser.Value("m_targetPredictionTime", m_targetPredictionTime);
  267.                 ser.Value("m_bPathFound", m_bPathFound);
  268.                 ser.Value("m_bInitialized", m_bInitialized);
  269.                 ser.Value("m_bConstantSpeed", m_bConstantSpeed);
  270.                 ser.Value("m_teleportCurrent", m_teleportCurrent);
  271.                 ser.Value("m_teleportEnd", m_teleportEnd);
  272.                 ser.Value("m_lastTeleportTime", m_lastTeleportTime);
  273.                 ser.Value("m_lastVisibleTime", m_lastVisibleTime);
  274.                 ser.Value("m_maxTeleportSpeed", m_maxTeleportSpeed);
  275.                 ser.Value("m_pathLengthForTeleport", m_pathLengthForTeleport);
  276.                 ser.Value("m_playerDistForTeleport", m_playerDistForTeleport);
  277.                 ser.Value("m_bForceReturnPartialPath", m_bForceReturnPartialPath);
  278.                 ser.Value("m_bStopOnAnimationStart", m_bStopOnAnimationStart);
  279.                 ser.Value("m_lastTargetPosTime", m_lastTargetPosTime);
  280.                 ser.Value("m_lastTargetPos", m_lastTargetPos);
  281.                 ser.Value("m_smoothedTargetVel", m_smoothedTargetVel);
  282.                 ser.Value("m_looseAttentionId", m_looseAttentionId);
  283.  
  284.                 ser.Value("m_stickTargetSafePoints", m_stickTargetSafePoints);
  285.                 if (ser.IsReading())
  286.                 {
  287.                         for (uint8 i = 0, size = m_stickTargetSafePoints.Size(); i < size; ++i)
  288.                         {
  289.                                 m_stickTargetSafePoints[i].Reset(0);
  290.                         }
  291.                 }
  292.                 ser.Value("m_safePointInterval", m_safePointInterval);
  293.  
  294.                 m_refStickTarget.Serialize(ser, "m_refStickTarget");
  295.                 m_refSightTarget.Serialize(ser, "m_refSightTarget");
  296.  
  297.                 if (ser.IsWriting())
  298.                 {
  299.                         if (ser.BeginOptionalGroup("TraceDirective", m_pTraceDirective != NULL))
  300.                         {
  301.                                 PREFAST_SUPPRESS_WARNING(6011) m_pTraceDirective->Serialize(ser);
  302.                                 ser.EndGroup();
  303.                         }
  304.                         if (ser.BeginOptionalGroup("PathFindDirective", m_pPathfindDirective != NULL))
  305.                         {
  306.                                 PREFAST_SUPPRESS_WARNING(6011) m_pPathfindDirective->Serialize(ser);
  307.                                 ser.EndGroup();
  308.                         }
  309.                 }
  310.                 else
  311.                 {
  312.                         SAFE_DELETE(m_pTraceDirective);
  313.                         if (ser.BeginOptionalGroup("TraceDirective", true))
  314.                         {
  315.                                 m_pTraceDirective = new COPTrace(true);
  316.                                 m_pTraceDirective->Serialize(ser);
  317.                                 ser.EndGroup();
  318.                         }
  319.                         SAFE_DELETE(m_pPathfindDirective);
  320.                         if (ser.BeginOptionalGroup("PathFindDirective", true))
  321.                         {
  322.                                 m_pPathfindDirective = new COPPathFind("");
  323.                                 m_pPathfindDirective->Serialize(ser);
  324.                                 ser.EndGroup();
  325.                         }
  326.                 }
  327.         }
  328.         ser.EndGroup();
  329. }
  330.  
  331. //===================================================================
  332. // GetEndDistance
  333. //===================================================================
  334. float COPStick::GetEndDistance(CPipeUser* pPipeUser) const
  335. {
  336.         if (m_fDuration > 0.f)
  337.         {
  338.                 float fNormalSpeed, fMinSpeed, fMaxSpeed;
  339.                 pPipeUser->GetMovementSpeedRange(pPipeUser->m_State.fMovementUrgency, false,
  340.                                                  fNormalSpeed, fMinSpeed, fMaxSpeed);
  341.  
  342.                 if (fNormalSpeed > 0.f)
  343.                         return -fNormalSpeed * m_fDuration;
  344.         }
  345.         return m_fStickDistance;
  346. }
  347.  
  348. //
  349. //----------------------------------------------------------------------------------------------------------
  350. void COPStick::RegeneratePath(CPipeUser* pPipeUser, const Vec3& vDestination)
  351. {
  352.         if (!pPipeUser)
  353.                 return;
  354.  
  355.         if (gAIEnv.CVars.DebugPathFinding)
  356.                 AILogAlways("COPStick::RegeneratePath %s", GetNameSafe(pPipeUser));
  357.  
  358.         m_pPathfindDirective->Reset(pPipeUser);
  359.         m_pTraceDirective->m_fEndAccuracy = m_fEndAccuracy;
  360.         m_vLastUsedTargetPos = vDestination;
  361.         pPipeUser->m_nPathDecision = PATHFINDER_STILLFINDING;
  362.  
  363.         const Vec3 vPipeUserPos = pPipeUser->GetPhysicsPos();
  364. }
  365.  
  366. //===================================================================
  367. // DebugDraw
  368. //===================================================================
  369. void COPStick::DebugDraw(CPipeUser* pPipeUser) const
  370. {
  371.         CDebugDrawContext dc;
  372.         unsigned nPts = m_stickTargetSafePoints.Size();
  373.         unsigned iPt = 0;
  374.         TStickTargetSafePoints::SConstIterator itEnd = m_stickTargetSafePoints.End();
  375.         for (TStickTargetSafePoints::SConstIterator it = m_stickTargetSafePoints.Begin(); it != itEnd; ++it, ++iPt)
  376.         {
  377.                 const SSafePoint& safePoint = *it;
  378.                 float frac = ((float) iPt) / nPts;
  379.                 ColorB color;
  380.                 if (safePoint.safe)
  381.                         color.set(0, uint8(255 * frac), uint8(255 * (1.0f - frac)), 255);
  382.                 else
  383.                         color.set(255, 0, 0, 255);
  384.                 dc->DrawSphere(safePoint.pos, 0.2f, color);
  385.         }
  386.  
  387.         if (m_pPathfindDirective)
  388.                 m_pPathfindDirective->DebugDraw(pPipeUser);
  389.         if (m_pTraceDirective)
  390.                 m_pTraceDirective->DebugDraw(pPipeUser);
  391. }
  392.  
  393. //===================================================================
  394. // UpdateStickTargetSafePoints
  395. //===================================================================
  396. void COPStick::UpdateStickTargetSafePoints(CPipeUser* pPipeUser)
  397. {
  398.         Vec3 curPos;
  399.         CLeader* pLeader = GetAISystem()->GetLeader(pPipeUser->GetGroupId());
  400.         CAIObject* pOwner = pLeader ? pLeader->GetFormationOwner().GetAIObject() : 0;
  401.         if (pOwner)
  402.                 curPos = pOwner->GetPhysicsPos();
  403.         else
  404.                 curPos = m_refStickTarget.GetAIObject()->GetPhysicsPos();
  405.  
  406.         Vec3 opPos = pPipeUser->GetPhysicsPos();
  407.         if (GetAISystem()->WouldHumanBeVisible(opPos, false))
  408.                 m_lastVisibleTime = GetAISystem()->GetFrameStartTime();
  409.  
  410.         unsigned lastNavNodeIndex = m_refStickTarget.GetAIObject()->GetNavNodeIndex();
  411.         if (!m_stickTargetSafePoints.Empty())
  412.         {
  413.                 Vec3 delta = curPos - m_stickTargetSafePoints.Front().pos;
  414.                 float dist = delta.GetLength();
  415.                 if (dist < m_safePointInterval)
  416.                         return;
  417.                 lastNavNodeIndex = m_stickTargetSafePoints.Front().nodeIndex;
  418.         }
  419.  
  420.         int maxNumPoints = 1 + (int)(m_pathLengthForTeleport / m_safePointInterval);
  421.         if (m_stickTargetSafePoints.Size() >= maxNumPoints || m_stickTargetSafePoints.Full())
  422.                 m_stickTargetSafePoints.PopBack();
  423.  
  424.         m_stickTargetSafePoints.PushFront(SSafePoint(curPos, *pPipeUser, lastNavNodeIndex));
  425. }
  426.  
  427. //===================================================================
  428. // ClearTeleportData
  429. //===================================================================
  430. void COPStick::ClearTeleportData()
  431. {
  432.         m_teleportCurrent.zero();
  433.         m_teleportEnd.zero();
  434. }
  435.  
  436. //===================================================================
  437. // TryToTeleport
  438. // This works by first detecting if we need to teleport. If we do, then
  439. // we identify and store the teleport destination location. However, we
  440. // don't move pPipeUser there immediately - we continue following our path. But we
  441. // move a "ghost" from the initial position to the destination. If it
  442. // reaches the destination without either the ghost or the real pPipeUser
  443. // being seen by the player then pPipeUser (may) get teleported. If teleporting
  444. // happens then m_stickTargetSafePoints needs to be updated.
  445. //===================================================================
  446. bool COPStick::TryToTeleport(CPipeUser* pPipeUser)
  447. {
  448.         FUNCTION_PROFILER(GetISystem(), PROFILE_AI);
  449.  
  450.         if (m_stickTargetSafePoints.Size() < 2)
  451.         {
  452.                 ClearTeleportData();
  453.                 return false;
  454.         }
  455.  
  456.         if (pPipeUser->m_nPathDecision != PATHFINDER_NOPATH)
  457.         {
  458.                 float curPathLen = pPipeUser->m_Path.GetPathLength(false);
  459.                 Vec3 stickPos = m_refStickTarget.GetAIObject()->GetPhysicsPos();
  460.                 if (pPipeUser->m_Path.Empty())
  461.                         curPathLen += Distance::Point_Point(pPipeUser->GetPhysicsPos(), stickPos);
  462.                 else
  463.                         curPathLen += Distance::Point_Point(pPipeUser->m_Path.GetLastPathPos(), stickPos);
  464.                 if (curPathLen < m_pathLengthForTeleport)
  465.                 {
  466.                         ClearTeleportData();
  467.                         return false;
  468.                 }
  469.                 else
  470.                 {
  471.                         // Danny/Luc todo issue some readability by sending a signal - the response to that signal
  472.                         // should ideally stop the path following
  473.                 }
  474.         }
  475.  
  476.         CTimeValue now(GetAISystem()->GetFrameStartTime());
  477.  
  478.         if (m_lastVisibleTime == now)
  479.         {
  480.                 ClearTeleportData();
  481.                 return false;
  482.         }
  483.  
  484.         if (m_teleportEnd.IsZero() && !m_stickTargetSafePoints.Empty())
  485.         {
  486.                 const Vec3 playerPos = GetAISystem()->GetPlayer()->GetPhysicsPos();
  487.  
  488.                 TStickTargetSafePoints::SIterator itEnd = m_stickTargetSafePoints.End();
  489.                 for (TStickTargetSafePoints::SIterator it = m_stickTargetSafePoints.Begin(); it != itEnd; ++it)
  490.                 {
  491.                         const SSafePoint& sp = *it;
  492.                         if (!sp.safe)
  493.                                 return false;
  494.  
  495.                         float playerDistSq = Distance::Point_PointSq(sp.pos, playerPos);
  496.                         if (playerDistSq < square(m_playerDistForTeleport))
  497.                                 continue;
  498.  
  499.                         TStickTargetSafePoints::SIterator itNext = it;
  500.                         ++itNext;
  501.                         if (itNext == itEnd)
  502.                         {
  503.                                 m_teleportEnd = sp.pos;
  504.                                 break;
  505.                         }
  506.                         else if (!itNext->safe)
  507.                         {
  508.                                 m_teleportEnd = sp.pos;
  509.                                 break;
  510.                         }
  511.                 }
  512.         }
  513.  
  514.         if (m_teleportEnd.IsZero())
  515.                 return false;
  516.  
  517.         Vec3 curPos = pPipeUser->GetPhysicsPos();
  518.         if (m_teleportCurrent.IsZero())
  519.         {
  520.                 m_teleportCurrent = curPos;
  521.                 m_lastTeleportTime = now;
  522.  
  523.                 // If player hasn't seen operand for X seconds then move along by that amount
  524.                 Vec3 moveDir = m_teleportEnd - m_teleportCurrent;
  525.                 float distToEnd = moveDir.NormalizeSafe();
  526.  
  527.                 float dt = (now - m_lastVisibleTime).GetSeconds();
  528.                 float dist = dt * m_maxTeleportSpeed;
  529.                 if (dist > distToEnd)
  530.                         dist = distToEnd;
  531.  
  532.                 m_teleportCurrent += dist * moveDir;
  533.  
  534.                 return false;
  535.         }
  536.  
  537.         // move the ghost
  538.         Vec3 moveDir = m_teleportEnd - m_teleportCurrent;
  539.         float distToEnd = moveDir.NormalizeSafe();
  540.  
  541.         float dt = (now - m_lastTeleportTime).GetSeconds();
  542.         m_lastTeleportTime = now;
  543.  
  544.         float dist = dt * m_maxTeleportSpeed;
  545.         bool reachedEnd = false;
  546.         if (dist > distToEnd)
  547.         {
  548.                 reachedEnd = true;
  549.                 dist = distToEnd;
  550.         }
  551.         m_teleportCurrent += dist * moveDir;
  552.  
  553.         if (GetAISystem()->WouldHumanBeVisible(m_teleportCurrent, false))
  554.         {
  555.                 ClearTeleportData();
  556.                 return false;
  557.         }
  558.  
  559.         if (reachedEnd)
  560.         {
  561.                 AILogEvent("COPStick::TryToTeleport teleporting %s to (%5.2f, %5.2f, %5.2f)",
  562.                            GetNameSafe(pPipeUser), m_teleportEnd.x, m_teleportEnd.y, m_teleportEnd.z);
  563.                 Vec3 floorPos = m_teleportEnd;
  564.                 GetFloorPos(floorPos, m_teleportEnd, 0.0f, 3.0f, 0.1f, AICE_ALL);
  565.                 pPipeUser->GetEntity()->SetPos(floorPos);
  566.                 pPipeUser->m_State.fDesiredSpeed = 0;
  567.                 pPipeUser->m_State.vMoveDir.zero();
  568.                 pPipeUser->ClearPath("Teleport");
  569.                 RegeneratePath(pPipeUser, m_refStickTarget.GetAIObject()->GetPos());
  570.  
  571.                 unsigned nPts = m_stickTargetSafePoints.Size();
  572.                 unsigned nBack = 10;
  573.                 unsigned iPt = 0;
  574.                 TStickTargetSafePoints::SIterator itEnd = m_stickTargetSafePoints.End();
  575.                 for (TStickTargetSafePoints::SIterator it = m_stickTargetSafePoints.Begin(); it != itEnd; ++it, ++iPt)
  576.                 {
  577.                         SSafePoint& sp = *it;
  578.                         if (iPt == nPts - 1 || sp.pos == m_teleportEnd)
  579.                         {
  580.                                 iPt -= min(iPt, nBack);
  581.                                 TStickTargetSafePoints::SIterator itFirst = m_stickTargetSafePoints.Begin();
  582.                                 itFirst += iPt;
  583.                                 m_stickTargetSafePoints.Erase(itFirst, m_stickTargetSafePoints.End());
  584.                                 break;
  585.                         }
  586.                 }
  587.                 ClearTeleportData();
  588.                 return true;
  589.         }
  590.  
  591.         return false;
  592. }
  593.  
  594. //
  595. //----------------------------------------------------------------------------------------------------------
  596. EGoalOpResult COPStick::Execute(CPipeUser* pPipeUser)
  597. {
  598.         CCCPOINT(COPStick_Execute);
  599.         FUNCTION_PROFILER(GetISystem(), PROFILE_AI);
  600.  
  601.         // Check to see if objects have disappeared since last call
  602.         // Note that at least in the first iteration, they won't be there to start with
  603.         if ((m_refSightTarget.IsSet() && !m_refSightTarget.IsValid()) ||
  604.             (m_refStickTarget.IsSet() && !m_refStickTarget.IsValid()))
  605.         {
  606.                 CCCPOINT(COPStick_Execute_TargetRemoved);
  607.  
  608.                 if (gAIEnv.CVars.DebugPathFinding)
  609.                         AILogAlways("COPStick::Execute (%p) resetting due stick/sight target removed", this);
  610.  
  611.                 Reset(NULL);
  612.         }
  613.  
  614.         // Do not mind the target direction when approaching.
  615.         pPipeUser->m_bPathfinderConsidersPathTargetDirection = false;
  616.  
  617.         EGoalOpResult eGoalOpResult;
  618.  
  619.         if (!m_refStickTarget.IsValid())
  620.                 if (!GetStickAndSightTargets_CreatePathfindAndTraceGoalOps(pPipeUser, &eGoalOpResult))
  621.                         return eGoalOpResult;
  622.  
  623.         CAIObject* const pStickTarget = m_refStickTarget.GetAIObject();
  624.         const CAIObject* const pSightTarget = m_refSightTarget.GetAIObject();
  625.  
  626.         SOBJECTSTATE& pipeUserState = pPipeUser->m_State;
  627.  
  628.         // Special case for formation points, do not stick to disabled points.
  629.         if ((pStickTarget != NULL) && (pStickTarget->GetSubType() == IAIObject::STP_FORMATION) && !pStickTarget->IsEnabled())
  630.         {
  631.                 // Wait until the formation becomes active again.
  632.                 pipeUserState.vMoveDir.zero();
  633.                 return eGOR_IN_PROGRESS;
  634.         }
  635.  
  636.         if (!m_bContinuous && pPipeUser->m_nPathDecision == PATHFINDER_NOPATH)
  637.         {
  638.  
  639.                 if (gAIEnv.CVars.DebugPathFinding)
  640.                         AILogAlways("COPStick::Execute (%p) resetting due to non-continuous and no path %s", this, GetNameSafe(pPipeUser));
  641.  
  642.                 Reset(pPipeUser);
  643.                 return eGOR_FAILED;
  644.         }
  645.  
  646.         //make sure the guy looks in correct direction
  647.         if (m_bLookAtLastOp && pSightTarget)
  648.         {
  649.                 m_looseAttentionId = pPipeUser->SetLooseAttentionTarget(m_refSightTarget);
  650.         }
  651.  
  652.         // trace gets deleted when we reach the end and it's not continuous
  653.         if (!m_pTraceDirective)
  654.         {
  655.  
  656.                 if (gAIEnv.CVars.DebugPathFinding)
  657.                         AILogAlways("COPStick::Execute (%p) returning true due to no trace directive %s", this, GetNameSafe(pPipeUser));
  658.  
  659.                 Reset(pPipeUser);
  660.                 return eGOR_FAILED;
  661.         }
  662.  
  663.         bool b2D = !pPipeUser->IsUsing3DNavigation();
  664.  
  665.         EGoalOpResult eTraceResult = eGOR_IN_PROGRESS;
  666.  
  667.         ///////// TRACE //////////////////////////////////////////////////////////
  668.         // actually trace the path - continue doing this even whilst regenerating (etc) the path
  669.         if (m_bPathFound)
  670.         {
  671.                 if (!m_bAlignBodyBeforeMove || m_bBodyIsAligned)
  672.                 {
  673.                         if (!Trace(pPipeUser, pStickTarget, &eTraceResult))
  674.                                 return eTraceResult;
  675.                 }
  676.                 else
  677.                 {
  678.                         //
  679.                         // Align body towards the move target before starting to move
  680.                         //
  681.  
  682.                         // We need to perform a trace to get the move target.
  683.                         // The movement data set in there will be cleared out later
  684.                         // to prevent the movement to actually take place.
  685.                         if (!Trace(pPipeUser, pStickTarget, &eTraceResult))
  686.                                 return eTraceResult;
  687.  
  688.                         if (!pipeUserState.vMoveTarget.IsZero())
  689.                         {
  690.                                 // Align body towards the move target
  691.                                 Vec3 dirToMoveTarget = pipeUserState.vMoveTarget - pPipeUser->GetPhysicsPos();
  692.                                 dirToMoveTarget.z = 0.0f;
  693.                                 dirToMoveTarget.Normalize();
  694.                                 pPipeUser->SetBodyTargetDir(dirToMoveTarget);
  695.  
  696.                                 // If animation body direction is within the angle threshold,
  697.                                 // wait for some time and then mark the agent as ready to move
  698.                                 Vec3 actualBodyDir = pPipeUser->GetBodyInfo().vAnimBodyDir;
  699.                                 const bool lookingTowardsMoveTarget = (actualBodyDir.Dot(dirToMoveTarget) > cosf(DEG2RAD(17.0f)));
  700.                                 if (lookingTowardsMoveTarget)
  701.                                         m_fCorrectBodyDirTime += gEnv->pTimer->GetFrameTime();
  702.                                 else
  703.                                         m_fCorrectBodyDirTime = 0.0f;
  704.  
  705.                                 const float timeSpentAligning = m_fTimeSpentAligning + gEnv->pTimer->GetFrameTime();
  706.                                 m_fTimeSpentAligning = timeSpentAligning;
  707.  
  708.                                 if (m_fCorrectBodyDirTime > 0.2f || timeSpentAligning > 8.0f)
  709.                                 {
  710.                                         pPipeUser->ResetBodyTargetDir();
  711.                                         m_bBodyIsAligned = true;
  712.                                 }
  713.                         }
  714.  
  715.                         // Clear the movement information so that the agent doesn't move
  716.                         pipeUserState.vMoveDir.zero();
  717.                         pipeUserState.vMoveTarget.zero();
  718.                         pipeUserState.vInflectionPoint.zero();
  719.                         pipeUserState.fDesiredSpeed = 0.0f;
  720.                         pipeUserState.fDistanceToPathEnd = 0.0f;
  721.                         pipeUserState.predictedCharacterStates.nStates = 0;
  722.                 }
  723.         }
  724.         //////////////////////////////////////////////////////////////////////////
  725.  
  726.         // We should never get asserted here! If this assert hits, then the m_pStickTarget was changed during trace,
  727.         // which should never happen!
  728.         // (MATT) That might not be true since the ref refactor {2009/03/23}
  729.         AIAssert(pStickTarget);
  730.         // Adding anti-crash "if" [6/6/2010 evgeny]
  731.         if (!pStickTarget)
  732.                 return eGOR_IN_PROGRESS;
  733.  
  734.         // Cache some values [6/6/2010 evgeny]
  735.         Vec3 vStickTargetPos = pStickTarget->GetPhysicsPos();
  736.         const Vec3 vPipeUserPos = pPipeUser->GetPhysicsPos();
  737.         const float fPathDistanceLeft = pPipeUser->m_Path.GetPathLength(false);
  738.  
  739.         // Hijack
  740.         if (m_eTraceEndMode == eTEM_MinimumDistance)
  741.                 if (HandleHijack(pPipeUser, vStickTargetPos, fPathDistanceLeft, eTraceResult))
  742.                         return eGOR_SUCCEEDED;
  743.  
  744.         // Teleport
  745.         if (m_maxTeleportSpeed > 0.f && pPipeUser->m_movementAbility.teleportEnabled)
  746.         {
  747.                 UpdateStickTargetSafePoints(pPipeUser);
  748.                 TryToTeleport(pPipeUser);
  749.         }
  750.  
  751.         // Target prediction
  752.         m_targetPredictionTime = (pPipeUser->GetType() == AIOBJECT_VEHICLE) ? 2.f : 0.f;
  753.         if (m_targetPredictionTime > 0.f)
  754.         {
  755.                 HandleTargetPrediction(pPipeUser, vStickTargetPos);
  756.         }
  757.         else
  758.         {
  759.                 m_smoothedTargetVel.zero();
  760.                 m_lastTargetPos = vStickTargetPos;
  761.         }
  762.         Vec3 vPredictedTargetOffset = m_smoothedTargetVel * m_targetPredictionTime;
  763.  
  764.         // ensure offset doesn't cross forbidden
  765.         int buildingID = -1;
  766.         IAISystem::ENavigationType ePipeUserLastNavNodeType = gAIEnv.pNavigation->CheckNavigationType(pPipeUser->GetPos(),
  767.                                                                                                       buildingID, pPipeUser->GetMovementAbility().pathfindingProperties.navCapMask);
  768.  
  769.         m_pPathfindDirective->SetTargetOffset(vPredictedTargetOffset);
  770.         vStickTargetPos += vPredictedTargetOffset;
  771.  
  772.         Vec3 vToStickTarget = ((m_bForceReturnPartialPath && (pPipeUser->m_nPathDecision == PATHFINDER_PATHFOUND))
  773.                                ? pPipeUser->m_Path.GetLastPathPos()
  774.                                : vStickTargetPos) - vPipeUserPos;
  775.  
  776.         if (b2D)
  777.                 vToStickTarget.z = 0.f;
  778.  
  779.         IAIObject* pAttTarget = pPipeUser->GetAttentionTarget();
  780.         if (pAttTarget && (pAttTarget != pStickTarget) && pipeUserState.vMoveDir.IsZero(.05f))
  781.                 pPipeUser->m_bLooseAttention = false;
  782.  
  783.         //////////////////////////////////////////////////////////////////////////
  784.         {
  785.                 FRAME_PROFILER("OPStick::Execute(): Final Path Processing!", GetISystem(), PROFILE_AI)
  786.  
  787.                 int nPathDecision = pPipeUser->m_nPathDecision;
  788.  
  789.                 // If the target pos moves substantially update
  790.                 // If we're not already close to the target but it's moved a bit then update.
  791.                 // Be careful about forcing an update too often - especially if we're nearly there.
  792.                 if (nPathDecision != PATHFINDER_STILLFINDING)
  793.                 {
  794.                         if ((m_pTraceDirective->m_Maneuver == COPTrace::eMV_None) && !m_pTraceDirective->m_passingStraightNavSO)
  795.                         {
  796.                                 EActorTargetPhase eCurrentActorTargetPhase = pipeUserState.curActorTargetPhase;
  797.                                 if ((eCurrentActorTargetPhase == eATP_None) || (eCurrentActorTargetPhase == eATP_Error))
  798.                                 {
  799.                                         const SNavPathParams& navPathParams = pPipeUser->m_Path.GetParams();
  800.                                         if (!navPathParams.precalculatedPath && !navPathParams.inhibitPathRegeneration)
  801.                                         {
  802.                                                 if (IsTargetDirty(pPipeUser, vPipeUserPos, b2D, vStickTargetPos, ePipeUserLastNavNodeType))
  803.                                                 {
  804.                                                         RegeneratePath(pPipeUser, vStickTargetPos);
  805.                                                 }
  806.                                         }
  807.                                 }
  808.                         }
  809.                 }
  810.  
  811.                 // check pathfinder status
  812.                 return HandlePathDecision(pPipeUser, nPathDecision, b2D);
  813.         }
  814. }
  815.  
  816. //===================================================================
  817. // ExecuteDry
  818. // Note - it is very important we don't call Reset on ourself from here
  819. // else we might restart ourself subsequently
  820. //===================================================================
  821. void COPStick::ExecuteDry(CPipeUser* pPipeUser)
  822. {
  823.         CAIObject* const pStickTarget = m_refStickTarget.GetAIObject();
  824.  
  825.         if (m_pTraceDirective && pStickTarget)
  826.         {
  827.                 bool bAdjustSpeed = !m_bConstantSpeed && (m_pTraceDirective->m_Maneuver == COPTrace::eMV_None);
  828.  
  829.                 if (bAdjustSpeed && (pPipeUser->GetType() == AIOBJECT_ACTOR) && !pPipeUser->IsUsing3DNavigation())
  830.                 {
  831.                         pPipeUser->m_State.fMovementUrgency = AISPEED_SPRINT;
  832.                 }
  833.  
  834.                 if (m_bPathFound && (!m_bAlignBodyBeforeMove || m_bBodyIsAligned))
  835.                 {
  836.                         m_pTraceDirective->ExecuteTrace(pPipeUser, false);
  837.                 }
  838.  
  839.                 if (bAdjustSpeed)
  840.                         if (CPuppet* pPuppet = pPipeUser->CastToCPuppet())
  841.                                 pPuppet->AdjustSpeed(pStickTarget, m_fStickDistance);
  842.         }
  843. }
  844.  
  845. bool COPStick::GetStickAndSightTargets_CreatePathfindAndTraceGoalOps(CPipeUser* pPipeUser, EGoalOpResult* peGoalOpResult)
  846. {
  847.         // first time = lets stick to target or special named if passed in
  848.         if (m_sLocateName.empty())
  849.         {
  850.                 m_refStickTarget = GetWeakRef(static_cast<CAIObject*>(pPipeUser->GetAttentionTarget()));
  851.         }
  852.         else if (!m_bUseLastOpResult) // Don't bother looking up the special AI object if we're going to look at the last op next anyway
  853.         {
  854.                 CAIObject* pAIObject = pPipeUser->GetSpecialAIObject(m_sLocateName, 0.0f);
  855.                 m_refStickTarget = GetWeakRef(pAIObject);
  856.         }
  857.  
  858.         if (m_bUseLastOpResult || !m_refStickTarget.IsValid())
  859.         {
  860.                 if (pPipeUser->m_refLastOpResult.IsValid())
  861.                 {
  862.                         m_refStickTarget = pPipeUser->m_refLastOpResult;
  863.                 }
  864.                 else
  865.                 {
  866.                         if (gAIEnv.CVars.DebugPathFinding)
  867.                                 AILogAlways("COPStick::Execute resetting due to no stick target %s", GetNameSafe(pPipeUser));
  868.  
  869.                         // no target, nothing to stick to
  870.                         Reset(pPipeUser);
  871.                         *peGoalOpResult = eGOR_FAILED;
  872.                         return false;
  873.                 }
  874.         }
  875.  
  876.         // keep last op. result as sight target
  877.         if (m_bLookAtLastOp && !m_refSightTarget.IsValid() && pPipeUser->m_refLastOpResult.IsValid())
  878.                 m_refSightTarget = pPipeUser->m_refLastOpResult;
  879.  
  880.         CAIObject* const pStickTarget = m_refStickTarget.GetAIObject();
  881.         if (pStickTarget == pPipeUser)
  882.         {
  883.                 AILogAlways("COPStick::Execute sticking to self %s ", GetNameSafe(pPipeUser));
  884.                 Reset(pPipeUser);
  885.                 *peGoalOpResult = eGOR_SUCCEEDED;
  886.                 return false;
  887.         }
  888.  
  889.         const CAIObject* const pSightTarget = m_refSightTarget.GetAIObject();
  890.  
  891.         if (m_fStickDistance > 0.f && (pStickTarget->GetSubType() == CAIObject::STP_ANIM_TARGET))
  892.         {
  893.                 AILogAlways("COPStick::Execute resetting stick distance from %.1f to zero because the stick target is anim target. %s",
  894.                             m_fStickDistance, GetNameSafe(pPipeUser));
  895.                 m_fStickDistance = 0.f;
  896.         }
  897.  
  898.         // Create pathfinder operation
  899.         {
  900.                 FRAME_PROFILER("OPStick::Execute(): Create Pathfinder/Tracer!", GetISystem(), PROFILE_AI);
  901.  
  902.                 Vec3 vStickPos = pStickTarget->GetPhysicsPos();
  903.  
  904.                 if (gAIEnv.CVars.DebugPathFinding)
  905.                         AILogAlways("COPStick::Execute (%p) Creating pathfind/trace directives to (%5.2f, %5.2f, %5.2f) %s", this,
  906.                                     vStickPos.x, vStickPos.y, vStickPos.z, GetNameSafe(pPipeUser));
  907.  
  908.                 float fEndTolerance = (m_bForceReturnPartialPath || m_fEndAccuracy < 0.f)
  909.                                       ? std::numeric_limits<float>::max()
  910.                                       : m_fEndAccuracy;
  911.                 // override end distance if a duration has been set
  912.                 m_pPathfindDirective = new COPPathFind("", pStickTarget, fEndTolerance, GetEndDistance(pPipeUser));
  913.  
  914.                 bool bExactFollow = !pSightTarget && !pPipeUser->m_bLooseAttention;
  915.                 m_pTraceDirective = new COPTrace(bExactFollow, m_fEndAccuracy, m_bForceReturnPartialPath, m_bStopOnAnimationStart, m_eTraceEndMode);
  916.  
  917.                 RegeneratePath(pPipeUser, vStickPos);
  918.  
  919.                 // TODO: This is hack to prevent the Alien Scouts not to use the speed control.
  920.                 // Use better test to use the speed control _only_ when it is really needed (human formations).
  921.                 CPuppet* pPuppet = pPipeUser->CastToCPuppet();
  922.                 if ((pPuppet != NULL) && !m_bInitialized && !pPuppet->m_movementAbility.b3DMove)
  923.                 {
  924.                         pPuppet->ResetSpeedControl();
  925.                         m_bInitialized = true;
  926.                 }
  927.         }
  928.  
  929.         return true;
  930. }
  931.  
  932. bool COPStick::Trace(CPipeUser* pPipeUser, CAIObject* pStickTarget, EGoalOpResult* peTraceResult)
  933. {
  934.         CRY_ASSERT_MESSAGE(m_pTraceDirective, "m_pTraceDirective should really be set here (set by the calling code)");
  935.         if (!m_pTraceDirective)
  936.         {
  937.                 *peTraceResult = eGOR_FAILED;
  938.                 return false;
  939.         }
  940.  
  941.         FRAME_PROFILER("OPStick::Trace(): Tracer Execute!", GetISystem(), PROFILE_AI);
  942.  
  943.         // if using AdjustSpeed then force sprint at this point - will get overridden later
  944.         bool bAdjustSpeed = !m_bConstantSpeed && (m_pTraceDirective->m_Maneuver == COPTrace::eMV_None);
  945.  
  946.         if (bAdjustSpeed && (pPipeUser->GetType() == AIOBJECT_ACTOR) && !pPipeUser->IsUsing3DNavigation())
  947.         {
  948.                 pPipeUser->m_State.fMovementUrgency = AISPEED_SPRINT;
  949.         }
  950.  
  951.         *peTraceResult = m_pTraceDirective->Execute(pPipeUser);
  952.  
  953.         if (bAdjustSpeed)
  954.                 if (CPuppet* pPuppet = pPipeUser->CastToCPuppet())
  955.                         pPuppet->AdjustSpeed(pStickTarget, m_fStickDistance);
  956.  
  957.         // If the path has been traced, finish the operation if the operand is not sticking continuously.
  958.         if (*peTraceResult != eGOR_IN_PROGRESS)
  959.         {
  960.                 if (!m_bContinuous && (m_eTraceEndMode != eTEM_MinimumDistance))
  961.                 {
  962.  
  963.                         if (gAIEnv.CVars.DebugPathFinding)
  964.                                 AILogAlways("COPStick::Execute (%p) finishing due to non-continuous and finished tracing %s", this, GetNameSafe(pPipeUser));
  965.  
  966.                         Reset(pPipeUser);
  967.                         return false;
  968.                 }
  969.  
  970.                 m_pPathfindDirective->m_bWaitingForResult = false;
  971.         }
  972.  
  973.         // m_pStickTarget might be set to NULL as result of passing thru a navigation smart objects
  974.         // on the path by executing an AI action which inserts a goal pipe which calls Reset() for
  975.         // all active goals including this one... in this case it would be fine if we just end this
  976.         // Execute() cycle and wait for the next one
  977.         if (!pStickTarget)
  978.         {
  979.                 *peTraceResult = eGOR_IN_PROGRESS;
  980.                 return false;
  981.         }
  982.  
  983.         return true;
  984. }
  985.  
  986. bool COPStick::HandleHijack(CPipeUser* pPipeUser, const Vec3& vStickTargetPos, float fPathDistanceLeft, EGoalOpResult eTraceResult)
  987. {
  988.         const float HIJACK_DISTANCE = 0.2f;
  989.  
  990.         const Vec3 vToStickTarget = vStickTargetPos - pPipeUser->GetPhysicsPos();
  991.         const float fToStickTargetLength2D = vStickTargetPos.GetLength2D();
  992.  
  993.         if (((eTraceResult != eGOR_IN_PROGRESS) && !m_bContinuous) ||
  994.             (m_bPathFound && (fPathDistanceLeft < HIJACK_DISTANCE)))
  995.         {
  996.                 float fFrameStartTimeInSeconds = GetAISystem()->GetFrameStartTimeSeconds();
  997.  
  998.                 if (m_fApproachTime == -1.f)
  999.                 {
  1000.                         const float MIN_APPROACH_TIME = 0.3f;
  1001.                         m_fApproachTime = fFrameStartTimeInSeconds + MIN_APPROACH_TIME;
  1002.                         m_fHijackDistance = fToStickTargetLength2D;
  1003.                 }
  1004.                 else if (m_fApproachTime <= fFrameStartTimeInSeconds)
  1005.                 {
  1006.                         const float fOldDistance = (vStickTargetPos - pPipeUser->GetLastPosition()).GetLength2D();
  1007.                         // Replaced GetPos with GetPhysicsPos [6/6/2010 evgeny]
  1008.                         //const float fNewDistance = (vStickTargetPos - pPipeUser->GetPos()).GetLength2D();
  1009.                         const float& fNewDistance = fToStickTargetLength2D;
  1010.  
  1011.                         // Ideally, this check should be framerate dependent
  1012.                         const float MOVEMENT_STOPPED_SECOND_EPSILON = 0.05f;
  1013.                         if (fNewDistance >= fOldDistance - MOVEMENT_STOPPED_SECOND_EPSILON)
  1014.                         {
  1015.                                 // We're done!
  1016.                                 m_fApproachTime = -1.f;
  1017.                                 m_fHijackDistance = -1.f;
  1018.  
  1019.                                 if (gAIEnv.CVars.DebugPathFinding)
  1020.                                         AILogAlways("COPStick::Execute (%p) finishing due to non-continuous and finished tracing %s", this, GetNameSafe(pPipeUser));
  1021.  
  1022.                                 Reset(pPipeUser);
  1023.                                 return true;
  1024.                         }
  1025.                 }
  1026.  
  1027.                 // Ignore pathfinding and force movement in the direction of our target.
  1028.                 // This will get us as close to a target as physically possible.
  1029.                 SOBJECTSTATE& pipeUserState = pPipeUser->m_State;
  1030.                 float fNormalSpeed, fMinSpeed, fMaxSpeed;
  1031.                 pPipeUser->GetMovementSpeedRange(pipeUserState.fMovementUrgency, pipeUserState.allowStrafing,
  1032.                                                  fNormalSpeed, fMinSpeed, fMaxSpeed);
  1033.                 const float& fRemainingDistance = fToStickTargetLength2D;
  1034.                 CRY_ASSERT(m_fHijackDistance > 0.f);
  1035.                 // slow down as we approach the target
  1036.                 pipeUserState.fDesiredSpeed = fNormalSpeed * fRemainingDistance / m_fHijackDistance;
  1037.                 pipeUserState.vMoveDir = vToStickTarget.GetNormalizedSafe(Vec3Constants<float>::fVec3_Zero);
  1038.         }
  1039.  
  1040.         return false;
  1041. }
  1042.  
  1043. void COPStick::HandleTargetPrediction(CPipeUser* pPipeUser, const Vec3& vStickTargetPos)
  1044. {
  1045.         CTimeValue now = GetAISystem()->GetFrameStartTime();
  1046.  
  1047.         if (m_lastTargetPos.IsZero())
  1048.         {
  1049.                 m_lastTargetPos = vStickTargetPos;
  1050.                 m_lastTargetPosTime = now;
  1051.                 m_smoothedTargetVel.zero();
  1052.         }
  1053.         else
  1054.         {
  1055.                 int64 dt = (now - m_lastTargetPosTime).GetMilliSecondsAsInt64();
  1056.                 if (dt > 0)
  1057.                 {
  1058.                         Vec3 targetVel = vStickTargetPos - m_lastTargetPos;
  1059.  
  1060.                         if (targetVel.GetLengthSquared() > 5.0f) // try to catch sudden jumps
  1061.                                 targetVel.zero();
  1062.                         else
  1063.                                 targetVel /= (static_cast<float>(dt) * 0.001f);
  1064.  
  1065.                         // Danny todo make this time timestep independent (exp dependency on dt)
  1066.                         const float frac = 0.1f;
  1067.                         m_smoothedTargetVel = frac * targetVel + (1.f - frac) * m_smoothedTargetVel;
  1068.                         m_lastTargetPos = vStickTargetPos;
  1069.                         m_lastTargetPosTime = now;
  1070.                 }
  1071.         }
  1072. }
  1073.  
  1074. bool COPStick::IsTargetDirty(CPipeUser* pPipeUser, const Vec3& vPipeUserPos, bool b2D, const Vec3& vStickTargetPos, IAISystem::ENavigationType ePipeUserLastNavNodeType)
  1075. {
  1076.         // check if need to regenerate path
  1077.         const Vec3 vFromStickTargetToLastUsedTarget = m_vLastUsedTargetPos - vStickTargetPos;
  1078.         float fTargetMoveDist = b2D
  1079.                                 ? vFromStickTargetToLastUsedTarget.GetLength2D()
  1080.                                 : vFromStickTargetToLastUsedTarget.GetLength();
  1081.  
  1082.         // [AlexMcC] If the target hasn't moved, there's no good reason to update our path.
  1083.         // Mikko's comment below explains why the path can be updated too frequently otherwise.
  1084.         // If we don't check to see if the target has moved, we could update our path every
  1085.         // frame and never move.
  1086.         if (fTargetMoveDist <= m_fTrhDistance)
  1087.                 return false;
  1088.  
  1089.         if (pPipeUser->m_Path.Empty())
  1090.                 return true;
  1091.  
  1092.         // If the target is moving approximately to the same direction, do not update the path so often.
  1093.  
  1094.         // Use the stored destination point instead of the last path node since the path may be cut because of navSO.
  1095.         const Vec3& vPathEndPos = pPipeUser->m_PathDestinationPos;
  1096.         Vec3 vDirToPathEnd = vPathEndPos - vPipeUserPos;
  1097.         if (b2D)
  1098.                 vDirToPathEnd.z = 0.f;
  1099.         vDirToPathEnd.NormalizeSafe();
  1100.  
  1101.         Vec3 vDirFromPathEndToStickTarget = vStickTargetPos - vPathEndPos;
  1102.         if (b2D)
  1103.                 vDirFromPathEndToStickTarget.z = 0.f;
  1104.         vDirFromPathEndToStickTarget.NormalizeSafe();
  1105.  
  1106.         float fRegenerateDist = m_fTrhDistance;
  1107.         if (vDirFromPathEndToStickTarget.Dot(vDirToPathEnd) < cosf(DEG2RAD(8.f)))
  1108.                 fRegenerateDist *= 5.f;
  1109.  
  1110.         if (fTargetMoveDist > fRegenerateDist)
  1111.                 return true;
  1112.  
  1113.         // when near the path end force more frequent updates
  1114.         float fPathDistLeft = pPipeUser->m_Path.GetPathLength(false);
  1115.         const Vec3 vFromStickTargetToPathEnd = vPathEndPos - vStickTargetPos;
  1116.         float fPathEndError = b2D ? vFromStickTargetToPathEnd.GetLength2D() : vFromStickTargetToPathEnd.GetLength();
  1117.  
  1118.         // TODO/HACK! [Mikko] This prevent the path to regenerated every frame in some special cases in Crysis Core level
  1119.         // where quite a few behaviors are sticking to a long distance (7-10m).
  1120.         // The whole stick regeneration logic is flawed mostly because pPipeUser->m_PathDestinationPos is not always
  1121.         // the actual target position. The pathfinder may adjust the end location and not keep the requested end pos
  1122.         // if the target is not reachable. I'm sure there are other really nasty cases about this path invalidation logic too.
  1123.         if (ePipeUserLastNavNodeType == IAISystem::NAV_VOLUME)
  1124.                 fPathEndError = max(0.0f, fPathEndError - GetEndDistance(pPipeUser));
  1125.  
  1126.         return (fPathEndError > 0.1f) && (fPathDistLeft < 2.f * fPathEndError);
  1127. }
  1128.  
  1129. EGoalOpResult COPStick::HandlePathDecision(CPipeUser* pPipeUser, int nPathDecision, bool b2D)
  1130. {
  1131.         switch (nPathDecision)
  1132.         {
  1133.         case PATHFINDER_STILLFINDING:
  1134.                 {
  1135.                         m_pPathfindDirective->Execute(pPipeUser);
  1136.                         return eGOR_IN_PROGRESS;
  1137.                 }
  1138.  
  1139.         case PATHFINDER_NOPATH:
  1140.                 pPipeUser->m_State.vMoveDir.zero();
  1141.                 if (m_bContinuous)
  1142.                 {
  1143.                         return eGOR_IN_PROGRESS;
  1144.                 }
  1145.                 else
  1146.                 {
  1147.                         if (gAIEnv.CVars.DebugPathFinding)
  1148.                                 AILogAlways("COPStick::Execute (%p) resetting due to no path %s", this, GetNameSafe(pPipeUser));
  1149.  
  1150.                         Reset(pPipeUser);
  1151.                         return eGOR_FAILED;
  1152.                 }
  1153.  
  1154.         case PATHFINDER_PATHFOUND:
  1155.                 {
  1156.                         // do not spam the AI with the OnPathFound signal (stick goal regenerates the path frequently)
  1157.                         if (!m_bPathFound)
  1158.                         {
  1159.                                 m_bPathFound = true;
  1160.                                 TPathPoints::const_reference lastPathNode = pPipeUser->m_OrigPath.GetPath().back();
  1161.                                 const Vec3& vLastPos = lastPathNode.vPos;
  1162.                                 const Vec3& vRequestedLastNodePos = pPipeUser->m_Path.GetParams().end;
  1163.                                 // send signal to AI
  1164.                                 float fDistance = b2D
  1165.                                                   ? Distance::Point_Point2D(vLastPos, vRequestedLastNodePos)
  1166.                                                   : Distance::Point_Point(vLastPos, vRequestedLastNodePos);
  1167.  
  1168.                                 if ((lastPathNode.navType != IAISystem::NAV_SMARTOBJECT) &&
  1169.                                     (fDistance > m_fStickDistance + C_MaxDistanceForPathOffset))
  1170.                                 {
  1171.                                         AISignalExtraData* pData = new AISignalExtraData;
  1172.                                         pData->fValue = fDistance - m_fStickDistance;
  1173.                                         pPipeUser->SetSignal(0, "OnEndPathOffset", pPipeUser->GetEntity(), pData, gAIEnv.SignalCRCs.m_nOnEndPathOffset);
  1174.                                 }
  1175.                                 else
  1176.                                 {
  1177.                                         pPipeUser->SetSignal(0, "OnPathFound", NULL, 0, gAIEnv.SignalCRCs.m_nOnPathFound);
  1178.                                 }
  1179.  
  1180.                                 return Execute(pPipeUser);
  1181.                         }
  1182.                 }
  1183.         }
  1184.  
  1185.         return eGOR_IN_PROGRESS;
  1186. }
  1187.  
downloadGoalOpStick.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