BVB Source Codes

CRYENGINE Show Puppet.cpp Source code

Return Download CRYENGINE: download Puppet.cpp Source code - Download CRYENGINE Source code - Type:.cpp
  1. // Copyright 2001-2016 Crytek GmbH / Crytek Group. All rights reserved.
  2.  
  3. /********************************************************************
  4.    -------------------------------------------------------------------------
  5.    File name:   Puppet.cpp
  6.    $Id$
  7.    Description: Implementation of the CPuppet class.
  8.  
  9.    -------------------------------------------------------------------------
  10.    History:
  11.    -
  12.  
  13.  *********************************************************************/
  14.  
  15. #include "StdAfx.h"
  16. #include "Puppet.h"
  17. #include "AIPlayer.h"
  18. #include "AIVehicle.h"
  19. #include "Leader.h"
  20. #include "GoalOp.h"
  21.  
  22. #include "AICollision.h"
  23. #include "HideSpot.h"
  24. #include "SmartObjects.h"
  25. #include "PathFollower.h"
  26. #include "FireCommand.h"
  27. #include "PerceptionManager.h"
  28. #include "ObjectContainer.h"
  29.  
  30. #include "CentralInterestManager.h"
  31. #include "TargetSelection/TargetTrackManager.h"
  32.  
  33. #include <CryMath/PNoise3.h>
  34. #include <CrySystem/ISystem.h>
  35. #include "DebugDrawContext.h"
  36. #include "Cover/CoverSystem.h"
  37. #include "Group/GroupManager.h"
  38. #include <CryAISystem/VisionMapTypes.h>
  39.  
  40. #include <CryAISystem/IPerceptionHandlerModifier.h>
  41.  
  42. #include "Navigation/NavigationSystem/NavigationSystem.h"
  43.  
  44. //#pragma optimize("", off)
  45. //#pragma inline_depth(0)
  46.  
  47. inline float SmoothStep(float a, float b, float x)
  48. {
  49.         x = (x - a) / (b - a);
  50.         x = clamp_tpl(x, 0.0f, 1.0f);
  51.         return x * x * (3.0f - 2.0f * x);
  52. }
  53.  
  54. inline float IndexToMovementUrgency(int idx)
  55. {
  56.         float sign = idx < 0 ? -1.0f : 1.0f;
  57.         if (idx < 0) idx = -idx;
  58.         switch (idx)
  59.         {
  60.         case 0:
  61.                 return AISPEED_ZERO * sign;
  62.         case 1:
  63.                 return AISPEED_SLOW * sign;
  64.         case 2:
  65.                 return AISPEED_WALK * sign;
  66.         case 3:
  67.                 return AISPEED_RUN * sign;
  68.         default:
  69.                 return AISPEED_SPRINT * sign;
  70.         }
  71. }
  72.  
  73. template<class Value> void SerializeWeakRefMap(TSerialize& ser, const char* sName, std::map<CWeakRef<CAIObject>, Value>& map)
  74. {
  75.         ser.BeginGroup(sName);
  76.         int size = map.size();
  77.         ser.Value("mapSize", size);
  78.  
  79.         // If reading, iterate over serialised data and add to container
  80.         if (ser.IsReading())
  81.         {
  82.                 map.clear();
  83.                 for (int i = 0; i < size; i++)
  84.                 {
  85.                         CWeakRef<CAIObject> k;
  86.                         Value v;
  87.                         ser.BeginGroup("mapPair");
  88.                         k.Serialize(ser, "key");
  89.                         ser.Value("value", v);
  90.                         ser.EndGroup();
  91.                         map.insert(std::make_pair(k, v));
  92.                 }
  93.         }
  94.         // If writing, iterate over container and serialise data
  95.         else if (ser.IsWriting())
  96.         {
  97.                 for (typename std::map<CWeakRef<CAIObject>, Value>::iterator it = map.begin(); it != map.end(); ++it)
  98.                 {
  99.                         CWeakRef<CAIObject> k = it->first;
  100.                         ser.BeginGroup("mapPair");
  101.                         k.Serialize(ser, "key");
  102.                         ser.Value("value", it->second);
  103.                         ser.EndGroup();
  104.                 }
  105.         }
  106.  
  107.         ser.EndGroup();
  108. }
  109.  
  110. std::vector<CAIActor*> CPuppet::s_enemies;
  111. std::vector<SSortedHideSpot> CPuppet::s_sortedHideSpots;
  112. MultimapRangeHideSpots CPuppet::s_hidespots;
  113. MapConstNodesDistance CPuppet::s_traversedNodes;
  114.  
  115. SSoundPerceptionDescriptor CPuppet::s_DefaultSoundPerceptionDescriptor[AISOUND_LAST] =
  116. {
  117.         SSoundPerceptionDescriptor(0.0f, 1.0f, 2.0f, PERCEPTION_INTERESTING_THR, 1.0f, 0.25f),
  118.         SSoundPerceptionDescriptor(0.0f, 1.0f, 4.0f, PERCEPTION_INTERESTING_THR, 1.0f, 0.5f),
  119.         SSoundPerceptionDescriptor(0.0f, 1.0f, 4.0f, PERCEPTION_THREATENING_THR, 1.0f, 0.5f),
  120.         SSoundPerceptionDescriptor(0.0f, 1.0f, 2.0f, PERCEPTION_INTERESTING_THR, 1.0f, 0.5f),
  121.         SSoundPerceptionDescriptor(0.0f, 1.0f, 4.0f, PERCEPTION_THREATENING_THR, 1.0f, 0.5f),
  122.         SSoundPerceptionDescriptor(0.0f, 1.0f, 4.0f, PERCEPTION_AGGRESSIVE_THR,  1.0f, 0.25f),
  123.         SSoundPerceptionDescriptor(0.0f, 1.0f, 6.0f, PERCEPTION_AGGRESSIVE_THR,  1.0f, 0.75f)
  124. };
  125.  
  126. //////////////////////////////////////////////////////////////////////
  127. // Construction/Destruction
  128. //////////////////////////////////////////////////////////////////////
  129.  
  130. CPuppet::CPuppet()
  131.         : m_fLastUpdateTime(0.0f)
  132.         , m_bWarningTargetDistance(false)
  133.         , m_Alertness(-1)
  134.         , m_pPerceptionHandler(NULL)
  135.         , m_pRODHandler(NULL)
  136.         , m_pFireCmdHandler(0)
  137.         , m_pFireCmdGrenade(0)
  138.         , m_currentWeaponId(0)
  139.         , m_bGrenadeThrowRequested(false)
  140.         , m_eGrenadeThrowRequestType(eRGT_INVALID)
  141.         , m_iGrenadeThrowTargetType(0)
  142.         , m_allowedStrafeDistanceStart(0)
  143.         , m_allowedStrafeDistanceEnd(0)
  144.         , m_allowStrafeLookWhileMoving(false)
  145.         , m_strafeStartDistance(0.0f)
  146.         , m_adaptiveUrgencyMin(0)
  147.         , m_adaptiveUrgencyMax(0)
  148.         , m_adaptiveUrgencyScaleDownPathLen(0)
  149.         , m_adaptiveUrgencyMaxPathLen(0)
  150.         , m_fLastTimeAwareOfPlayer(0)
  151.         , m_playerAwarenessType(PA_NONE)
  152.         , m_timeSinceTriggerPressed(0)
  153.         , m_friendOnWayElapsedTime(0)
  154.         , m_bCanBeShot(true)
  155.         , m_eMemoryFireType(eMFT_UseCoverFireTime)
  156.         , m_allowedToHitTarget(false)
  157.         , m_allowedToUseExpensiveAccessory(false)
  158.         , m_firingReactionTimePassed(false)
  159.         , m_firingReactionTime(0.0f)
  160.         , m_targetApproach(0.0f)
  161.         , m_targetFlee(0.0f)
  162.         , m_targetApproaching(false)
  163.         , m_targetFleeing(false)
  164.         , m_lastTargetValid(false)
  165.         , m_lastTargetPos(ZERO)
  166.         , m_lastTargetSpeed(0)
  167.         , m_chaseSpeed(0.0f)
  168.         , m_chaseSpeedRate(0.0f)
  169.         , m_lastChaseUrgencyDist(-1)
  170.         , m_lastChaseUrgencySpeed(-1)
  171.         , m_vehicleAvoidingTime(0.0f)
  172.         , m_targetLastMissPoint(ZERO)
  173.         , m_targetFocus(0.0f)
  174.         , m_targetZone(AIZONE_OUT)
  175.         , m_targetPosOnSilhouettePlane(ZERO)
  176.         , m_targetDistanceToSilhouette(FLT_MAX)
  177.         , m_targetBiasDirection(0, 0, -1)
  178.         , m_targetEscapeLastMiss(0.0f)
  179.         , m_targetDamageHealthThr(0.0f)
  180.         , m_targetDamageHealthThrHistory(0)
  181.         , m_targetSeenTime(0)
  182.         , m_targetLostTime(0)
  183.         , m_burstEffectTime(0.0f)
  184.         , m_burstEffectState(0)
  185.         , m_targetDazzlingTime(0.0f)
  186.         , m_bCoverFireEnabled(false)
  187.         , m_lastSteerTime(0.0f)
  188.         , m_lastTimeUpdatedBestTarget(0.0f)
  189.         , m_delayedStance(STANCE_NULL)
  190.         , m_delayedStanceMovementCounter(0)
  191.         , m_outOfAmmoTimeOut(0.0f)
  192.         , m_lastAimObstructionResult(true)
  193.         , m_updatePriority(AIPUP_LOW)
  194.         , m_vForcedNavigation(ZERO)
  195.         , m_fForcedNavigationSpeed(0.0f)
  196.         , m_vehicleStickTarget(0)
  197.         , m_lastMissShotsCount(~0l)
  198.         , m_lastHitShotsCount(~0l)
  199.         , m_lastTargetPart(~0l)
  200.         , m_steeringOccupancyBias(0)
  201.         , m_steeringAdjustTime(0)
  202.         , m_steeringEnabled(false)
  203.         , m_alarmedTime(0.0f)
  204.         , m_alarmedLevel(0.0f)
  205.         , m_fireDisabled(0)
  206.         , m_closeRangeStrafing(false)
  207.         , m_damagePartsUpdated(false)
  208. {
  209.         CCCPOINT(CPuppet_CPuppet);
  210.  
  211.         _fastcast_CPuppet = true;
  212.  
  213.         // todo: make it safe, not just casting
  214.         m_pFireCmdGrenade = static_cast<CFireCommandGrenade*>(GetAISystem()->CreateFirecommandHandler("grenade", this));
  215.         if (m_pFireCmdGrenade)
  216.                 m_pFireCmdGrenade->Reset();
  217.  
  218.         m_postureManager.ResetPostures();
  219.         m_postureManager.AddDefaultPostures(PostureManager::AimPosture);
  220.         m_postureManager.AddDefaultPostures(PostureManager::HidePosture);
  221.  
  222.         AILogComment("CPuppet::CPuppet (%p)", this);
  223. }
  224.  
  225. CPuppet::~CPuppet()
  226. {
  227.         // goal ops need to be reset at the top level
  228.         // otherwise their reset methods might operate on already destructed memory
  229.         ResetCurrentPipe(true);
  230.  
  231.         CCCPOINT(CPuppet_Destructor);
  232.  
  233.         AILogComment("CPuppet::~CPuppet %s (%p)", GetName(), this);
  234.  
  235.         SAFE_DELETE(m_pPerceptionHandler);
  236.  
  237.         if (m_pFireCmdGrenade) m_pFireCmdGrenade->Release();
  238.  
  239.         if (m_pFireCmdHandler) m_pFireCmdHandler->Release();
  240.  
  241.         delete m_targetDamageHealthThrHistory;
  242. }
  243.  
  244. void CPuppet::ClearStaticData()
  245. {
  246.         stl::free_container(s_weights);
  247.         stl::free_container(s_sortedHideSpots);
  248.         stl::free_container(s_enemies);
  249.         stl::free_container(s_traversedNodes);
  250.         s_hidespots.clear();
  251. }
  252.  
  253. //===================================================================
  254. // SetRODHandler
  255. //===================================================================
  256. void CPuppet::SetRODHandler(IAIRateOfDeathHandler* pHandler)
  257. {
  258.         CRY_ASSERT(pHandler);
  259.  
  260.         m_pRODHandler = pHandler;
  261. }
  262.  
  263. //===================================================================
  264. // ClearRODHandler
  265. //===================================================================
  266. void CPuppet::ClearRODHandler()
  267. {
  268.         m_pRODHandler = NULL;
  269. }
  270.  
  271. //===================================================================
  272. // GetPerceivedTargetPos
  273. //===================================================================
  274. bool CPuppet::GetPerceivedTargetPos(IAIObject* pTarget, Vec3& vPos) const
  275. {
  276.         CRY_ASSERT(pTarget);
  277.  
  278.         bool bResult = false;
  279.         vPos.zero();
  280.  
  281.         if (pTarget)
  282.         {
  283.                 CAIObject* pTargetObj = (CAIObject*)pTarget;
  284.                 CWeakRef<CAIObject> refTargetAssociation = pTargetObj->GetAssociation();
  285.                 if (refTargetAssociation.IsValid())
  286.                         pTargetObj = refTargetAssociation.GetAIObject();
  287.  
  288.                 // Check potential targets
  289.                 PotentialTargetMap targetMap;
  290.                 if (m_pPerceptionHandler && m_pPerceptionHandler->GetPotentialTargets(targetMap))
  291.                 {
  292.                         PotentialTargetMap::const_iterator itTarget = targetMap.find(GetWeakRef(pTargetObj));
  293.                         if (itTarget != targetMap.end())
  294.                         {
  295.                                 // Found, use perceived if not visual or aggressive
  296.                                 if (itTarget->second.type == AITARGET_VISUAL && itTarget->second.threat == AITHREAT_AGGRESSIVE)
  297.                                 {
  298.                                         IEntity* pTargetEntity = pTargetObj->GetEntity();
  299.                                         CRY_ASSERT(pTargetEntity);
  300.                                         vPos = pTargetEntity->GetWorldPos();
  301.                                 }
  302.                                 else
  303.                                 {
  304.                                         CWeakRef<CAIObject> refDummyRep = itTarget->second.refDummyRepresentation.GetWeakRef();
  305.                                         if (refDummyRep.IsValid())
  306.                                                 vPos = refDummyRep.GetAIObject()->GetPos();
  307.                                 }
  308.                                 bResult = true;
  309.                         }
  310.                 }
  311.         }
  312.  
  313.         return bResult;
  314. }
  315.  
  316. //===================================================================
  317. // ParseParameters
  318. //===================================================================
  319. void CPuppet::ParseParameters(const AIObjectParams& params, bool bParseMovementParams)
  320. {
  321.         CCCPOINT(CPuppet_ParseParameters);
  322.  
  323.         CPipeUser::ParseParameters(params, bParseMovementParams);
  324. }
  325.  
  326. //===================================================================
  327. // QueryCurrentWeaponDescriptor
  328. //===================================================================
  329. const AIWeaponDescriptor& CPuppet::QueryCurrentWeaponDescriptor(bool bIsSecondaryFire, ERequestedGrenadeType prefGrenadeType)
  330. {
  331.         if (IAIActorProxy* pProxy = GetProxy())
  332.         {
  333.                 bool bUpdatedDescriptor = false;
  334.                 EntityId weaponToListenTo = 0;
  335.  
  336.                 // Use the secondary weapon descriptor if requested and available
  337.                 if (!bIsSecondaryFire)
  338.                 {
  339.                         EntityId weaponId = 0;
  340.                         pProxy->GetCurrentWeapon(weaponId);
  341.  
  342.                         weaponToListenTo = weaponId;
  343.  
  344.                         // Bug: The condition below doesn't check if we went from secondary to primary fire (i.e. grenade to scar).
  345.                         // I removed the condition to keep the weapon descriptor up to date. Unfortunately ran every frame.
  346.                         // Investigate how we could fix this. /Jonas
  347.  
  348.                         const bool weaponChanged = (m_currentWeaponId != weaponId);
  349.                         if (weaponChanged || m_fireModeUpdated)
  350.                         {
  351.                                 m_currentWeaponId = weaponId;
  352.                                 m_CurrentWeaponDescriptor = pProxy->GetCurrentWeaponDescriptor();
  353.                                 bUpdatedDescriptor = true;
  354.                         }
  355.                 }
  356.                 else
  357.                 {
  358.                         bUpdatedDescriptor = true;
  359.  
  360.                         pProxy->GetSecWeapon(prefGrenadeType, NULL, &weaponToListenTo);
  361.  
  362.                         if (!pProxy->GetSecWeaponDescriptor(m_CurrentWeaponDescriptor, prefGrenadeType))
  363.                         {
  364.                                 // Use default if no secondary weapon descriptor is available
  365.                                 m_CurrentWeaponDescriptor = AIWeaponDescriptor();
  366.                         }
  367.                 }
  368.  
  369.                 if (bUpdatedDescriptor)
  370.                 {
  371.                         pProxy->EnableWeaponListener(weaponToListenTo, m_CurrentWeaponDescriptor.bSignalOnShoot);
  372.  
  373.                         // Make sure the fire command handler is up to date.
  374.                         // If the current fire command handler is already correct, do not recreate it.
  375.                         if (m_pFireCmdHandler && stricmp(m_CurrentWeaponDescriptor.firecmdHandler.c_str(), m_pFireCmdHandler->GetName()) == 0)
  376.                         {
  377.                                 m_pFireCmdHandler->Reset();
  378.                         }
  379.                         else
  380.                         {
  381.                                 // Release the old handler and create new.
  382.                                 SAFE_RELEASE(m_pFireCmdHandler);
  383.                                 m_pFireCmdHandler = GetAISystem()->CreateFirecommandHandler(m_CurrentWeaponDescriptor.firecmdHandler, this);
  384.                                 if (m_pFireCmdHandler)
  385.                                         m_pFireCmdHandler->Reset();
  386.                         }
  387.                 }
  388.         }
  389.  
  390.         return m_CurrentWeaponDescriptor;
  391. }
  392.  
  393. //===================================================================
  394. // AdjustTargetVisibleRange
  395. //===================================================================
  396. float CPuppet::AdjustTargetVisibleRange(const CAIActor& observer, float fVisibleRange) const
  397. {
  398.         float fRangeScale = 1.0f;
  399.  
  400.         // Adjust using my light level if the observer is affected by light
  401.         if (IsAffectedByLight())
  402.         {
  403.                 const EAILightLevel targetLightLevel = GetLightLevel();
  404.                 switch (targetLightLevel)
  405.                 {
  406.                 //      case AILL_LIGHT: SOMSpeed
  407.                 case AILL_MEDIUM:
  408.                         fRangeScale *= gAIEnv.CVars.SightRangeMediumIllumMod;
  409.                         break;
  410.                 case AILL_DARK:
  411.                         fRangeScale *= gAIEnv.CVars.SightRangeDarkIllumMod;
  412.                         break;
  413.                 case AILL_SUPERDARK:
  414.                         fRangeScale *= gAIEnv.CVars.SightRangeSuperDarkIllumMod;
  415.                         break;
  416.                 }
  417.         }
  418.  
  419.         // Scale down sight range when target is underwater based on distance
  420.         const float fCachedWaterOcclusionValue = GetCachedWaterOcclusionValue();
  421.         if (fCachedWaterOcclusionValue > FLT_EPSILON)
  422.         {
  423.                 const Vec3& observerPos = observer.GetPos();
  424.                 const float fDistance = Distance::Point_Point(GetPos(), observerPos);
  425.                 const float fDistanceFactor = (fVisibleRange > FLT_EPSILON ? GetAISystem()->GetVisPerceptionDistScale(fDistance / fVisibleRange) : 0.0f);
  426.  
  427.                 const float fWaterOcclusionEffect = 2.0f * fCachedWaterOcclusionValue + (1 - fDistanceFactor) * 0.5f;
  428.  
  429.                 fRangeScale *= (fWaterOcclusionEffect > 1.0f ? 0.0f : 1.0f - fWaterOcclusionEffect);
  430.         }
  431.  
  432.         // Return new range
  433.         return fVisibleRange * fRangeScale;
  434. }
  435.  
  436. //===================================================================
  437. // Update
  438. //===================================================================
  439. void CPuppet::Update(EObjectUpdate type)
  440. {
  441.         CCCPOINT(CPuppet_Update);
  442.         FUNCTION_PROFILER(gEnv->pSystem, PROFILE_AI);
  443.  
  444.         m_bDryUpdate = (type != AIUPDATE_FULL);
  445.  
  446.         if (!IsEnabled())
  447.         {
  448.                 AIWarning("CPuppet::Update: Trying to update disabled Puppet: %s", GetName());
  449.                 AIAssert(0);
  450.                 return;
  451.         }
  452.  
  453.         IAIActorProxy* pAIActorProxy = GetProxy();
  454.  
  455.         // There should never be Puppets without proxies.
  456.         if (!pAIActorProxy)
  457.         {
  458.                 AIWarning("CPuppet::Update: Puppet does not have proxy: %s", GetName());
  459.                 AIAssert(0);
  460.                 return;
  461.         }
  462.         // There should never be Puppets without physics.
  463.         if (!GetPhysics())
  464.         {
  465.                 AIWarning("CPuppet::Update: Puppet does not have physics: %s", GetName());
  466.                 AIAssert(0);
  467.                 return;
  468.         }
  469.         // dead Puppets should never be updated
  470.         if (pAIActorProxy->IsDead())
  471.         {
  472.                 AIWarning("CPuppet::Update: Trying to update dead Puppet: %s ", GetName());
  473.                 AIAssert(0);
  474.                 return;
  475.         }
  476.  
  477.         CPipeUser::Update(type);
  478.  
  479.         UpdateHealthTracking();
  480.         m_damagePartsUpdated = false;
  481.  
  482.         static bool doDryUpdateCall = true;
  483.  
  484.         CAIObject* pAttentionTarget = m_refAttentionTarget.GetAIObject();
  485.  
  486.         if (!m_bDryUpdate)
  487.         {
  488.                 CTimeValue fCurrentTime = GetAISystem()->GetFrameStartTime();
  489.                 m_fTimePassed = (m_fLastUpdateTime.GetMilliSecondsAsInt64() > 0)
  490.                                 ? min(0.5f, (fCurrentTime - m_fLastUpdateTime).GetSeconds())
  491.                                 : 0;
  492.                 m_fLastUpdateTime = fCurrentTime;
  493.  
  494.                 // Dario: From Crysis 3 on we don't need to clear the movement direction every frame (04.09.2014)
  495.                 const bool clearMoveDir = false;
  496.  
  497.                 m_State.Reset(clearMoveDir);
  498.  
  499.                 // affect puppet parameters here----------------------------------------
  500.                 if (m_bCanReceiveSignals)
  501.                 {
  502.                         UpdatePuppetInternalState();
  503.  
  504.                         // Marcio: Update the attention target, since most likely the AIOBJECTSTATE evaluation
  505.                         // will only happen this frame, and then we'll miss it
  506.                         pAttentionTarget = m_refAttentionTarget.GetAIObject();
  507.                 }
  508.  
  509.                 GetStateFromActiveGoals(m_State);
  510.  
  511. #ifdef CRYAISYSTEM_DEBUG
  512.                 // Store current position to debug stream.
  513.                 {
  514.                         RecorderEventData recorderEventData(GetPos());
  515.                         RecordEvent(IAIRecordable::E_AGENTPOS, &recorderEventData);
  516.                 }
  517.  
  518.                 // Store current direction to debug stream.
  519.                 {
  520.                         RecorderEventData recorderEventData(GetViewDir());
  521.                         RecordEvent(IAIRecordable::E_AGENTDIR, &recorderEventData);
  522.                 }
  523.  
  524.                 // Store current attention target position to debug stream.
  525.                 if (pAttentionTarget)
  526.                 {
  527.                         RecorderEventData recorderEventData(pAttentionTarget->GetPos());
  528.                         RecordEvent(IAIRecordable::E_ATTENTIONTARGETPOS, &recorderEventData);
  529.                 }
  530. #endif
  531.  
  532.                 // Update last know target position, and last target position constrained into the territory.
  533.                 if (pAttentionTarget && (pAttentionTarget->IsAgent() || (pAttentionTarget->GetType() == AIOBJECT_TARGET)))
  534.                 {
  535.                         m_lastLiveTargetPos = pAttentionTarget->GetPos();
  536.                         m_timeSinceLastLiveTarget = 0.0f;
  537.                 }
  538.                 else
  539.                 {
  540.                         if (m_timeSinceLastLiveTarget >= 0.0f)
  541.                                 m_timeSinceLastLiveTarget += m_fTimePassed;
  542.                 }
  543.  
  544.                 m_lightLevel = GetAISystem()->GetLightManager()->GetLightLevelAt(GetPos(), this, &m_usingCombatLight);
  545.         }
  546.         else if (doDryUpdateCall)
  547.         {
  548.                 //if approaching then always update
  549.                 for (size_t i = 0; i < m_vActiveGoals.size(); i++)
  550.                 {
  551.                         QGoal& Goal = m_vActiveGoals[i];
  552.                         Goal.pGoalOp->ExecuteDry(this);
  553.                 }
  554.         }
  555.  
  556.         if (m_delayedStance != STANCE_NULL)
  557.         {
  558.                 bool wantsToMove = !m_State.vMoveDir.IsZero() && m_State.fDesiredSpeed > 0.0f;
  559.                 if (wantsToMove)
  560.                 {
  561.                         m_delayedStanceMovementCounter++;
  562.                         if (m_delayedStanceMovementCounter > 3)
  563.                         {
  564.                                 m_State.bodystate = m_delayedStance;
  565.                                 m_delayedStance = STANCE_NULL;
  566.                                 m_delayedStanceMovementCounter = 0;
  567.                         }
  568.                 }
  569.                 else
  570.                 {
  571.                         m_delayedStanceMovementCounter = 0;
  572.                 }
  573.         }
  574.  
  575.         HandleNavSOFailure();
  576.         SyncActorTargetPhaseWithAIProxy();
  577.  
  578.         //--------------------------------------------------------
  579.         // Update the look at and strafe logic.
  580.         // Do not perform these actions if the AI is paused for things like communications.
  581.         if (!m_paused)
  582.         {
  583.                 if (GetSubType() == CAIObject::STP_2D_FLY)
  584.                         UpdateLookTarget3D(pAttentionTarget); //this is only for the scout now.
  585.                 else
  586.                         UpdateLookTarget(pAttentionTarget);
  587.         }
  588.  
  589.         //--------------------------------------------------------
  590.         // Update the body target
  591.         m_State.vBodyTargetDir = m_vBodyTargetDir;
  592.         m_State.vDesiredBodyDirectionAtTarget = m_vDesiredBodyDirectionAtTarget;
  593.         m_State.movementContext = m_movementContext;
  594.  
  595.         if (pAttentionTarget)
  596.         {
  597.                 m_State.nTargetType = pAttentionTarget->GetType();
  598.                 m_State.bTargetEnabled = pAttentionTarget->IsEnabled();
  599.         }
  600.         else
  601.         {
  602.                 m_State.nTargetType = -1;
  603.                 m_State.bTargetEnabled = false;
  604.                 m_State.eTargetThreat = AITHREAT_NONE;
  605.                 m_State.eTargetType = AITARGET_NONE;
  606.         }
  607.  
  608.         const float dt = GetAISystem()->GetFrameDeltaTime();
  609.  
  610.         m_targetDazzlingTime = max(0.0f, m_targetDazzlingTime - dt);
  611.         if (GetAttentionTargetType() == AITARGET_VISUAL && GetAttentionTargetThreat() == AITHREAT_AGGRESSIVE)
  612.         {
  613.                 m_targetLostTime = 0.0f;
  614.                 m_targetSeenTime = min(m_targetSeenTime + dt, 10.0f);
  615.         }
  616.         else
  617.         {
  618.                 m_targetLostTime += dt;
  619.                 m_targetSeenTime = max(0.0f, m_targetSeenTime - dt);
  620.         }
  621.  
  622.         FireCommand(gEnv->pTimer->GetFrameTime());
  623.  
  624.         if (m_Parameters.m_fAwarenessOfPlayer > 0)
  625.                 CheckAwarenessPlayer();
  626.  
  627.         // Time out unreachable hidepoints.
  628.         for (TimeOutVec3List::iterator it = m_recentUnreachableHideObjects.begin(); it != m_recentUnreachableHideObjects.end(); )
  629.         {
  630.                 it->first -= GetAISystem()->GetFrameDeltaTime();
  631.                 if (it->first < 0.0f)
  632.                         it = m_recentUnreachableHideObjects.erase(it);
  633.                 else
  634.                         ++it;
  635.         }
  636.  
  637.         UpdateCloakScale();
  638.  
  639.         m_State.vForcedNavigation = m_vForcedNavigation;
  640.         m_State.fForcedNavigationSpeed = m_fForcedNavigationSpeed;
  641. }
  642.  
  643. void CPuppet::UpdateProxy(EObjectUpdate type)
  644. {
  645.         IAIActorProxy* pAIActorProxy = GetProxy();
  646.         // There should never be Puppets without proxies.
  647.         if (!pAIActorProxy)
  648.         {
  649.                 AIWarning("CPuppet::UpdateProxy: Puppet does not have proxy: %s", GetName());
  650.                 AIAssert(0);
  651.                 return;
  652.         }
  653.  
  654.         SetMoveDir(m_State.vMoveDir);
  655.  
  656.         if (gAIEnv.CVars.UpdateProxy)
  657.         {
  658.                 // Force stance etc
  659.                 //              int lastStance = m_State.bodystate;
  660.                 bool forcedPosture = false;
  661.                 if (strcmp(gAIEnv.CVars.ForcePosture, "0"))
  662.                 {
  663.                         PostureManager::PostureInfo posture;
  664.  
  665.                         if (m_postureManager.GetPostureByName(gAIEnv.CVars.ForcePosture, &posture))
  666.                         {
  667.                                 forcedPosture = true;
  668.  
  669.                                 m_State.bodystate = posture.stance;
  670.                                 m_State.lean = posture.lean;
  671.                                 m_State.peekOver = posture.peekOver;
  672.  
  673.                                 if (!posture.agInput.empty())
  674.                                         pAIActorProxy->SetAGInput(AIAG_ACTION, posture.agInput.c_str());
  675.                                 else
  676.                                         pAIActorProxy->ResetAGInput(AIAG_ACTION);
  677.                         }
  678.                 }
  679.  
  680.                 if (!forcedPosture)
  681.                 {
  682.                         if (gAIEnv.CVars.ForceStance > -1)
  683.                                 m_State.bodystate = gAIEnv.CVars.ForceStance;
  684.  
  685.                         if (strcmp(gAIEnv.CVars.ForceAGAction, "0"))
  686.                                 pAIActorProxy->SetAGInput(AIAG_ACTION, gAIEnv.CVars.ForceAGAction);
  687.                 }
  688.  
  689.                 if (strcmp(gAIEnv.CVars.ForceAGSignal, "0"))
  690.                         pAIActorProxy->SetAGInput(AIAG_SIGNAL, gAIEnv.CVars.ForceAGSignal);
  691.  
  692.                 if (gAIEnv.CVars.ForceAllowStrafing > -1)
  693.                         m_State.allowStrafing = gAIEnv.CVars.ForceAllowStrafing != 0;
  694.  
  695.                 const char* forceLookAimTarget = gAIEnv.CVars.ForceLookAimTarget;
  696.                 if (strcmp(forceLookAimTarget, "none") != 0)
  697.                 {
  698.                         Vec3 targetPos = GetPos();
  699.                         if (strcmp(forceLookAimTarget, "x") == 0)
  700.                                 targetPos += Vec3(10, 0, 0);
  701.                         else if (strcmp(forceLookAimTarget, "y") == 0)
  702.                                 targetPos += Vec3(0, 10, 0);
  703.                         else if (strcmp(forceLookAimTarget, "xz") == 0)
  704.                                 targetPos += Vec3(10, 0, 10);
  705.                         else if (strcmp(forceLookAimTarget, "yz") == 0)
  706.                                 targetPos += Vec3(0, 10, 10);
  707.                         else
  708.                         {
  709.                                 IEntity* pEntity = gEnv->pEntitySystem->FindEntityByName(forceLookAimTarget);
  710.                                 if (pEntity)
  711.                                         targetPos = pEntity->GetPos();
  712.                                 else
  713.                                         targetPos.zero();
  714.                         }
  715.  
  716.                         m_State.vLookTargetPos = targetPos;
  717.                         m_State.vAimTargetPos = targetPos;
  718.                         m_State.aimTargetIsValid = true;
  719.                 }
  720.  
  721.                 if (!m_bDryUpdate)
  722.                 {
  723.                         // If secondary fire went through, clear throw grenade request
  724.                         if (m_bGrenadeThrowRequested && (m_State.fireSecondary != eAIFS_Blocking))
  725.                                 m_bGrenadeThrowRequested = false;
  726.                 }
  727.  
  728.                 // Always update the AI proxy, also during dry updates. The Animation system
  729.                 // needs correct and constantly updated predictions to correctly set animation
  730.                 // parameters.
  731.                 // (MATT) Try avoiding UpdateMind, which triggers script, signal and behaviour code, if only a dry update {2009/12/06}
  732.                 pAIActorProxy->Update(m_State, !m_bDryUpdate);
  733.  
  734.                 // Restore foced state.
  735.                 //m_State.bodystate = lastStance;
  736.  
  737.                 if (IsEnabled()) // the puppet may have been killed above in this loop (say, in GetProxy()->Update(m_State))
  738.                         UpdateAlertness();
  739.         }
  740.  
  741.         // Make sure we haven't played with that value during our update
  742.         assert(m_bDryUpdate == (type == AIUPDATE_DRY));
  743.  
  744. #ifdef CRYAISYSTEM_DEBUG
  745.         if (!m_bDryUpdate)
  746.         {
  747.                 // Health
  748.                 RecorderEventData recorderEventData(pAIActorProxy->GetActorHealth());
  749.                 RecordEvent(IAIRecordable::E_HEALTH, &recorderEventData);
  750.         }
  751. #endif
  752. }
  753.  
  754. //===================================================================
  755. // UpdateTargetMovementState
  756. //===================================================================
  757. void CPuppet::UpdateTargetMovementState()
  758. {
  759.         const float dt = m_fTimePassed;
  760.         CAIObject* pAttentionTarget = m_refAttentionTarget.GetAIObject();
  761.  
  762.         if (!pAttentionTarget || dt < 0.00001f)
  763.         {
  764.                 m_lastTargetValid = false;
  765.                 m_targetApproaching = false;
  766.                 m_targetFleeing = false;
  767.                 m_targetApproach = 0;
  768.                 m_targetFlee = 0;
  769.                 return;
  770.         }
  771.  
  772.         bool targetValid;
  773.         switch (pAttentionTarget->GetType())
  774.         {
  775.         case AIOBJECT_TARGET:
  776.         case AIOBJECT_PLAYER:
  777.         case AIOBJECT_ACTOR:
  778.                 targetValid = true;
  779.                 break;
  780.         default:
  781.                 targetValid = false;
  782.         }
  783.  
  784.         Vec3 targetPos = pAttentionTarget->GetPos();
  785.         Vec3 targetDir = pAttentionTarget->GetMoveDir();
  786.         float targetSpeed = pAttentionTarget->GetVelocity().GetLength();
  787.         const Vec3& puppetPos = GetPos();
  788.  
  789.         if (!m_lastTargetValid)
  790.         {
  791.                 m_lastTargetValid = true;
  792.                 m_lastTargetSpeed = targetSpeed;
  793.                 m_lastTargetPos = targetPos;
  794.         }
  795.         const float fleeMin = 10.0f;
  796.         const float approachMax = 20.0f;
  797.  
  798.         if (!targetValid && m_lastTargetValid)
  799.         {
  800.                 targetPos = m_lastTargetPos;
  801.                 targetSpeed = m_lastTargetSpeed;
  802.         }
  803.  
  804.         {
  805.                 float curDist = Distance::Point_Point(targetPos, puppetPos);
  806.                 float lastDist = Distance::Point_Point(m_lastTargetPos, puppetPos);
  807.  
  808.                 Vec3 dirTargetToPuppet = puppetPos - targetPos;
  809.                 dirTargetToPuppet.NormalizeSafe();
  810.  
  811.                 float dot = (1.0f + dirTargetToPuppet.Dot(targetDir)) * 0.5f;
  812.  
  813.                 bool movingTowards = curDist < lastDist && targetSpeed > 0; //fabsf(curDist - lastDist) > 0.01f;
  814.                 bool movingAway = curDist > lastDist && targetSpeed > 0;    //fabsf(curDist - lastDist) > 0.01f;
  815.  
  816.                 if (curDist < approachMax && movingTowards)
  817.                         m_targetApproach += targetSpeed * sqr(dot) * 0.25f;
  818.                 else
  819.                         m_targetApproach -= dt * 2.0f;
  820.  
  821.                 if (curDist > fleeMin && movingAway)
  822.                         m_targetFlee += targetSpeed * sqr(1.0f - dot) * 0.1f;
  823.                 else
  824.                         m_targetFlee -= dt * 2.0f;
  825.  
  826.                 m_lastTargetPos = targetPos;
  827.         }
  828.  
  829.         m_targetApproach = clamp_tpl(m_targetApproach, 0.0f, 10.0f);
  830.         m_targetFlee = clamp_tpl(m_targetFlee, 0.0f, 10.0f);
  831.  
  832.         bool approaching = m_targetApproach > 9.9f;
  833.         bool fleeing = m_targetFlee > 9.9f;
  834.  
  835.         if (approaching != m_targetApproaching)
  836.         {
  837.                 m_targetApproaching = approaching;
  838.                 if (m_targetApproaching)
  839.                 {
  840.                         m_targetApproach = 0;
  841.                         SetSignal(1, "OnTargetApproaching", pAttentionTarget->GetEntity(), 0, gAIEnv.SignalCRCs.m_nOnTargetApproaching);
  842.                 }
  843.         }
  844.  
  845.         if (fleeing != m_targetFleeing)
  846.         {
  847.                 m_targetFleeing = fleeing;
  848.                 if (m_targetFleeing)
  849.                 {
  850.                         m_targetFlee = 0;
  851.                         SetSignal(1, "OnTargetFleeing", pAttentionTarget->GetEntity(), 0, gAIEnv.SignalCRCs.m_nOnTargetFleeing);
  852.                 }
  853.         }
  854. }
  855.  
  856. //===================================================================
  857. // UpdateAlertness
  858. //===================================================================
  859. void CPuppet::UpdateAlertness()
  860. {
  861.         CRY_ASSERT(IsEnabled());
  862.  
  863.         int nextAlertness = GetProxy()->GetAlertnessState();
  864.         if ((m_Alertness != nextAlertness) && m_Parameters.factionHostility)
  865.         {
  866.                 if (m_Alertness >= 0)
  867.                 {
  868.                         int& counter = GetAISystem()->m_AlertnessCounters[m_Alertness];
  869.                         if (counter > 0)
  870.                         {
  871.                                 --counter;
  872.                         }
  873.                 }
  874.  
  875.                 CRY_ASSERT(NUM_ALERTNESS_COUNTERS > nextAlertness && nextAlertness >= 0);
  876.                 if (NUM_ALERTNESS_COUNTERS > nextAlertness && nextAlertness >= 0)
  877.                 {
  878.                         ++GetAISystem()->m_AlertnessCounters[nextAlertness];
  879.                 }
  880.         }
  881.  
  882.         m_Alertness = nextAlertness;
  883. }
  884.  
  885. //===================================================================
  886. // ResetAlertness
  887. //===================================================================
  888. void CPuppet::ResetAlertness()
  889. {
  890.         // get alertness before doing GetProxy()->Reset()!!!
  891.         if (m_Alertness >= 0 && m_Parameters.factionHostility &&
  892.             GetAISystem()->m_AlertnessCounters[m_Alertness] > 0)
  893.                 --GetAISystem()->m_AlertnessCounters[m_Alertness];
  894.         m_Alertness = -1;
  895. }
  896.  
  897. //===================================================================
  898. // GetEventOwner
  899. //===================================================================
  900. IAIObject* CPuppet::GetEventOwner(IAIObject* pObject) const
  901. {
  902.         IAIObject* pOwner = 0;
  903.  
  904.         if (m_pPerceptionHandler)
  905.         {
  906.                 CWeakRef<CAIObject> refObject = GetWeakRefSafe((CAIObject*)pObject);
  907.                 pOwner = m_pPerceptionHandler->GetEventOwner(refObject);
  908.         }
  909.  
  910.         return pOwner;
  911. }
  912.  
  913. //===================================================================
  914. // GetEventOwner
  915. //===================================================================
  916. CAIObject* CPuppet::GetEventOwner(CWeakRef<CAIObject> refOwned) const
  917. {
  918.         if (!refOwned.IsValid()) return 0;
  919.         // TO DO: for memory/sound target etc, probably it's better to set their association equal to the owner
  920.         // instead of searching for it here
  921.         return (m_pPerceptionHandler ? m_pPerceptionHandler->GetEventOwner(refOwned) : NULL);
  922. }
  923.  
  924. //===================================================================
  925. // UpdateTargetSelection
  926. //===================================================================
  927. bool CPuppet::UpdateTargetSelection(STargetSelectionInfo& targetSelectionInfo)
  928. {
  929.         bool bResult = false;
  930.  
  931.         if (gAIEnv.CVars.TargetTracking)
  932.         {
  933.                 if (GetTargetTrackBestTarget(targetSelectionInfo.bestTarget, targetSelectionInfo.pTargetInfo, targetSelectionInfo.bCurrentTargetErased))
  934.                 {
  935.                         if (targetSelectionInfo.pTargetInfo &&
  936.                             targetSelectionInfo.pTargetInfo->type == AITARGET_VISUAL &&
  937.                             targetSelectionInfo.pTargetInfo->threat >= AITHREAT_AGGRESSIVE)
  938.                         {
  939.                                 SetAlarmed();
  940.                         }
  941.                         bResult = true;
  942.                 }
  943.         }
  944.         else
  945.         {
  946.                 // Disabled
  947.                 bResult = false;
  948.         }
  949.  
  950.         const Group& group = gAIEnv.pGroupManager->GetGroup(GetGroupId());
  951.  
  952.         if ((group.GetTargetType() > AITARGET_NONE) && (!targetSelectionInfo.pTargetInfo || (group.GetTargetThreat() >= targetSelectionInfo.pTargetInfo->threat && group.GetTargetType() > targetSelectionInfo.pTargetInfo->type)))
  953.         {
  954.                 targetSelectionInfo.bestTarget = group.GetTarget().GetWeakRef();
  955.                 targetSelectionInfo.targetThreat = group.GetTargetThreat();
  956.                 targetSelectionInfo.targetType = group.GetTargetType();
  957.                 targetSelectionInfo.bIsGroupTarget = true;
  958.  
  959.                 bResult = true;
  960.         }
  961.         else if (targetSelectionInfo.pTargetInfo)
  962.         {
  963.                 targetSelectionInfo.targetThreat = targetSelectionInfo.pTargetInfo->threat;
  964.                 targetSelectionInfo.targetType = targetSelectionInfo.pTargetInfo->type;
  965.         }
  966.  
  967.         return bResult;
  968. }
  969.  
  970. //===================================================================
  971. // GetTargetTrackBestTarget
  972. //===================================================================
  973. bool CPuppet::GetTargetTrackBestTarget(CWeakRef<CAIObject>& refBestTarget, SAIPotentialTarget*& pTargetInfo, bool& bCurrentTargetErased) const
  974. {
  975.         bool bResult = false;
  976.  
  977.         refBestTarget.Reset();
  978.         pTargetInfo = NULL;
  979.         bCurrentTargetErased = false;
  980.  
  981.         tAIObjectID objectId = GetAIObjectID();
  982.         CRY_ASSERT(objectId > 0);
  983.  
  984.         tAIObjectID targetId = 0;
  985.         gAIEnv.pTargetTrackManager->Update(objectId);
  986.         const uint32 uTargetMethod = (TargetTrackHelpers::eDTM_Select_Highest);
  987.         if (gAIEnv.pTargetTrackManager->GetDesiredTarget(objectId, uTargetMethod, refBestTarget, pTargetInfo))
  988.         {
  989.                 bResult = true;
  990.         }
  991.         else
  992.         {
  993.                 bCurrentTargetErased = true;
  994.         }
  995.  
  996.         return bResult;
  997. }
  998.  
  999. //===================================================================
  1000. // UpdatePuppetInternalState
  1001. //===================================================================
  1002. void CPuppet::UpdatePuppetInternalState()
  1003. {
  1004.         FUNCTION_PROFILER(gEnv->pSystem, PROFILE_AI);
  1005.         CCCPOINT(CPuppet_UpdatePuppetInternalState);
  1006.  
  1007.         CAIObject* pAttentionTarget = m_refAttentionTarget.GetAIObject();
  1008.  
  1009.         assert(!m_bDryUpdate);
  1010.         // Update alarmed state
  1011.         m_alarmedTime -= m_fTimePassed;
  1012.         if (m_alarmedTime < 0.0f)
  1013.                 m_alarmedTime = 0.0f;
  1014.  
  1015.         // Sight range threshold.
  1016.         // The sight attenuation range envelope changes based on the alarmed state.
  1017.         // The threshold is changed smoothly.
  1018.         const float alarmLevelChangeTime = 3.0f;
  1019.         const float alarmLevelGoal = IsAlarmed() ? 1.0f : 0.0f;
  1020.         m_alarmedLevel += (alarmLevelGoal - m_alarmedLevel) * (m_fTimePassed / alarmLevelChangeTime);
  1021.         Limit(m_alarmedLevel, 0.0f, 1.0f);
  1022.  
  1023.         STargetSelectionInfo targetSelectionInfo;
  1024.         if (UpdateTargetSelection(targetSelectionInfo))
  1025.         {
  1026.                 SAIPotentialTarget* bestTargetEvent = targetSelectionInfo.pTargetInfo;
  1027.  
  1028.                 const EAITargetThreat oldThreat = m_State.eTargetThreat;
  1029.                 const EAITargetThreat newThreat = targetSelectionInfo.targetThreat;
  1030.  
  1031.                 if (newThreat > oldThreat && newThreat >= AITHREAT_THREATENING)
  1032.                 {
  1033.                         gEnv->pAISystem->GetAIActionManager()->AbortAIAction(GetEntity());
  1034.                 }
  1035.  
  1036.                 m_State.eTargetThreat = targetSelectionInfo.targetThreat;
  1037.                 m_State.eTargetType = targetSelectionInfo.targetType;
  1038.                 m_State.eTargetID = targetSelectionInfo.bestTarget.GetObjectID();
  1039.                 m_State.eTargetStuntReaction = AITSR_NONE;
  1040.                 m_State.bTargetIsGroupTarget = targetSelectionInfo.bIsGroupTarget;
  1041.  
  1042.                 CAIObject* bestTarget = targetSelectionInfo.bestTarget.GetAIObject();
  1043.                 if (bestTarget)
  1044.                 {
  1045.                         m_State.vTargetPos = bestTarget->GetPos();
  1046.                 }
  1047.  
  1048.                 if (bestTarget != pAttentionTarget)
  1049.                 {
  1050.                         // New attention target
  1051.                         SetAttentionTarget(GetWeakRef(bestTarget));
  1052.                         m_AttTargetPersistenceTimeout = m_Parameters.m_PerceptionParams.targetPersistence;
  1053.  
  1054.                         // When seeing a visible target, check for stunt reaction.
  1055.                         if (bestTarget && m_State.eTargetType == AITARGET_VISUAL && m_State.eTargetThreat == AITHREAT_AGGRESSIVE)
  1056.                         {
  1057.                                 if (CAIPlayer* pPlayer = bestTarget->CastToCAIPlayer())
  1058.                                 {
  1059.                                         if (IsHostile(pPlayer))
  1060.                                         {
  1061.                                                 bool isStunt = pPlayer->IsDoingStuntActionRelatedTo(GetPos(), m_Parameters.m_PerceptionParams.sightRange / 5.0f);
  1062.                                                 if (m_targetLostTime > m_Parameters.m_PerceptionParams.stuntReactionTimeOut && isStunt)
  1063.                                                         m_State.eTargetStuntReaction = AITSR_SEE_STUNT_ACTION;
  1064.                                                 else if (pPlayer->IsCloakEffective(bestTarget->GetPos()))
  1065.                                                         m_State.eTargetStuntReaction = AITSR_SEE_CLOAKED;
  1066.                                         }
  1067.                                 }
  1068.                         }
  1069.  
  1070.                         EntityId bestTargetId = bestTarget ? bestTarget->GetEntityID() : 0;
  1071.                         if (bestTarget && !bestTargetId)
  1072.                         {
  1073.                                 CWeakRef<CAIObject> refAssociation = bestTarget->GetAssociation();
  1074.                                 if (refAssociation.IsValid())
  1075.                                         bestTargetId = refAssociation.GetAIObject()->GetEntityID();
  1076.                         }
  1077.  
  1078.                         // Keep track of peak threat level and type here
  1079.                         CTimeValue curTime = GetAISystem()->GetFrameStartTime();
  1080.  
  1081.                         if ((targetSelectionInfo.targetThreat > m_State.ePeakTargetThreat) || (curTime - m_lastTimeUpdatedBestTarget).GetSeconds() > 30.0f)
  1082.                         {
  1083.                                 // Save the previous peak now
  1084.                                 m_State.ePreviousPeakTargetThreat = m_State.ePeakTargetThreat;
  1085.                                 m_State.ePreviousPeakTargetType = m_State.ePeakTargetType;
  1086.                                 m_State.ePreviousPeakTargetID = m_State.ePeakTargetID;
  1087.  
  1088.                                 // Now set the new peak
  1089.                                 m_State.ePeakTargetThreat = m_State.eTargetThreat;
  1090.                                 m_State.ePeakTargetType = m_State.eTargetType;
  1091.                                 m_State.ePeakTargetID = bestTarget ? bestTarget->GetAIObjectID() : INVALID_AIOBJECTID;
  1092.  
  1093.                                 // Update the last time we found a better target here
  1094.                                 m_lastTimeUpdatedBestTarget = curTime;
  1095.                         }
  1096.  
  1097.                         // Inform AI of change
  1098.                         IAISignalExtraData* pData = GetAISystem()->CreateSignalExtraData();
  1099.                         CRY_ASSERT(pData);
  1100.                         pData->nID = bestTargetId;
  1101.                         pData->fValue = (targetSelectionInfo.bIsGroupTarget ? 1.0f : 0.0f);
  1102.                         pData->iValue = m_State.eTargetType;
  1103.                         pData->iValue2 = m_State.eTargetThreat;
  1104.                         SetSignal(0, "OnNewAttentionTarget", GetEntity(), pData, gAIEnv.SignalCRCs.m_nOnNewAttentionTarget);
  1105.  
  1106.                         if (bestTargetEvent)
  1107.                                 bestTargetEvent->bNeedsUpdating = false;
  1108.                 }
  1109.                 else if (pAttentionTarget)
  1110.                 {
  1111.                         if (m_AttTargetThreat != m_State.eTargetThreat)
  1112.                         {
  1113.                                 IAISignalExtraData* pData = GetAISystem()->CreateSignalExtraData();
  1114.                                 pData->iValue = m_State.eTargetThreat;
  1115.                                 SetSignal(0, "OnAttentionTargetThreatChanged", GetEntity(), pData, gAIEnv.SignalCRCs.m_nOnAttentionTargetThreatChanged);
  1116.                         }
  1117.  
  1118.                         // Handle state change of the current attention target.
  1119.  
  1120.                         // The state lowering.
  1121.                         if (m_AttTargetThreat >= AITHREAT_AGGRESSIVE && m_State.eTargetThreat < AITHREAT_AGGRESSIVE)
  1122.                         {
  1123.                                 // Aggressive -> threatening
  1124.                                 if (m_State.eTargetType == AITARGET_VISUAL || m_State.eTargetType == AITARGET_MEMORY)
  1125.                                         SetSignal(0, "OnNoTargetVisible", GetEntity(), 0, gAIEnv.SignalCRCs.m_nOnNoTargetVisible);
  1126.                         }
  1127.                         else if (m_AttTargetThreat >= AITHREAT_THREATENING && m_State.eTargetThreat < AITHREAT_THREATENING)
  1128.                         {
  1129.                                 // Threatening -> interesting
  1130.                                 SetSignal(0, "OnNoTargetAwareness", GetEntity(), 0, gAIEnv.SignalCRCs.m_nOnNoTargetAwareness);
  1131.                         }
  1132.  
  1133.                         if (bestTargetEvent)
  1134.                         {
  1135.                                 // The state rising.
  1136.                                 // Use the exposure threat to trigger the signals. This will result multiple
  1137.                                 // same signals (like on threatening sound) to be sent if the exposure is
  1138.                                 // crossing the threshold. This should allow more responsive behaviors, but
  1139.                                 // at the same time prevent too many signals.
  1140.                                 // The signal is resent only if the exposure is crossing the current or higher threshold.
  1141.                                 if (bestTargetEvent->bNeedsUpdating || bestTargetEvent->exposureThreat > bestTargetEvent->threat || m_AttTargetType != bestTargetEvent->type)
  1142.                                 {
  1143.                                         bestTargetEvent->bNeedsUpdating = false;
  1144.  
  1145.                                         if (m_AttTargetExposureThreat <= AITHREAT_AGGRESSIVE && bestTargetEvent->exposureThreat >= AITHREAT_AGGRESSIVE)
  1146.                                         {
  1147.                                                 // Threatening -> aggressive
  1148.                                                 if (bestTargetEvent->type == AITARGET_VISUAL)
  1149.                                                 {
  1150.                                                         if (CAIPlayer* pPlayer = bestTarget->CastToCAIPlayer())
  1151.                                                         {
  1152.                                                                 if (IsHostile(pPlayer))
  1153.                                                                 {
  1154.                                                                         bool isStunt = pPlayer->IsDoingStuntActionRelatedTo(GetPos(), m_Parameters.m_PerceptionParams.sightRange / 5.0f);
  1155.                                                                         if (m_targetLostTime > m_Parameters.m_PerceptionParams.stuntReactionTimeOut && isStunt)
  1156.                                                                                 m_State.eTargetStuntReaction = AITSR_SEE_STUNT_ACTION;
  1157.                                                                         else if (pPlayer->IsCloakEffective(bestTarget->GetPos()))
  1158.                                                                                 m_State.eTargetStuntReaction = AITSR_SEE_CLOAKED;
  1159.                                                                 }
  1160.                                                         }
  1161.                                                 }
  1162.                                         }
  1163.                                 }
  1164.                         }
  1165.                 }
  1166.  
  1167.                 // Keep track of the current state, used to track the state transitions.
  1168.                 m_AttTargetType = m_State.eTargetType;
  1169.                 m_AttTargetThreat = m_State.eTargetThreat;
  1170.                 m_AttTargetExposureThreat = bestTargetEvent ? bestTargetEvent->exposureThreat : m_State.eTargetThreat;
  1171.         }
  1172.         else
  1173.         {
  1174.                 // No attention target, reset if the current target is erased.
  1175.                 // The check for current target erased allows to forcefully set the
  1176.                 // attention target.
  1177.                 if (pAttentionTarget)
  1178.                 {
  1179.                         if (targetSelectionInfo.bCurrentTargetErased)
  1180.                                 SetAttentionTarget(NILREF);
  1181.                 }
  1182.  
  1183.                 m_AttTargetType = AITARGET_NONE;
  1184.                 m_AttTargetThreat = AITHREAT_NONE;
  1185.                 m_AttTargetExposureThreat = AITHREAT_NONE;
  1186.  
  1187.                 m_State.eTargetType = AITARGET_NONE;
  1188.                 m_State.eTargetThreat = AITHREAT_NONE;
  1189.         }
  1190.  
  1191.         // update devaluated points
  1192.         DevaluedMap::iterator di, next;
  1193.         for (di = m_mapDevaluedPoints.begin(); di != m_mapDevaluedPoints.end(); di = next)
  1194.         {
  1195.                 next = di;
  1196.                 ++next;
  1197.                 di->second -= m_fTimePassed;
  1198.                 if (di->second < 0 || !di->first.IsValid())
  1199.                 {
  1200.                         CCCPOINT(CPuppet_UpdatePuppetInternalState_DevaluedPoints);
  1201.  
  1202.                         m_mapDevaluedPoints.erase(di);
  1203.                 }
  1204.         }
  1205.  
  1206.         UpdateTargetMovementState();
  1207.  
  1208.         // Update attention-target related info:
  1209.         // distance from target, in/out of territory status
  1210.         if (pAttentionTarget)
  1211.         {
  1212.                 const Vec3& vAttTargetPos = pAttentionTarget->GetPos();
  1213.  
  1214.                 m_State.fDistanceFromTarget = Distance::Point_Point(vAttTargetPos, GetPos());
  1215.  
  1216.                 if (m_territoryShape)
  1217.                 {
  1218.                         m_attTargetOutOfTerritory.bState = !m_territoryShape->IsPointInsideShape(vAttTargetPos, false);
  1219.                 }
  1220.                 else
  1221.                 {
  1222.                         m_attTargetOutOfTerritory.bState = false;
  1223.                 }
  1224.         }
  1225.         else
  1226.         {
  1227.                 m_State.fDistanceFromTarget = FLT_MAX;
  1228.                 m_attTargetOutOfTerritory.bState = false;
  1229.         }
  1230.  
  1231.         if (m_attTargetOutOfTerritory.CheckUpdate())
  1232.         {
  1233.                 bool bState = m_attTargetOutOfTerritory.bState;
  1234.                 const char* sSignal = (bState ? "OnTargetOutOfTerritory" : "OnTargetInTerritory");
  1235.                 SetSignal(AISIGNAL_DEFAULT, sSignal, NULL, NULL, 0);
  1236.         }
  1237. }
  1238.  
  1239. //===================================================================
  1240. // Event
  1241. //===================================================================
  1242. void CPuppet::Event(unsigned short eType, SAIEVENT* pEvent)
  1243. {
  1244.         CAISystem* pAISystem = GetAISystem();
  1245.         //      pAISystem->Record(this, IAIRecordable::E_EVENT, GetEventName(eType));
  1246.         bool bWasEnabled = m_bEnabled;
  1247.  
  1248.         switch (eType)
  1249.         {
  1250.         case AIEVENT_DROPBEACON:
  1251.                 UpdateBeacon();
  1252.                 break;
  1253.         case AIEVENT_CLEAR:
  1254.                 {
  1255.                         CCCPOINT(CPuppet_Event_Clear);
  1256.  
  1257.                         ClearActiveGoals();
  1258.                         m_bLooseAttention = false;
  1259.                         pAISystem->FreeFormationPoint(GetWeakRef(this));
  1260.                         SetAttentionTarget(NILREF);
  1261.                         m_bBlocked = false;
  1262.                         m_bCanReceiveSignals = true;
  1263.                 }
  1264.                 break;
  1265.         case AIEVENT_CLEARACTIVEGOALS:
  1266.                 ClearActiveGoals();
  1267.                 m_bBlocked = false;
  1268.                 break;
  1269.         case AIEVENT_DISABLE:
  1270.                 {
  1271.                         m_bEnabled = false;
  1272.                         //                      m_bCheckedBody = true;
  1273.  
  1274.                         // Reset and disable the agent's target track
  1275.                         const tAIObjectID aiObjectId = GetAIObjectID();
  1276.                         gAIEnv.pTargetTrackManager->ResetAgent(aiObjectId);
  1277.                         gAIEnv.pTargetTrackManager->SetAgentEnabled(aiObjectId, false);
  1278.  
  1279.                         pAISystem->UpdateGroupStatus(GetGroupId());
  1280.                         pAISystem->NotifyEnableState(this, m_bEnabled);
  1281.  
  1282.                         SetObserver(false);
  1283.                         SetObservable(false);
  1284.  
  1285.                         SetNavSOFailureStates();
  1286.                 }
  1287.                 break;
  1288.         case AIEVENT_ENABLE:
  1289.                 if (GetProxy()->IsDead())
  1290.                 {
  1291.                         // can happen when rendering dead bodies? AI should not be enabled
  1292.                         //                              AIAssert(!"Trying to enable dead character!");
  1293.                         return;
  1294.                 }
  1295.                 m_bEnabled = true;
  1296.                 gAIEnv.pTargetTrackManager->SetAgentEnabled(GetAIObjectID(), true);
  1297.                 pAISystem->UpdateGroupStatus(GetGroupId());
  1298.                 pAISystem->NotifyEnableState(this, m_bEnabled);
  1299.  
  1300.                 SetObserver(true);
  1301.                 SetObservable(true);
  1302.                 break;
  1303.         case AIEVENT_SLEEP:
  1304.                 m_fireMode = FIREMODE_OFF;
  1305.                 m_bCheckedBody = false;
  1306.                 if (GetProxy()->GetLinkedVehicleEntityId() == 0)
  1307.                 {
  1308.                         m_bEnabled = false;
  1309.                         pAISystem->NotifyEnableState(this, m_bEnabled);
  1310.                 }
  1311.                 break;
  1312.         case AIEVENT_WAKEUP:
  1313.                 ClearActiveGoals();
  1314.                 m_bLooseAttention = false;
  1315.                 SetAttentionTarget(NILREF);
  1316.                 m_bEnabled = true;
  1317.                 pAISystem->NotifyEnableState(this, m_bEnabled);
  1318.                 m_bCheckedBody = true;
  1319.                 pAISystem->UpdateGroupStatus(GetGroupId());
  1320.                 break;
  1321.         case AIEVENT_ONVISUALSTIMULUS:
  1322.                 HandleVisualStimulus(pEvent);
  1323.                 break;
  1324.         case AIEVENT_ONSOUNDEVENT:
  1325.                 HandleSoundEvent(pEvent);
  1326.                 break;
  1327.         case AIEVENT_ONBULLETRAIN:
  1328.                 HandleBulletRain(pEvent);
  1329.                 break;
  1330.         case AIEVENT_AGENTDIED:
  1331.                 {
  1332.                         SetNavSOFailureStates();
  1333.  
  1334.                         if (m_inCover || m_movingToCover)
  1335.                         {
  1336.                                 SetCoverRegister(CoverID());
  1337.                                 m_coverUser.SetCoverID(CoverID());
  1338.                         }
  1339.  
  1340.                         ResetBehaviorSelectionTree(AIOBJRESET_SHUTDOWN);
  1341.  
  1342.                         pAISystem->NotifyTargetDead(this);
  1343.  
  1344.                         m_bCheckedBody = false;
  1345.                         m_bEnabled = false;
  1346.                         pAISystem->NotifyEnableState(this, m_bEnabled);
  1347.  
  1348.                         pAISystem->RemoveFromGroup(GetGroupId(), this);
  1349.  
  1350.                         pAISystem->ReleaseFormationPoint(this);
  1351.                         CancelRequestedPath(false);
  1352.                         ReleaseFormation();
  1353.  
  1354.                         ResetCurrentPipe(true);
  1355.                         m_State.ClearSignals();
  1356.  
  1357.                         ResetAlertness();
  1358.  
  1359.                         const EntityId killerID = pEvent->targetId;
  1360.                         pAISystem->OnAgentDeath(GetEntityID(), killerID);
  1361.  
  1362.                         if (GetProxy())
  1363.                                 GetProxy()->Reset(AIOBJRESET_SHUTDOWN);
  1364.  
  1365.                         SetObservable(false);
  1366.                         SetObserver(false);
  1367.                 }
  1368.                 break;
  1369.         case AIEVENT_FORCEDNAVIGATION:
  1370.                 m_vForcedNavigation = pEvent->vForcedNavigation;
  1371.                 break;
  1372.         case AIEVENT_ADJUSTPATH:
  1373.                 m_adjustpath = pEvent->nType;
  1374.                 break;
  1375.         default:
  1376.                 // triggering non-existing event - script error?
  1377.                 // no error - various e AIEVENT_PLAYER_STUNT_ go here - processed in AIPlayer
  1378.                 //AIAssert(0);
  1379.                 break;
  1380.         }
  1381.  
  1382.         // Activate tree if enabled state is changing
  1383.         if (bWasEnabled != m_bEnabled)
  1384.         {
  1385.                 // remove from alertness counters
  1386.                 ResetAlertness();
  1387.         }
  1388. }
  1389.  
  1390. //===================================================================
  1391. // HandleVisualStimulus
  1392. //===================================================================
  1393. void CPuppet::HandleVisualStimulus(SAIEVENT* pAIEvent)
  1394. {
  1395.         FUNCTION_PROFILER(gEnv->pSystem, PROFILE_AI);
  1396.  
  1397.         const float fGlobalVisualPerceptionScale = gEnv->pAISystem->GetGlobalVisualScale(this);
  1398.         const float fVisualPerceptionScale = m_Parameters.m_PerceptionParams.perceptionScale.visual * fGlobalVisualPerceptionScale;
  1399.         if (gAIEnv.CVars.IgnoreVisualStimulus != 0 || m_Parameters.m_bAiIgnoreFgNode || fVisualPerceptionScale <= 0.0f)
  1400.                 return;
  1401.  
  1402.         if (gAIEnv.pTargetTrackManager->IsEnabled())
  1403.         {
  1404.                 // Check if in range (using perception scale)
  1405.                 if (eFOV_Outside != IsPointInFOV(pAIEvent->vPosition, fVisualPerceptionScale))
  1406.                 {
  1407.                         gAIEnv.pTargetTrackManager->HandleStimulusFromAIEvent(GetAIObjectID(), pAIEvent, TargetTrackHelpers::eEST_Visual);
  1408.                 }
  1409.         }
  1410.         else if (m_pPerceptionHandler)
  1411.                 m_pPerceptionHandler->HandleVisualStimulus(pAIEvent);
  1412. }
  1413.  
  1414. //===================================================================
  1415. // GetPersonalInterestManager
  1416. //===================================================================
  1417. CPersonalInterestManager* CPuppet::GetPersonalInterestManager()
  1418. {
  1419.         return CCentralInterestManager::GetInstance()->FindPIM(GetEntity());
  1420. }
  1421.  
  1422. //===================================================================
  1423. // UpdateLookTarget
  1424. //===================================================================
  1425. void CPuppet::UpdateLookTarget(CAIObject* pTarget)
  1426. {
  1427.         CCCPOINT(CPuppet_UpdateLookTarget);
  1428.         FUNCTION_PROFILER(gEnv->pSystem, PROFILE_AI);
  1429.  
  1430. #ifdef AI_STRIP_OUT_LEGACY_LOOK_TARGET_CODE
  1431.  
  1432.         // Essence of this code: look towards the first non-zero look target
  1433.  
  1434.         Vec3 positionToLookAt(ZERO);
  1435.  
  1436.         LookTargets::iterator it = m_lookTargets.begin();
  1437.  
  1438.         while (it != m_lookTargets.end())
  1439.         {
  1440.                 LookTargetPtr lookTarget = it->lock();
  1441.  
  1442.                 if (lookTarget)
  1443.                 {
  1444.                         if (lookTarget->IsZero())
  1445.                         {
  1446.                                 ++it;
  1447.                                 continue;
  1448.                         }
  1449.                         else
  1450.                         {
  1451.                                 positionToLookAt = *lookTarget;
  1452.                                 break;
  1453.                         }
  1454.                 }
  1455.                 else
  1456.                 {
  1457.                         it = m_lookTargets.erase(it);
  1458.                 }
  1459.         }
  1460.  
  1461.         m_State.vLookTargetPos = positionToLookAt;
  1462.         m_State.vShootTargetPos = positionToLookAt;
  1463.  
  1464.         return;
  1465.  
  1466. #else
  1467.  
  1468.         if (pTarget == NULL)
  1469.         {
  1470.                 CPersonalInterestManager* pPIM = GetPersonalInterestManager();
  1471.                 if (pPIM && pPIM->IsInterested())
  1472.                 {
  1473.                         CWeakRef<CAIObject> refInterest = pPIM->GetInterestDummyPoint();
  1474.                         CAIObject* pInterest = refInterest.GetAIObject();
  1475.                         if (pInterest)
  1476.                         {
  1477.                                 ELookStyle eStyle = pPIM->GetLookingStyle();
  1478.                                 if (eStyle == LOOKSTYLE_HARD || eStyle == LOOKSTYLE_SOFT)
  1479.                                 {
  1480.                                         SetAllowedStrafeDistances(999999.0f, 999999.0f, true);
  1481.                                 }
  1482.                                 SetLookStyle(eStyle);
  1483.                                 pTarget = pInterest;
  1484.                         }
  1485.                 }
  1486.         }
  1487.  
  1488.         // Don't look at targets that aren't at least interesting
  1489.         if (pTarget && m_refAttentionTarget.GetAIObject() == pTarget && GetAttentionTargetThreat() <= AITHREAT_SUSPECT)
  1490.                 pTarget = NULL;
  1491.  
  1492.         // Update look direction and strafing
  1493.         bool lookAtTarget = false;
  1494.         // If not moving allow to look at target.
  1495.         if (m_State.fDesiredSpeed < 0.01f || m_Path.Empty())
  1496.                 lookAtTarget = true;
  1497.  
  1498.         // Check if strafing should be allowed.
  1499.         UpdateStrafing();
  1500.         if (m_State.allowStrafing)
  1501.         {
  1502.                 lookAtTarget = true;
  1503.         }
  1504.         if (m_bLooseAttention)
  1505.         {
  1506.                 CAIObject* pLooseAttentionTarget = m_refLooseAttentionTarget.GetAIObject();
  1507.                 if (pLooseAttentionTarget)
  1508.                         pTarget = pLooseAttentionTarget;
  1509.         }
  1510.         if (m_refFireTarget.IsValid() && m_fireMode != FIREMODE_OFF)
  1511.                 pTarget = GetFireTargetObject();
  1512.  
  1513.         Vec3 lookTarget(ZERO);
  1514.  
  1515.         if (m_fireMode == FIREMODE_MELEE || m_fireMode == FIREMODE_MELEE_FORCED)
  1516.         {
  1517.                 if (pTarget)
  1518.                 {
  1519.                         lookTarget = pTarget->GetPos();
  1520.                         lookTarget.z = GetPos().z;
  1521.                         lookAtTarget = true;
  1522.                 }
  1523.         }
  1524.  
  1525.         bool use3DNav = IsUsing3DNavigation();
  1526.         bool isMoving = m_State.fDesiredSpeed > 0.0f && m_State.curActorTargetPhase == eATP_None && !m_State.vMoveDir.IsZero();
  1527.  
  1528.         float distToTarget = FLT_MAX;
  1529.         if (pTarget)
  1530.         {
  1531.                 Vec3 dirToTarget = pTarget->GetPos() - GetPos();
  1532.                 distToTarget = dirToTarget.GetLength();
  1533.                 if (distToTarget > 0.0001f)
  1534.                         dirToTarget /= distToTarget;
  1535.  
  1536.                 // Allow to look at the target when it is almost at the movement direction or very close.
  1537.                 if (isMoving)
  1538.                 {
  1539.                         Vec3 move(m_State.vMoveDir);
  1540.                         if (!use3DNav)
  1541.                                 move.z = 0.0f;
  1542.                         move.NormalizeSafe(Vec3Constants<float>::fVec3_Zero);
  1543.                         if (distToTarget < 2.5f || move.Dot(dirToTarget) > cosf(DEG2RAD(60)))
  1544.                                 lookAtTarget = true;
  1545.                 }
  1546.         }
  1547.  
  1548.         if (lookAtTarget && pTarget)
  1549.         {
  1550.                 Vec3 vTargetPos = pTarget->GetPos();
  1551.  
  1552.                 const float maxDeviation = distToTarget * sinf(DEG2RAD(15));
  1553.  
  1554.                 if (distToTarget > GetParameters().m_fPassRadius)
  1555.                 {
  1556.                         lookTarget = vTargetPos;
  1557.                         Limit(lookTarget.z, GetPos().z - maxDeviation, GetPos().z + maxDeviation);
  1558.                 }
  1559.  
  1560.                 // Clamp the lookat height when the target is close.
  1561.                 int TargetType = pTarget->GetType();
  1562.                 if (distToTarget < 1.0f ||
  1563.                     (TargetType == AIOBJECT_DUMMY || TargetType == AIOBJECT_HIDEPOINT || TargetType == AIOBJECT_WAYPOINT ||
  1564.                      TargetType > AIOBJECT_PLAYER) && distToTarget < 5.0f) // anchors & dummy objects
  1565.                 {
  1566.                         if (!use3DNav)
  1567.                         {
  1568.                                 lookTarget = vTargetPos;
  1569.                                 Limit(lookTarget.z, GetPos().z - maxDeviation, GetPos().z + maxDeviation);
  1570.                         }
  1571.                 }
  1572.         }
  1573.         else if (isMoving && (gAIEnv.configuration.eCompatibilityMode != ECCM_CRYSIS2))
  1574.         {
  1575.                 // Check if strafing should be allowed.
  1576.  
  1577.                 // Look forward or to the movement direction
  1578.                 Vec3 lookAheadPoint;
  1579.                 float lookAheadDist = 2.5f;
  1580.  
  1581.                 if (m_pPathFollower)
  1582.                 {
  1583.                         float junk;
  1584.                         lookAheadPoint = m_pPathFollower->GetPathPointAhead(lookAheadDist, junk);
  1585.                 }
  1586.                 else
  1587.                 {
  1588.                         if (!m_Path.GetPosAlongPath(lookAheadPoint, lookAheadDist, !m_movementAbility.b3DMove, true))
  1589.                                 lookAheadPoint = GetPhysicsPos();
  1590.                 }
  1591.  
  1592.                 // Since the path height is not guaranteed to follow terrain, do not even try to look up or down.
  1593.                 lookTarget = lookAheadPoint;
  1594.  
  1595.                 // Make sure the lookahead position is far enough so that the catchup logic in the path following
  1596.                 // together with look-ik does not get flipped.
  1597.                 Vec3 delta = lookTarget - GetPhysicsPos();
  1598.                 delta.z = 0.0f;
  1599.                 float dist = delta.GetLengthSquared();
  1600.                 if (dist < sqr(1.0f))
  1601.                 {
  1602.                         float u = 1.0f - sqrtf(dist);
  1603.                         Vec3 safeDir = GetEntityDir();
  1604.                         safeDir.z = 0;
  1605.                         delta = delta + (safeDir - delta) * u;
  1606.                 }
  1607.                 delta.Normalize();
  1608.  
  1609.                 lookTarget = GetPhysicsPos() + delta * 40.0f;
  1610.                 lookTarget.z = GetPos().z;
  1611.         }
  1612.         else
  1613.         {
  1614.                 // Disable look target.
  1615.                 lookTarget.zero();
  1616.         }
  1617.  
  1618.         if (!m_posLookAtSmartObject.IsZero())
  1619.         {
  1620.                 // The SO lookat should override the lookat target in case not requesting to fire and not using lookat goalop.
  1621.                 if (!m_bLooseAttention && m_fireMode == FIREMODE_OFF)
  1622.                 {
  1623.                         lookTarget = m_posLookAtSmartObject;
  1624.                 }
  1625.         }
  1626.  
  1627.         if (!lookTarget.IsZero())
  1628.         {
  1629.                 if (m_allowStrafeLookWhileMoving && m_fireMode != FIREMODE_OFF && GetFireTargetObject())
  1630.                 {
  1631.                         float distSqr = Distance::Point_Point2DSq(GetFireTargetObject()->GetPos(), GetPos());
  1632.                         if (!m_closeRangeStrafing)
  1633.                         {
  1634.                                 // Outside the range
  1635.                                 const float thr = GetParameters().m_PerceptionParams.sightRange * 0.12f;
  1636.                                 if (distSqr < sqr(thr))
  1637.                                         m_closeRangeStrafing = true;
  1638.                         }
  1639.                         if (m_closeRangeStrafing)
  1640.                         {
  1641.                                 // Inside the range
  1642.                                 m_State.allowStrafing = true;
  1643.                                 const float thr = GetParameters().m_PerceptionParams.sightRange * 0.12f + 2.0f;
  1644.                                 if (distSqr > sqr(thr))
  1645.                                         m_closeRangeStrafing = false;
  1646.                         }
  1647.                 }
  1648.  
  1649.                 float distSqr = Distance::Point_Point2DSq(lookTarget, GetPos());
  1650.                 if (distSqr < sqr(2.0f))
  1651.                 {
  1652.                         Vec3 dirToLookTarget = lookTarget - GetPos();
  1653.                         dirToLookTarget.GetNormalizedSafe(GetEntityDir());
  1654.                         Vec3 fakePos = GetPos() + dirToLookTarget * 2.0f;
  1655.                         //Disable setting a look target if you're virtually on top of the point
  1656.                         if (distSqr < sqr(0.12f))
  1657.                         {
  1658.                                 lookTarget.zero();
  1659.                         }
  1660.                         else if (distSqr < sqr(0.7f))
  1661.                         {
  1662.                                 lookTarget = fakePos;
  1663.                         }
  1664.                         else
  1665.                         {
  1666.                                 float speed = m_State.vMoveDir.GetLength();
  1667.                                 speed = clamp_tpl(speed, 0.0f, 10.f);
  1668.                                 float d = sqrtf(distSqr);
  1669.                                 float u = 1.0f - (d - 0.7f) / (2.0f - 0.7f);
  1670.                                 lookTarget += speed / 10 * u * (fakePos - lookTarget);
  1671.                         }
  1672.                 }
  1673.         }
  1674.  
  1675.         // for the invehicle gunners
  1676.         if (GetProxy())
  1677.         {
  1678.                 const SAIBodyInfo& bodyInfo = GetBodyInfo();
  1679.  
  1680.                 if (IEntity* pLinkedVehicleEntity = bodyInfo.GetLinkedVehicleEntity())
  1681.                 {
  1682.                         if (GetProxy()->GetActorIsFallen())
  1683.                         {
  1684.                                 lookTarget.zero();
  1685.                         }
  1686.                         else
  1687.                         {
  1688.                                 CAIObject* pUnit = (CAIObject*)pLinkedVehicleEntity->GetAI();
  1689.                                 if (pUnit)
  1690.                                 {
  1691.                                         if (pUnit->CastToCAIVehicle())
  1692.                                         {
  1693.                                                 lookTarget.zero();
  1694.                                                 CAIObject* pLooseAttentionTarget = m_refLooseAttentionTarget.GetAIObject();
  1695.                                                 if (m_bLooseAttention && pLooseAttentionTarget)
  1696.                                                         pTarget = pLooseAttentionTarget;
  1697.                                                 if (pTarget)
  1698.                                                 {
  1699.                                                         lookTarget = pTarget->GetPos();
  1700.                                                         m_State.allowStrafing = false;
  1701.                                                 }
  1702.                                         }
  1703.                                 }
  1704.                         }
  1705.                 }
  1706.         }
  1707.  
  1708.         if (GetSubType() != STP_HELICRYSIS2)
  1709.         {
  1710.                 float lookTurnSpeed = GetAlertness() > 0 ? m_Parameters.m_lookCombatTurnSpeed : m_Parameters.m_lookIdleTurnSpeed;
  1711.                 //If entity is not moving, then do not use look target interpolation, smoothing will come from turn animations.
  1712.                 if (lookTurnSpeed <= 0.0f || !isMoving)
  1713.                         m_State.vLookTargetPos = lookTarget;
  1714.                 else
  1715.                         m_State.vLookTargetPos = InterpolateLookOrAimTargetPos(m_State.vLookTargetPos, lookTarget, lookTurnSpeed);
  1716.         }
  1717.  
  1718. #endif
  1719.  
  1720. }
  1721.  
  1722. //===================================================================
  1723. // InterpolateLookOrAimTargetPos
  1724. //===================================================================
  1725. Vec3 CPuppet::InterpolateLookOrAimTargetPos(const Vec3& current, const Vec3& target, float maxRatePerSec)
  1726. {
  1727.         if ((!target.IsZero()) && !target.IsEquivalent(m_vLastPosition))
  1728.         {
  1729.                 // Interpolate.
  1730.                 Vec3 curDir;
  1731.                 if (current.IsZero())
  1732.                 {
  1733.                         curDir = GetEntityDir(); // GetViewDir();
  1734.                 }
  1735.                 else
  1736.                 {
  1737.                         curDir = current - GetPos();
  1738.                         curDir.Normalize();
  1739.                 }
  1740.  
  1741.                 Vec3 reqDir = target - m_vLastPosition;  // GetPos();
  1742.                 float dist = reqDir.NormalizeSafe();
  1743.  
  1744.                 // Slerp
  1745.                 float cosAngle = curDir.Dot(reqDir);
  1746.  
  1747.                 const float eps = 1e-6f;
  1748.                 const float maxRate = maxRatePerSec * GetAISystem()->GetFrameDeltaTime();
  1749.                 const float thr = cosf(maxRate);
  1750.  
  1751.                 if (cosAngle > thr || maxRate < eps || dist < eps)
  1752.                 {
  1753.                         return target;
  1754.                 }
  1755.                 else
  1756.                 {
  1757.                         float angle = acos_tpl(cosAngle);
  1758.  
  1759.                         // Allow higher rate when over 90degrees.
  1760.                         const float piOverFour = gf_PI / 4.0f;
  1761.                         const float rcpPIOverFour = 1.0f / piOverFour;
  1762.                         float scale = 1.0f + clamp_tpl((angle - piOverFour) * rcpPIOverFour, 0.0f, 1.0f) * 2.0f;
  1763.                         if (angle < eps || angle < maxRate * scale)
  1764.                                 return target;
  1765.  
  1766.                         float t = (maxRate * scale) / angle;
  1767.  
  1768.                         Quat curView;
  1769.                         curView.SetRotationVDir(curDir);
  1770.                         Quat reqView;
  1771.                         reqView.SetRotationVDir(reqDir);
  1772.  
  1773.                         Quat view;
  1774.                         view.SetSlerp(curView, reqView, t);
  1775.  
  1776.                         return GetPos() + (view * FORWARD_DIRECTION) * dist;
  1777.                 }
  1778.         }
  1779.  
  1780.         // Clear look target.
  1781.         return target;
  1782. }
  1783.  
  1784. //===================================================================
  1785. // UpdateLookTarget3D
  1786. //===================================================================
  1787. void CPuppet::UpdateLookTarget3D(CAIObject* pTarget)
  1788. {
  1789.         // This is for the scout mainly
  1790.         m_State.vLookTargetPos.zero();
  1791.         m_State.aimTargetIsValid = false;
  1792.  
  1793.         CAIObject* pLooseAttentionTarget = m_refLooseAttentionTarget.GetAIObject();
  1794.         if (m_bLooseAttention && pLooseAttentionTarget)
  1795.         {
  1796.                 pTarget = pLooseAttentionTarget;
  1797.                 m_State.vLookTargetPos = pTarget->GetPos();
  1798.         }
  1799.  
  1800.         m_State.vForcedNavigation = m_vForcedNavigation;
  1801. }
  1802.  
  1803. //===================================================================
  1804. // AdjustMovementUrgency
  1805. //===================================================================
  1806. void CPuppet::AdjustMovementUrgency(float& urgency, float pathLength, float* maxPathLen)
  1807. {
  1808.         if (!maxPathLen)
  1809.                 maxPathLen = &m_adaptiveUrgencyMaxPathLen;
  1810.  
  1811.         if (m_adaptiveUrgencyScaleDownPathLen > 0.0001f)
  1812.         {
  1813.                 if (pathLength > *maxPathLen)
  1814.                 {
  1815.                         *maxPathLen = pathLength;
  1816.  
  1817.                         int scaleDown = 0;
  1818.                         float scale = m_adaptiveUrgencyScaleDownPathLen;
  1819.                         while (scale > m_adaptiveUrgencyMaxPathLen && scaleDown < 4)
  1820.                         {
  1821.                                 scale /= 2.0f;
  1822.                                 scaleDown++;
  1823.                         }
  1824.  
  1825.                         int minIdx = MovementUrgencyToIndex(m_adaptiveUrgencyMin);
  1826.                         int maxIdx = MovementUrgencyToIndex(m_adaptiveUrgencyMax);
  1827.                         int idx = maxIdx - scaleDown;
  1828.                         if (idx < minIdx) idx = minIdx;
  1829.  
  1830.                         // Special case for really short paths.
  1831.                         if (*maxPathLen < 1.2f && idx > 2)
  1832.                                 idx = 2; // walk
  1833.  
  1834.                         urgency = IndexToMovementUrgency(idx);
  1835.                 }
  1836.         }
  1837. }
  1838.  
  1839. //===================================================================
  1840. // HandlePathDecision
  1841. //===================================================================
  1842. void CPuppet::HandlePathDecision(MNMPathRequestResult& result)
  1843. {
  1844.         CPipeUser::HandlePathDecision(result);
  1845.  
  1846.         if (result.HasPathBeenFound())
  1847.         {
  1848.                 const bool validPath = !result.pPath->Empty();
  1849.                 if (validPath)
  1850.                 {
  1851.                         // Update adaptive urgency control before the path gets processed further
  1852.                         AdjustMovementUrgency(m_State.fMovementUrgency, m_Path.GetPathLength(!IsUsing3DNavigation()));
  1853.  
  1854.                         AdjustPath();
  1855.                 }
  1856.         }
  1857. }
  1858.  
  1859. //===================================================================
  1860. // Devalue
  1861. //===================================================================
  1862. void CPuppet::Devalue(IAIObject* pObject, bool bDevaluePuppets, float fAmount)
  1863. {
  1864.         DevaluedMap::iterator di;
  1865.  
  1866.         unsigned short type = ((CAIObject*)pObject)->GetType();
  1867.  
  1868.         CAIObject* pAttentionTarget = m_refAttentionTarget.GetAIObject();
  1869.         CWeakRef<CAIObject> refObject = GetWeakRefSafe((CAIObject*)pObject);
  1870.  
  1871.         if (pObject == pAttentionTarget)
  1872.                 SetAttentionTarget(NILREF);
  1873.  
  1874.         if ((type == AIOBJECT_ACTOR) && !bDevaluePuppets)
  1875.                 return;
  1876.  
  1877.         if (type == AIOBJECT_PLAYER)
  1878.                 return;
  1879.  
  1880.         CCCPOINT(CPuppet_Devalue);
  1881.  
  1882.         // remove it from map of pending events, so that it does not get reacquire
  1883.         if (m_pPerceptionHandler)
  1884.                 m_pPerceptionHandler->RemoveEvent(refObject);
  1885.  
  1886.         if ((di = m_mapDevaluedPoints.find(refObject)) == m_mapDevaluedPoints.end())
  1887.                 m_mapDevaluedPoints.insert(DevaluedMap::iterator::value_type(refObject, fAmount));
  1888. }
  1889.  
  1890. //===================================================================
  1891. // IsDevalued
  1892. //===================================================================
  1893. bool CPuppet::IsDevalued(IAIObject* pObject)
  1894. {
  1895.         CWeakRef<CAIObject> refObject = GetWeakRefSafe((CAIObject*)pObject);
  1896.         return m_mapDevaluedPoints.find(refObject) != m_mapDevaluedPoints.end();
  1897. }
  1898.  
  1899. //===================================================================
  1900. // ClearDevalued
  1901. //===================================================================
  1902. void CPuppet::ClearDevalued()
  1903. {
  1904.         m_mapDevaluedPoints.clear();
  1905. }
  1906.  
  1907. //===================================================================
  1908. // OnObjectRemoved
  1909. //===================================================================
  1910. void CPuppet::OnObjectRemoved(CAIObject* pObject)
  1911. {
  1912.         CAIActor::OnObjectRemoved(pObject);
  1913.  
  1914.         if (m_pPerceptionHandler)
  1915.                 m_pPerceptionHandler->RemoveEvent(GetWeakRef(pObject));
  1916.  
  1917.         if (!m_steeringObjects.empty())
  1918.                 m_steeringObjects.erase(std::remove(m_steeringObjects.begin(), m_steeringObjects.end(), pObject), m_steeringObjects.end());
  1919. }
  1920.  
  1921. //===================================================================
  1922. // UpTargetPriority
  1923. //===================================================================
  1924. void CPuppet::UpTargetPriority(const IAIObject* pTarget, float fPriorityIncrement)
  1925. {
  1926.         if (m_pPerceptionHandler)
  1927.                 m_pPerceptionHandler->UpTargetPriority(GetWeakRef((CAIObject*)pTarget), fPriorityIncrement);
  1928. }
  1929.  
  1930. //===================================================================
  1931. // HandleSoundEvent
  1932. //===================================================================
  1933. void CPuppet::HandleSoundEvent(SAIEVENT* pEvent)
  1934. {
  1935.         FUNCTION_PROFILER(gEnv->pSystem, PROFILE_AI);
  1936.  
  1937.         const float fGlobalAudioPerceptionScale = gEnv->pAISystem->GetGlobalAudioScale(this);
  1938.         const float fAudioPerceptionScale = m_Parameters.m_PerceptionParams.perceptionScale.audio * fGlobalAudioPerceptionScale;
  1939.         if (gAIEnv.CVars.IgnoreSoundStimulus != 0 || m_Parameters.m_bAiIgnoreFgNode || fAudioPerceptionScale <= 0.0f)
  1940.                 return;
  1941.  
  1942.         if (gAIEnv.pTargetTrackManager->IsEnabled())
  1943.         {
  1944.                 // Check if in range (using perception scale)
  1945.                 const Vec3& vMyPos = GetPos();
  1946.                 const float fSoundDistance = vMyPos.GetDistance(pEvent->vPosition) * (1.0f / fAudioPerceptionScale);
  1947.                 if (fSoundDistance <= pEvent->fThreat)
  1948.                 {
  1949.                         gAIEnv.pTargetTrackManager->HandleStimulusFromAIEvent(GetAIObjectID(), pEvent, TargetTrackHelpers::eEST_Sound);
  1950.                 }
  1951.         }
  1952.         if (m_pPerceptionHandler)
  1953.                 m_pPerceptionHandler->HandleSoundEvent(pEvent);
  1954. }
  1955.  
  1956. //===================================================================
  1957. // HandleBulletRain
  1958. //===================================================================
  1959. void CPuppet::HandleBulletRain(SAIEVENT* pEvent)
  1960. {
  1961.         FUNCTION_PROFILER(gEnv->pSystem, PROFILE_AI);
  1962.  
  1963.         CPipeUser::HandleBulletRain(pEvent);
  1964.  
  1965.         if (gAIEnv.pTargetTrackManager->IsEnabled())
  1966.                 gAIEnv.pTargetTrackManager->HandleStimulusFromAIEvent(GetAIObjectID(), pEvent, TargetTrackHelpers::eEST_BulletRain);
  1967.         else if (m_pPerceptionHandler)
  1968.                 m_pPerceptionHandler->HandleBulletRain(pEvent);
  1969. }
  1970.  
  1971. //===================================================================
  1972. // SetForcedNavigation
  1973. //===================================================================
  1974. void CPuppet::SetForcedNavigation(const Vec3& vDirection, float fSpeed)
  1975. {
  1976.         m_vForcedNavigation = vDirection;
  1977.         m_fForcedNavigationSpeed = fSpeed;
  1978. }
  1979.  
  1980. //===================================================================
  1981. // ClearForcedNavigation
  1982. //===================================================================
  1983. void CPuppet::ClearForcedNavigation()
  1984. {
  1985.         m_vForcedNavigation.zero();
  1986.         m_fForcedNavigationSpeed = 0.0f;
  1987. }
  1988.  
  1989. CPuppet::ENavInteraction CPuppet::NavigateAroundObjectsBasicCheck(const CAIObject* object) const
  1990. {
  1991.         //These checks have been factored out of the old NavigateAroundObjectsBasicCheck so that they can be used
  1992.         //by the old version as well as the new approach in NavigateAroundObjects
  1993.  
  1994.         ENavInteraction ret = NI_IGNORE;
  1995.  
  1996.         if (object)
  1997.         {
  1998.                 //to make sure we skip disable entities (hidden in the game, etc)
  1999.                 IEntity* pEntity(object->GetEntity());
  2000.                 if (pEntity && pEntity->IsActive())
  2001.                 {
  2002.                         if (AIOBJECT_VEHICLE == object->GetType() || object->IsEnabled()) // vehicles are not enabled when idle, so don't skip them
  2003.                         {
  2004.                                 if (this != object)
  2005.                                 {
  2006.                                         ret = GetNavInteraction(this, object);
  2007.                                 }
  2008.                         }
  2009.                 }
  2010.         }
  2011.  
  2012.         return ret;
  2013. }
  2014.  
  2015. //===================================================================
  2016. // NavigateAroundObjectsBasicCheck
  2017. //===================================================================
  2018. bool CPuppet::NavigateAroundObjectsBasicCheck(const Vec3& targetPos, const Vec3& myPos, bool in3D, const CAIObject* object, float extraDist)
  2019. {
  2020.         bool ret = false;
  2021.  
  2022.         //now calling the factored out function
  2023.         ENavInteraction navInteraction = NavigateAroundObjectsBasicCheck(object);
  2024.         if (navInteraction != NI_IGNORE)
  2025.         {
  2026.                 Vec3 objectPos = object->GetPos();
  2027.                 Vec3 delta = objectPos - myPos;
  2028.                 const CAIActor* pActor = object->CastToCAIActor();
  2029.                 float avoidanceR = m_movementAbility.avoidanceRadius;
  2030.                 avoidanceR += pActor->m_movementAbility.avoidanceRadius;
  2031.                 avoidanceR += extraDist;
  2032.                 float avoidanceRSq = square(avoidanceR);
  2033.  
  2034.                 // skip if we're not close
  2035.                 float distSq = delta.GetLengthSquared();
  2036.                 if (!(distSq > avoidanceRSq))
  2037.                 {
  2038.                         ret = true;
  2039.                 }
  2040.         }
  2041.  
  2042.         return ret;
  2043. }
  2044.  
  2045. //===================================================================
  2046. // NavigateAroundObjectsInternal
  2047. //===================================================================
  2048. bool CPuppet::NavigateAroundObjectsInternal(const Vec3& targetPos, const Vec3& myPos, bool in3D, const CAIObject* object)
  2049. {
  2050.         // skip if we're not trying to move towards
  2051.         Vec3 objectPos = object->GetPos();
  2052.         Vec3 delta = objectPos - myPos;
  2053.         float dot = m_State.vMoveDir.Dot(delta);
  2054.         if (dot < 0.001f)
  2055.                 return false;
  2056.         const CAIActor* pActor = object->CastToCAIActor();
  2057.         float avoidanceR = m_movementAbility.avoidanceRadius;
  2058.         avoidanceR += pActor->m_movementAbility.avoidanceRadius;
  2059.         float avoidanceRSq = square(avoidanceR);
  2060.  
  2061.         // skip if we're not close
  2062.         float distSq = delta.GetLengthSquared();
  2063.         if (distSq > avoidanceRSq)
  2064.                 return false;
  2065.  
  2066.         return NavigateAroundAIObject(targetPos, object, myPos, objectPos, true, in3D);
  2067. }
  2068.  
  2069. //===================================================================
  2070. // NavigateAroundObjects
  2071. //===================================================================
  2072. bool CPuppet::NavigateAroundObjects(const Vec3& targetPos, bool fullUpdate)
  2073. {
  2074.         FUNCTION_PROFILER(GetISystem(), PROFILE_AI);
  2075.         bool in3D = IsUsing3DNavigation();
  2076.         const Vec3 myPos = GetPhysicsPos();
  2077.  
  2078.         bool steering = false;
  2079.         bool lastSteeringEnabled = m_steeringEnabled;
  2080.         bool steeringEnabled = m_State.vMoveDir.GetLength() > 0.01f && m_State.fDesiredSpeed > 0.01f;
  2081.  
  2082.         CTimeValue curTime = GetAISystem()->GetFrameStartTime();
  2083.  
  2084.         int64 deltaTime = (curTime - m_lastSteerTime).GetMilliSecondsAsInt64();
  2085.         const int64 timeForUpdate = 500;
  2086.  
  2087.         if (steeringEnabled && (deltaTime > timeForUpdate || !lastSteeringEnabled))
  2088.         {
  2089.                 FRAME_PROFILER("NavigateAroundObjects Gather Objects", gEnv->pSystem, PROFILE_AI)
  2090.  
  2091.                 m_lastSteerTime = curTime;
  2092.                 m_steeringObjects.clear();
  2093.  
  2094.                 //This approach now uses a cylinder overlap to collect the entities surrounding
  2095.                 //this puppet. The cylinder has a height of 2.5m, the center of its bottom is
  2096.                 //at this puppets position. The radius used for the cylinder is the minimum
  2097.                 //of 2.5m (should probably be made configurable) and the distance to my final
  2098.                 //goal. That way, when approaching the destpos we don't check any further.
  2099.                 float radius = min(2.5f, Distance::Point_Point(myPos, m_Path.GetLastPathPos()));
  2100.                 Lineseg lseg(myPos, myPos + Vec3(0.0f, 0.0f, 2.5f));
  2101.  
  2102.                 //We are interested in living and dynamic entities
  2103.                 static EAICollisionEntities colfilter = static_cast<EAICollisionEntities>(ent_living | AICE_DYNAMIC);
  2104.  
  2105.                 int32 ent[11] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
  2106.                 //Gather up to 10 entities surrounding this puppet
  2107.                 if (OverlapCylinder(lseg, radius, colfilter, GetPhysics(), 0, ent, 10))
  2108.                 {
  2109.  
  2110.                         //loop over the id-array until we find an id of 0
  2111.                         for (int32* entityid = ent; *entityid; ++entityid)
  2112.                         {
  2113.                                 IEntity* entity = gEnv->pSystem->GetIEntitySystem()->GetEntity(*entityid);
  2114.                                 if (entity)
  2115.                                 {
  2116.                                         CAIObject* aiob = static_cast<CAIObject*>(entity->GetAI());
  2117.  
  2118.                                         //If this AIObject passes the test, push it back onto the vector
  2119.                                         if (NI_IGNORE != NavigateAroundObjectsBasicCheck(aiob))
  2120.                                         {
  2121.                                                 m_steeringObjects.push_back(aiob);
  2122.                                         }
  2123.                                 }
  2124.                         }
  2125.                 }
  2126.         }
  2127.  
  2128.         if (steeringEnabled)
  2129.         {
  2130.                 if ((GetType() == AIOBJECT_ACTOR) && !in3D)
  2131.                 {
  2132.                         FRAME_PROFILER("NavigateAroundObjects Update Steering", gEnv->pSystem, PROFILE_AI)
  2133.  
  2134.                         bool check = fullUpdate;
  2135.                         if (m_updatePriority == AIPUP_VERY_HIGH || m_updatePriority == AIPUP_HIGH)
  2136.                                 check = true;
  2137.  
  2138.                         if (check || !lastSteeringEnabled)
  2139.                         {
  2140.                                 AABB selfBounds;
  2141.                                 GetEntity()->GetWorldBounds(selfBounds);
  2142.                                 selfBounds.min.z -= 0.25f;
  2143.                                 selfBounds.max.z += 0.25f;
  2144.  
  2145.                                 // Build occupancy map
  2146.                                 const float radScale = 1.0f - clamp_tpl(m_steeringAdjustTime - 1.0f, 0.0f, 1.0f);
  2147.                                 const float selfRad = m_movementAbility.pathRadius * radScale;
  2148.                                 m_steeringOccupancy.Reset(GetPhysicsPos(), GetEntityDir(), m_movementAbility.avoidanceRadius * 2.0f);
  2149.  
  2150.                                 for (unsigned i = 0, ni = m_steeringObjects.size(); i < ni; ++i)
  2151.                                 {
  2152.                                         const CAIActor* pActor = m_steeringObjects[i]->CastToCAIActor();
  2153.                                         if (!pActor) // || !pActor->IsActive())
  2154.                                                 continue;
  2155.  
  2156.                                         // Check that the height overlaps.
  2157.                                         IEntity* pActorEnt = pActor->GetEntity();
  2158.                                         AABB bounds;
  2159.                                         pActorEnt->GetWorldBounds(bounds);
  2160.                                         if (selfBounds.min.z >= bounds.max.z || selfBounds.max.z <= bounds.min.z)
  2161.                                                 continue;
  2162.  
  2163.                                         if (pActor->GetType() == AIOBJECT_VEHICLE)
  2164.                                         {
  2165.                                                 AABB localBounds;
  2166.                                                 pActor->GetLocalBounds(localBounds);
  2167.                                                 const Matrix34& tm = pActorEnt->GetWorldTM();
  2168.  
  2169.                                                 SAIRect3 r;
  2170.                                                 GetFloorRectangleFromOrientedBox(tm, localBounds, r);
  2171.                                                 // Extend the box based on velocity.
  2172.                                                 Vec3 vel = pActor->GetVelocity();
  2173.                                                 float speedu = r.axisu.Dot(vel) * 0.25f;
  2174.                                                 float speedv = r.axisv.Dot(vel) * 0.25f;
  2175.                                                 if (speedu > 0)
  2176.                                                         r.max.x += speedu;
  2177.                                                 else
  2178.                                                         r.min.x += speedu;
  2179.                                                 if (speedv > 0)
  2180.                                                         r.max.y += speedv;
  2181.                                                 else
  2182.                                                         r.min.y += speedv;
  2183.  
  2184.                                                 // Extend the box based on the
  2185.                                                 r.min.x -= selfRad;
  2186.                                                 r.min.y -= selfRad;
  2187.                                                 r.max.x += selfRad;
  2188.                                                 r.max.y += selfRad;
  2189.  
  2190.                                                 const unsigned maxpts = 4;
  2191.                                                 Vec3 rect[maxpts];
  2192.                                                 rect[0] = r.center + r.axisu * r.min.x + r.axisv * r.min.y;
  2193.                                                 rect[1] = r.center + r.axisu * r.max.x + r.axisv * r.min.y;
  2194.                                                 rect[2] = r.center + r.axisu * r.max.x + r.axisv * r.max.y;
  2195.                                                 rect[3] = r.center + r.axisu * r.min.x + r.axisv * r.max.y;
  2196.  
  2197.                                                 /*                                              unsigned last = maxpts-1;
  2198.                                                             for (unsigned i = 0; i < maxpts; ++i)
  2199.                                                             {
  2200.                                                               GetAISystem()->AddDebugLine(rect[last], rect[i], 255,0,0, 0);
  2201.                                                               last = i;
  2202.                                                             }*/
  2203.  
  2204.                                                 float x = r.axisu.Dot(m_steeringOccupancy.GetCenter() - r.center);
  2205.                                                 float y = r.axisv.Dot(m_steeringOccupancy.GetCenter() - r.center);
  2206.  
  2207.                                                 const float eps = 0.1f;
  2208.                                                 if (x >= r.min.x - eps && x <= r.max.x + eps && y >= r.min.y - eps && y <= r.max.y + eps)
  2209.                                                 {
  2210.                                                         //                                                      GetAISystem()->AddDebugLine(m_steeringOccupancy.GetCenter()+Vec3(0,0,-10), m_steeringOccupancy.GetCenter()+Vec3(0,0,10), 0,0,0, 0);
  2211.                                                         m_steeringOccupancy.AddObstructionDirection(r.center - m_steeringOccupancy.GetCenter());
  2212.                                                 }
  2213.                                                 else
  2214.                                                 {
  2215.                                                         unsigned last = maxpts - 1;
  2216.                                                         for (unsigned j = 0; j < maxpts; ++j)
  2217.                                                         {
  2218.                                                                 m_steeringOccupancy.AddObstructionLine(rect[last], rect[j]);
  2219.                                                                 last = j;
  2220.                                                         }
  2221.                                                 }
  2222.                                         }
  2223.                                         else
  2224.                                         {
  2225.                                                 const Vec3& pos = pActor->GetPhysicsPos();
  2226.                                                 const float rad = pActor->GetMovementAbility().pathRadius;
  2227.  
  2228.                                                 const Vec3& bodyDir = pActor->GetEntityDir();
  2229.                                                 Vec3 right(bodyDir.y, -bodyDir.x, 0);
  2230.                                                 right.Normalize();
  2231.  
  2232.                                                 m_steeringOccupancy.AddObstructionCircle(pos, selfRad + rad);
  2233.                                                 Vec3 vel = pActor->GetVelocity();
  2234.                                                 if (vel.GetLengthSquared() > sqr(0.1f))
  2235.                                                         m_steeringOccupancy.AddObstructionCircle(pos + vel * 0.25f + right * rad * 0.3f, selfRad + rad);
  2236.                                         }
  2237.                                 }
  2238.                         }
  2239.  
  2240.                         // Steer around
  2241.                         Vec3 oldMoveDir = m_State.vMoveDir;
  2242.                         m_State.vMoveDir = m_steeringOccupancy.GetNearestUnoccupiedDirection(m_State.vMoveDir, m_steeringOccupancyBias);
  2243.  
  2244.                         if (gAIEnv.CVars.DebugDrawCrowdControl > 0)
  2245.                         {
  2246.                                 Vec3 pos = GetPhysicsPos() + Vec3(0, 0, 0.75f);
  2247.                                 GetAISystem()->AddDebugLine(pos, pos + oldMoveDir * 2.0f, 196, 0, 0, 0);
  2248.                                 GetAISystem()->AddDebugLine(pos, pos + m_State.vMoveDir * 2.0f, 255, 196, 0, 0);
  2249.                         }
  2250.  
  2251.                         if (fabsf(m_steeringOccupancyBias) > 0.1f)
  2252.                         {
  2253.                                 steering = true;
  2254.  
  2255.                                 Vec3 aheadPos;
  2256.                                 if (m_pPathFollower)
  2257.                                 {
  2258.                                         float junk;
  2259.                                         aheadPos = m_pPathFollower->GetPathPointAhead(m_movementAbility.pathRadius, junk);
  2260.                                         if (Distance::Point_Point2DSq(aheadPos, GetPhysicsPos()) < square(m_movementAbility.avoidanceRadius))
  2261.                                         {
  2262.                                                 m_pPathFollower->Advance(m_movementAbility.pathRadius * 0.3f);
  2263.                                         }
  2264.                                 }
  2265.                                 else
  2266.                                 {
  2267.                                         aheadPos = m_Path.CalculateTargetPos(myPos, 0.f, 0.f, m_movementAbility.pathRadius, true);
  2268.                                         if (!m_Path.Empty() && Distance::Point_Point2DSq(aheadPos, GetPhysicsPos()) < square(m_movementAbility.avoidanceRadius))
  2269.                                         {
  2270.                                                 Vec3 pathNextPoint;
  2271.                                                 if (m_Path.GetPosAlongPath(pathNextPoint, m_movementAbility.pathRadius * 0.3f, true, false))
  2272.                                                         m_Path.UpdatePathPosition(pathNextPoint, 100.0f, true, false);
  2273.                                         }
  2274.                                 }
  2275.  
  2276.                                 float slowdown = 1.0f - (oldMoveDir.Dot(m_State.vMoveDir) + 1.0f) * 0.5f;
  2277.  
  2278.                                 float normalSpeed, minSpeed, maxSpeed;
  2279.                                 GetMovementSpeedRange(m_State.fMovementUrgency, m_State.allowStrafing, normalSpeed, minSpeed, maxSpeed);
  2280.  
  2281.                                 m_State.fDesiredSpeed += (minSpeed - m_State.fDesiredSpeed) * slowdown;
  2282.  
  2283.                                 if (slowdown > 0.1f)
  2284.                                         m_steeringAdjustTime += m_fTimePassed;
  2285.                         }
  2286.                         else
  2287.                         {
  2288.                                 m_steeringAdjustTime -= m_fTimePassed;
  2289.                         }
  2290.  
  2291.                         Limit(m_steeringAdjustTime, 0.0f, 3.0f);
  2292.                 }
  2293.                 else
  2294.                 {
  2295.                         FRAME_PROFILER("NavigateAroundObjects Update Steering Old", gEnv->pSystem, PROFILE_AI)
  2296.                         // Old type steering for the rest of the objects.
  2297.                         unsigned nObj = m_steeringObjects.size();
  2298.                         for (unsigned i = 0; i < nObj; ++i)
  2299.                         {
  2300.                                 const CAIObject* object = m_steeringObjects[i];
  2301.                                 if (NavigateAroundObjectsInternal(targetPos, myPos, in3D, object))
  2302.                                         steering = true;
  2303.                         }
  2304.                 }
  2305.         }
  2306.  
  2307.         m_steeringEnabled = steeringEnabled;
  2308.  
  2309.         return steering;
  2310. }
  2311.  
  2312. //===================================================================
  2313. // NavigateAroundAIObject
  2314. //===================================================================
  2315. bool CPuppet::NavigateAroundAIObject(const Vec3& targetPos, const CAIObject* obstacle, const Vec3& myPos,
  2316.                                      const Vec3& objectPos, bool steer, bool in3D)
  2317. {
  2318.         FUNCTION_PROFILER(GetISystem(), PROFILE_AI);
  2319.         if (steer)
  2320.         {
  2321.                 if (in3D)
  2322.                         return SteerAround3D(targetPos, obstacle, myPos, objectPos);
  2323.                 else if (obstacle->GetType() == AIOBJECT_VEHICLE)
  2324.                         return SteerAroundVehicle(targetPos, obstacle, myPos, objectPos);
  2325.                 else
  2326.                         return SteerAroundPuppet(targetPos, obstacle, myPos, objectPos);
  2327.         }
  2328.         else
  2329.         {
  2330.                 AIError("NavigateAroundAIObject - only handles steering so far");
  2331.                 return false;
  2332.         }
  2333. }
  2334.  
  2335. //===================================================================
  2336. // SteerAroundPuppet
  2337. //===================================================================
  2338. bool CPuppet::SteerAroundPuppet(const Vec3& targetPos, const CAIObject* object, const Vec3& myPos, const Vec3& objectPos)
  2339. {
  2340.         const CPuppet* pPuppet = object->CastToCPuppet();
  2341.         if (!pPuppet)
  2342.                 return false;
  2343.  
  2344.         float avoidanceR = m_movementAbility.avoidanceRadius;
  2345.         avoidanceR += pPuppet->m_movementAbility.avoidanceRadius;
  2346.         float avoidanceRSq = square(avoidanceR);
  2347.  
  2348.         float maxAllowedSpeedMod = 10.0f;
  2349.         Vec3 steerOffset(ZERO);
  2350.  
  2351.         bool outside = true;
  2352.         if (m_lastNavNodeIndex && (gAIEnv.pGraph->GetNodeManager().GetNode(m_lastNavNodeIndex)->navType & (IAISystem::NAV_TRIANGULAR | IAISystem::NAV_ROAD)) == 0)
  2353.                 outside = false;
  2354.  
  2355.         Vec3 delta = objectPos - myPos;
  2356.         // skip if we're not close
  2357.         float distSq = delta.GetLengthSquared();
  2358.         if (distSq > avoidanceRSq)
  2359.                 return false;
  2360.  
  2361.         // don't overtake unless we're in more of a hurry
  2362.         static float overtakeScale = 2.0f;
  2363.         static float overtakeOffset = 0.1f;
  2364.         static float criticalOvertakeMoveDot = 0.4f;
  2365.  
  2366.         float holdbackDist = 0.6f;
  2367.         if (object->GetType() == AIOBJECT_VEHICLE)
  2368.                 holdbackDist = 15.0f;
  2369.  
  2370.         if (m_State.vMoveDir.Dot(pPuppet->GetState().vMoveDir) > criticalOvertakeMoveDot)
  2371.         {
  2372.                 float myNormalSpeed, myMinSpeed, myMaxSpeed;
  2373.                 GetMovementSpeedRange(m_State.fMovementUrgency, m_State.allowStrafing, myNormalSpeed, myMinSpeed, myMaxSpeed);
  2374.                 //    float myNormalSpeed = GetNormalMovementSpeed(m_State.fMovementUrgency, true);
  2375.                 //    float otherNormalSpeed = pPuppet->GetNormalMovementSpeed(pPuppet->m_State.fMovementUrgency, true);
  2376.                 float otherNormalSpeed, otherMinSpeed, otherMaxSpeed;
  2377.                 pPuppet->GetMovementSpeedRange(pPuppet->m_State.fMovementUrgency, pPuppet->m_State.allowStrafing, otherNormalSpeed, otherMinSpeed, otherMaxSpeed);
  2378.  
  2379.                 if (!outside || myNormalSpeed < overtakeScale * otherNormalSpeed + overtakeOffset)
  2380.                 {
  2381.                         float maxDesiredSpeed = max(myMinSpeed, object->GetVelocity().Dot(m_State.vMoveDir));
  2382.  
  2383.                         float dist = sqrtf(distSq);
  2384.                         dist -= holdbackDist;
  2385.  
  2386.                         float extraFrac = dist / holdbackDist;
  2387.                         Limit(extraFrac, -0.1f, 0.1f);
  2388.                         maxDesiredSpeed *= 1.0f + extraFrac;
  2389.  
  2390.                         if (m_State.fDesiredSpeed > maxDesiredSpeed)
  2391.                                 m_State.fDesiredSpeed = maxDesiredSpeed;
  2392.  
  2393.                         return true;
  2394.                 }
  2395.                 avoidanceR *= 0.75f;
  2396.                 avoidanceRSq = square(avoidanceR);
  2397.         }
  2398.  
  2399.         // steer around
  2400.         Vec3 aheadPos;
  2401.         if (m_pPathFollower)
  2402.         {
  2403.                 float junk;
  2404.                 aheadPos = m_pPathFollower->GetPathPointAhead(m_movementAbility.pathRadius, junk);
  2405.                 if (outside && Distance::Point_Point2DSq(aheadPos, objectPos) < square(avoidanceR))
  2406.                 {
  2407.                         static float advanceFrac = 0.2f;
  2408.                         m_pPathFollower->Advance(advanceFrac * avoidanceR);
  2409.                 }
  2410.         }
  2411.         else
  2412.         {
  2413.                 aheadPos = m_Path.CalculateTargetPos(myPos, 0.f, 0.f, m_movementAbility.pathRadius, true);
  2414.                 if (outside && !m_Path.Empty() && Distance::Point_Point2DSq(aheadPos, objectPos) < square(avoidanceR))
  2415.                 {
  2416.                         static float advanceFrac = 0.2f;
  2417.                         Vec3 pathNextPoint;
  2418.                         if (m_Path.GetPosAlongPath(pathNextPoint, advanceFrac * avoidanceR, true, false))
  2419.                                 m_Path.UpdatePathPosition(pathNextPoint, 100.0f, true, false);
  2420.                 }
  2421.         }
  2422.  
  2423.         Vec3 toTargetDir(objectPos - myPos);
  2424.         toTargetDir.z = 0.f;
  2425.         float toTargetDist = toTargetDir.NormalizeSafe();
  2426.         Vec3 forward2D(m_State.vMoveDir);
  2427.         forward2D.z = 0.f;
  2428.         forward2D.NormalizeSafe();
  2429.         Vec3 steerSideDir(forward2D.y, -forward2D.x, 0.f);
  2430.         // +ve when approaching, -ve when receeding
  2431.         float toTargetDot = forward2D.Dot(toTargetDir);
  2432.         Limit(toTargetDot, 0.5f, 1.0f);
  2433.  
  2434.         // which way to turn
  2435.         float steerSign = steerSideDir.Dot(toTargetDir);
  2436.         steerSign = steerSign > 0.0f ? 1.0f : -1.0f;
  2437.  
  2438.         float toTargetDistScale = 1.0f - (toTargetDist / avoidanceR);
  2439.         Limit(toTargetDistScale, 0.0f, 1.0f);
  2440.         toTargetDistScale = sqrtf(toTargetDistScale);
  2441.  
  2442.         Vec3 thisSteerOffset = -toTargetDistScale * steerSign * steerSideDir * toTargetDot;
  2443.         if (!outside)
  2444.                 thisSteerOffset *= 0.1f;
  2445.  
  2446.         steerOffset += thisSteerOffset;
  2447.  
  2448.         float normalSpeed, minSpeed, maxSpeed;
  2449.         GetMovementSpeedRange(m_State.fMovementUrgency, m_State.allowStrafing, normalSpeed, minSpeed, maxSpeed);
  2450.         //  float normalSpeed = GetNormalMovementSpeed(m_State.fMovementUrgency, true);
  2451.         if (m_State.fDesiredSpeed > maxAllowedSpeedMod * normalSpeed)
  2452.                 m_State.fDesiredSpeed = maxAllowedSpeedMod * normalSpeed;
  2453.  
  2454.         if (!steerOffset.IsZero())
  2455.         {
  2456.                 m_State.vMoveDir += steerOffset;
  2457.                 m_State.vMoveDir.NormalizeSafe();
  2458.         }
  2459.         return true;
  2460. }
  2461.  
  2462. //===================================================================
  2463. // SteerAround3D
  2464. // Danny TODO make this 3D!!!
  2465. //===================================================================
  2466. bool CPuppet::SteerAround3D(const Vec3& targetPos, const CAIObject* object, const Vec3& myPos, const Vec3& objectPos)
  2467. {
  2468.         const CAIActor* pActor = object->CastToCAIActor();
  2469.         float avoidanceR = m_movementAbility.avoidanceRadius;
  2470.         avoidanceR += pActor->m_movementAbility.avoidanceRadius;
  2471.         float avoidanceRSq = square(avoidanceR);
  2472.  
  2473.         Vec3 delta = objectPos - myPos;
  2474.         // skip if we're not close
  2475.         float distSq = delta.GetLengthSquared();
  2476.         if (distSq > square(avoidanceR))
  2477.                 return false;
  2478.  
  2479.         Vec3 aheadPos = m_Path.CalculateTargetPos(myPos, 0.f, 0.f, m_movementAbility.pathRadius, true);
  2480.         if (Distance::Point_Point2DSq(aheadPos, objectPos) < square(avoidanceR))
  2481.         {
  2482.                 static float advanceFrac = 0.2f;
  2483.                 Vec3 pathNextPoint;
  2484.                 if (m_Path.GetPosAlongPath(pathNextPoint, advanceFrac * avoidanceR, true, false))
  2485.                         m_Path.UpdatePathPosition(pathNextPoint, 100.0f, true, false);
  2486.         }
  2487.         Vec3 toTargetDir(objectPos - myPos);
  2488.         toTargetDir.z = 0.f;
  2489.         float toTargetDist = toTargetDir.NormalizeSafe();
  2490.         Vec3 forward2D(m_State.vMoveDir);
  2491.         forward2D.z = 0.f;
  2492.         forward2D.NormalizeSafe();
  2493.         Vec3 steerDir(forward2D.y, -forward2D.x, 0.f);
  2494.  
  2495.         // +ve when approaching, -ve when receeding
  2496.         float toTargetDot = forward2D.Dot(toTargetDir);
  2497.         // which way to turn
  2498.         float steerSign = steerDir.Dot(toTargetDir);
  2499.         steerSign = steerSign > 0.0f ? 1.0f : -1.0f;
  2500.  
  2501.         float toTargetDistScale = 1.0f - (toTargetDist / avoidanceR);
  2502.         Limit(toTargetDistScale, 0.0f, 1.0f);
  2503.         toTargetDistScale = sqrtf(toTargetDistScale);
  2504.  
  2505.         m_State.vMoveDir = m_State.vMoveDir - toTargetDistScale * steerSign * steerDir * toTargetDot;
  2506.         m_State.vMoveDir.NormalizeSafe();
  2507.  
  2508.         return true;
  2509. }
  2510.  
  2511. //===================================================================
  2512. // SteerAroundVehicles
  2513. //===================================================================
  2514. bool CPuppet::SteerAroundVehicle(const Vec3& targetPos, const CAIObject* object, const Vec3& myPos, const Vec3& objectPos)
  2515. {
  2516.         // if vehicle is in the same formation (convoy) - don't steer around it, otherwise can't stay in formation
  2517.         if (const CAIVehicle* pVehicle = object->CastToCAIVehicle())
  2518.         {
  2519.                 if (GetAISystem()->SameFormation(this, pVehicle))
  2520.                         return false;
  2521.         }
  2522.         // currently puppet algorithm seems to work ok.
  2523.         return SteerAroundPuppet(targetPos, object, myPos, objectPos);
  2524. }
  2525.  
  2526. //===================================================================
  2527. // CreateFormation
  2528. //===================================================================
  2529. bool CPuppet::CreateFormation(const char* szName, Vec3 vTargetPos)
  2530. {
  2531.         // special handling for beacons :) It will create a formation point where the current target of the
  2532.         // puppet is.
  2533.         if (!stricmp(szName, "beacon"))
  2534.         {
  2535.                 UpdateBeacon();
  2536.                 return (m_pFormation != NULL);
  2537.         }
  2538.         return CAIObject::CreateFormation(szName, vTargetPos);
  2539. }
  2540.  
  2541. //===================================================================
  2542. // Reset
  2543. //===================================================================
  2544. void CPuppet::Reset(EObjectResetType type)
  2545. {
  2546.         AILogComment("CPuppet::Reset %s (%p)", GetName(), this);
  2547.  
  2548.         CPipeUser::Reset(type); // creates the proxy
  2549.  
  2550.         m_bCanReceiveSignals = true;
  2551.  
  2552.         LineOfFireState().Swap(m_lineOfFireState);
  2553.         ValidTargetState().Swap(m_validTargetState);
  2554.  
  2555.         CAISystem* pAISystem = GetAISystem();
  2556.  
  2557.         m_steeringOccupancy.Reset(Vec3Constants<float>::fVec3_Zero, Vec3Constants<float>::fVec3_OneY, 1.0f);
  2558.         m_steeringOccupancyBias = 0;
  2559.         m_steeringAdjustTime = 0;
  2560.  
  2561.         m_mapDevaluedPoints.clear();
  2562.  
  2563.         m_steeringObjects.clear();
  2564.  
  2565.         ClearPotentialTargets();
  2566.         m_fLastUpdateTime = 0.0f;
  2567.  
  2568.         m_bDryUpdate = false;
  2569.  
  2570.         m_fLastNavTest = 0.0f;
  2571.  
  2572.         //Reset target movement tracking
  2573.         m_targetApproaching = false;
  2574.         m_targetFleeing = false;
  2575.         m_targetApproach = 0;
  2576.         m_targetFlee = 0;
  2577.         m_lastTargetValid = false;
  2578.         m_allowedStrafeDistanceStart = 0.0f;
  2579.         m_allowedStrafeDistanceEnd = 0.0f;
  2580.         m_allowStrafeLookWhileMoving = false;
  2581.         m_strafeStartDistance = 0;
  2582.         m_closeRangeStrafing = false;
  2583.  
  2584.         m_currentWeaponId = 0;
  2585.         m_CurrentWeaponDescriptor = AIWeaponDescriptor();
  2586.  
  2587.         m_bGrenadeThrowRequested = false;
  2588.         m_eGrenadeThrowRequestType = eRGT_INVALID;
  2589.         m_iGrenadeThrowTargetType = 0;
  2590.  
  2591.         m_lastAimObstructionResult = true;
  2592.         m_updatePriority = AIPUP_LOW;
  2593.  
  2594.         m_adaptiveUrgencyMin = 0.0f;
  2595.         m_adaptiveUrgencyMax = 0.0f;
  2596.         m_adaptiveUrgencyScaleDownPathLen = 0.0f;
  2597.         m_adaptiveUrgencyMaxPathLen = 0.0f;
  2598.  
  2599.         m_delayedStance = STANCE_NULL;
  2600.         m_delayedStanceMovementCounter = 0;
  2601.  
  2602.         m_timeSinceTriggerPressed = 0.0f;
  2603.         m_friendOnWayElapsedTime = 0.0f;
  2604.  
  2605.         if (m_pFireCmdHandler)
  2606.                 m_pFireCmdHandler->Reset();
  2607.         if (m_pFireCmdGrenade)
  2608.                 m_pFireCmdGrenade->Reset();
  2609.  
  2610.         m_PFBlockers.clear();
  2611.  
  2612.         m_CurrentHideObject.Set(0, Vec3Constants<float>::fVec3_Zero, Vec3Constants<float>::fVec3_Zero);
  2613.         m_InitialPath.clear();
  2614.  
  2615.         SetAvoidedVehicle(NILREF);
  2616.         //make sure i'm added to groupsMap; no problem if there already.
  2617.         pAISystem->AddToGroup(this, GetGroupId());
  2618.  
  2619.         // Initially allowed to hit target if not using ambient fire system
  2620.         const bool bAmbientFireEnabled = (gAIEnv.CVars.AmbientFireEnable != 0);
  2621.         m_allowedToHitTarget = !bAmbientFireEnabled;
  2622.  
  2623.         m_allowedToUseExpensiveAccessory = false;
  2624.         m_firingReactionTimePassed = false;
  2625.         m_firingReactionTime = 0.0f;
  2626.         m_outOfAmmoTimeOut = 0.0f;
  2627.  
  2628.         m_currentNavSOStates.Clear();
  2629.         m_pendingNavSOStates.Clear();
  2630.  
  2631.         m_targetSilhouette.Reset();
  2632.         m_targetLastMissPoint.zero();
  2633.         m_targetFocus = 0.0f;
  2634.         m_targetZone = AIZONE_OUT;
  2635.         m_targetPosOnSilhouettePlane.zero();
  2636.         m_targetDistanceToSilhouette = FLT_MAX;
  2637.         m_targetBiasDirection.Set(0, 0, -1);
  2638.         m_targetEscapeLastMiss = 0.0f;
  2639.         m_targetSeenTime = 0;
  2640.         m_targetLostTime = 0;
  2641.  
  2642.         m_alarmedTime = 0.0f;
  2643.         m_alarmedLevel = 0.0f;
  2644.  
  2645.         m_targetDamageHealthThr = -1.0f;
  2646.         m_burstEffectTime = 0.0f;
  2647.         m_burstEffectState = 0;
  2648.         m_targetDazzlingTime = 0.0f;
  2649.  
  2650.         if (m_targetDamageHealthThrHistory)
  2651.                 m_targetDamageHealthThrHistory->Reset();
  2652.  
  2653.         m_vForcedNavigation.zero();
  2654.         m_fForcedNavigationSpeed = 0.0f;
  2655.  
  2656.         m_vehicleStickTarget = 0;
  2657.  
  2658.         m_lastMissShotsCount = ~0l;
  2659.         m_lastHitShotsCount = ~0l;
  2660.         m_lastTargetPart = ~0l;
  2661.  
  2662.         m_damagePartsUpdated = false;
  2663.  
  2664.         // Default perception descriptors
  2665.         stl::free_container(m_SoundPerceptionDescriptor);
  2666.  
  2667.         m_fireDisabled = 0;
  2668.  
  2669.         ResetAlertness();
  2670. }
  2671.  
  2672. //===================================================================
  2673. // SDynamicHidePositionNotInNavType
  2674. //===================================================================
  2675. struct SDynamicHidePositionNotInNavType
  2676. {
  2677.         SDynamicHidePositionNotInNavType(IAISystem::tNavCapMask mask) : mask(mask) {}
  2678.         bool operator()(const SHideSpot& hs)
  2679.         {
  2680.                 if (hs.info.type != SHideSpotInfo::eHST_DYNAMIC)
  2681.                         return false;
  2682.                 int nBuildingID;
  2683.                 IAISystem::ENavigationType navType = gAIEnv.pNavigation->CheckNavigationType(hs.info.pos, nBuildingID, mask);
  2684.                 return (navType & mask) == 0;
  2685.         }
  2686.         IAISystem::tNavCapMask mask;
  2687. };
  2688.  
  2689. //===================================================================
  2690. // IsSmartObjectHideSpot
  2691. //===================================================================
  2692. inline bool IsSmartObjectHideSpot(const std::pair<float, SHideSpot>& hsPair)
  2693. {
  2694.         return hsPair.second.info.type == SHideSpotInfo::eHST_SMARTOBJECT;
  2695. }
  2696.  
  2697. //===================================================================
  2698. // Check if path to new spot will cross the target fire dir
  2699. //===================================================================
  2700. /*static bool   IsRightOf(const Vec3& Pos, const Vec3& Dir,const Vec3& Target)
  2701.    {
  2702.    Vec3 vDiff = Target - Pos;
  2703.    float fDotLeft = (vDiff.x * -Dir.y) + (vDiff.y * Dir.x);
  2704.  
  2705.    return (fDotLeft > 0.0f);
  2706.    }
  2707.  
  2708.    //===================================================================
  2709.    // Check if path to new spot will cross the target fire dir
  2710.    //===================================================================
  2711.    static bool  IsBehindOf(const Vec3& Pos, const Vec3& Dir,const Vec3& Target)
  2712.    {
  2713.    Vec3 vDiff = Target - Pos;
  2714.    float fDotFront = (vDiff.x * Dir.x) + (vDiff.y * Dir.y);
  2715.  
  2716.    return (fDotFront < 0.0f);
  2717.    }
  2718.  */
  2719. //===================================================================
  2720. // Check if path to new spot will cross the target fire dir
  2721. //===================================================================
  2722. /*static bool   IsCrossingTargetDir(const Vec3& OriginalPos, const Vec3& PretendedNewPos, const Vec3& TargetPos, const Vec3& TargetDir)
  2723.    {
  2724.    bool bRet = false;
  2725.  
  2726.    Vec3 DirToOriginalPos(TargetPos - OriginalPos);
  2727.    Vec3 DirToPretendedPos(TargetPos - PretendedNewPos);
  2728.  
  2729.    DirToOriginalPos.z = 0;
  2730.    DirToOriginalPos.NormalizeSafe();
  2731.  
  2732.    DirToPretendedPos.z = 0;
  2733.    DirToPretendedPos.NormalizeSafe();
  2734.  
  2735.    //GetAISystem()->AddPerceptionDebugLine("tgt", TargetPos, (TargetPos + (TargetDir * 20.0f)), 0, 0, 255, 5.f, 5.f);
  2736.  
  2737.    if(IsBehindOf(TargetPos, TargetDir, OriginalPos) == false || IsBehindOf(TargetPos, TargetDir, PretendedNewPos) == false)
  2738.    {
  2739.     if( IsRightOf(TargetPos, TargetDir, OriginalPos) != IsRightOf(TargetPos, TargetDir, PretendedNewPos) )
  2740.     {
  2741.       bRet = true;
  2742.     }
  2743.    }
  2744.  
  2745.    return (bRet);
  2746.    }
  2747.  */
  2748. //===================================================================
  2749. // Check if path to new spot will cross the target fire dir
  2750. //===================================================================
  2751. /*static bool CheckVisibilityBetweenTwoPoints(const Vec3& Pos1, const Vec3& Pos2)
  2752.    {
  2753.    bool bRet = false;
  2754.    ray_hit hit;
  2755.  
  2756.    bRet = 0 == gEnv->pPhysicalWorld->RayWorldIntersection(Pos2, (Pos1 - Pos2), COVER_OBJECT_TYPES, AI_VISION_RAY_CAST_FLAG_BLOCKED_BY_SOLID_COVER | AI_VISION_RAY_CAST_FLAG_BLOCKED_BY_SOFT_COVER, &hit, 1);
  2757.  
  2758.    if( gAIEnv.CVars.DrawHideSpotSearchRays == 1 )
  2759.    {
  2760.     if(bRet == true)
  2761.       GetAISystem()->AddDebugLine(Pos1, Pos2, 0, 255, 0, 20.f);
  2762.     else
  2763.       GetAISystem()->AddDebugLine(Pos1, Pos2, 255, 0, 0, 20.f);
  2764.    }
  2765.  
  2766.    return (bRet);
  2767.    }
  2768.  */
  2769. //===================================================================
  2770. // Check if path to new spot will cross the target fire dir
  2771. //===================================================================
  2772. /*
  2773.    static bool  CanShootTargetFromThere(const Vec3& PretendedNewPos, const Vec3& TargetPos)
  2774.    {
  2775.    bool bRet = false;
  2776.    Vec3 vPos = PretendedNewPos;
  2777.    vPos.z += 1.f;
  2778.  
  2779.    float fLeanDist = 0.7f;
  2780.    Vec3 vDir = TargetPos - PretendedNewPos;
  2781.    vDir.Normalize();
  2782.  
  2783.    Matrix33 orientation = Matrix33::CreateRotationVDir( vDir, 0 );
  2784.    Vec3 vRight = orientation.TransformVector(Vec3(1,0,0));
  2785.  
  2786.    bRet = CheckVisibilityBetweenTwoPoints(vPos + (vRight * fLeanDist), TargetPos + (vRight * fLeanDist));
  2787.  
  2788.    if(bRet == false)
  2789.    {
  2790.     bRet =CheckVisibilityBetweenTwoPoints(vPos + (-vRight * fLeanDist), TargetPos + (-vRight * fLeanDist));
  2791.    }
  2792.  
  2793.    return (bRet);
  2794.    }
  2795.  */
  2796.  
  2797. //====================================================================
  2798. // GetAccuracy
  2799. //      calculate current accuracy - account for distance, target stance, ...
  2800. //      at close range always hit, at attackRange always miss
  2801. //      if accuracy in properties is 1 - ALWAYS hit
  2802. //      if accuracy in properties is 0 - ALWAYS miss
  2803. //====================================================================
  2804. float CPuppet::GetAccuracy(const CAIObject* pTarget) const
  2805. {
  2806.  
  2807.         //---------parameters------------------------------------------
  2808.         const float absoluteAccurateTrh(5.f); // if closer than this - always hit
  2809.         //      const float     accurateTrhSlope(.3f);          // slop from aways-hit to nominal accuracy
  2810.         const float nominalAccuracyStartAt(.3f);    // at what attack range nominal accuracy is on
  2811.         const float nominalAccuracyStopAt(.73f);    // at what attack range nominal accuracy is starting to fade to 0
  2812.         //-------------------------------------------------------------
  2813.  
  2814.         float unscaleAccuracy = GetParameters().m_fAccuracy;
  2815.         float curAccuracy = unscaleAccuracy;
  2816.         if (curAccuracy <= 0.00001f)
  2817.                 return 0.f;
  2818.  
  2819.         if (!IsAllowedToHitTarget())
  2820.                 curAccuracy *= 0.0f;
  2821.  
  2822.         if (!pTarget)
  2823.                 return curAccuracy;
  2824.  
  2825.         const CAIActor* pTargetActor = pTarget->CastToCAIActor();
  2826.  
  2827.         //curAccuracy = max(0.f, curAccuracy);  // account for soft cover
  2828.         float distance((pTarget->GetPos() - GetPos()).len());
  2829.  
  2830.         if (distance < absoluteAccurateTrh)  // too close - always hit