BVB Source Codes

CRYENGINE Show TargetTrack.cpp Source code

Return Download CRYENGINE: download TargetTrack.cpp Source code - Download CRYENGINE Source code - Type:.cpp
  1. // Copyright 2001-2016 Crytek GmbH / Crytek Group. All rights reserved.
  2.  
  3. /*************************************************************************
  4.    -------------------------------------------------------------------------
  5.    $Id$
  6.    $DateTime$
  7.    Description: Maintains an interest level of an agent's perception on a
  8.         target, used for determining the agent's target
  9.  
  10.    -------------------------------------------------------------------------
  11.    History:
  12.    - 02:01:2010: Created by Kevin Kirst
  13.  
  14. *************************************************************************/
  15.  
  16. #include "StdAfx.h"
  17. #include "TargetTrack.h"
  18. #include "TargetTrackModifiers.h"
  19. #include "PipeUser.h"
  20. #include "ObjectContainer.h"
  21. #include "AIVehicle.h"
  22.  
  23. #ifdef TARGET_TRACK_DEBUG
  24.         #include "DebugDrawContext.h"
  25. #endif //TARGET_TRACK_DEBUG
  26.  
  27. // Error ratio beyond the agent's update rate to consider the stimulus invocation to still be running
  28. // A higher value means we lessen the impact of thrashing via the invocation turning on/off rapidly,
  29. //      but it has the impact of introducing latency
  30. static const float TARGET_TRACK_RUNNING_THRESHOLD = 0.01f;
  31.  
  32. //////////////////////////////////////////////////////////////////////////
  33. bool CTargetTrack::SStimulusInvocation::IsRunning(float fUpdateInterval) const
  34. {
  35.         bool bResult = m_bMustRun;
  36.         if (!bResult)
  37.         {
  38.                 CAISystem* pAISystem = GetAISystem();
  39.                 assert(pAISystem);
  40.  
  41.                 const float fCurrTime = pAISystem->GetFrameStartTimeSeconds();
  42.                 bResult = (fCurrTime - m_envelopeData.m_fLastInvokeTime - fUpdateInterval * 2.0f <= TARGET_TRACK_RUNNING_THRESHOLD);
  43.         }
  44.  
  45.         return bResult;
  46. }
  47.  
  48. //////////////////////////////////////////////////////////////////////////
  49. void CTargetTrack::SStimulusInvocation::SPulseTrigger::Serialize(TSerialize ser)
  50. {
  51.         ser.Value("uPulseNameHash", uPulseNameHash);
  52.         ser.Value("fTriggerTime", fTriggerTime);
  53. }
  54.  
  55. //////////////////////////////////////////////////////////////////////////
  56. void CTargetTrack::SStimulusInvocation::Serialize(TSerialize ser)
  57. {
  58.         ser.Value("m_vLastPos", m_vLastPos);
  59.         ser.Value("m_vLastDir", m_vLastDir);
  60.         ser.Value("m_fCurrentValue", m_envelopeData.m_fCurrentValue);
  61.         ser.Value("m_fStartTime", m_envelopeData.m_fStartTime);
  62.         ser.Value("m_fLastInvokeTime", m_envelopeData.m_fLastInvokeTime);
  63.         ser.Value("m_fLastRunningValue", m_envelopeData.m_fLastRunningValue);
  64.         ser.Value("m_fLastReleasingValue", m_envelopeData.m_fLastReleasingValue);
  65.         ser.Value("m_pulseTriggers", m_pulseTriggers);
  66.         ser.EnumValue("m_eTargetThreat", m_eTargetThreat, AITHREAT_NONE, AITHREAT_LAST);
  67.         ser.EnumValue("m_eTargetContextType", m_eTargetContextType, AITARGET_CONTEXT_UNKNOWN, AITARGET_CONTEXT_LAST);
  68.  
  69.         uint8 stimulusType = (int8)m_eStimulusType;
  70.         ser.Value("m_eStimulusType", stimulusType);
  71.         m_eStimulusType = (TargetTrackHelpers::EAIEventStimulusType)stimulusType;
  72. }
  73.  
  74. //////////////////////////////////////////////////////////////////////////
  75. CTargetTrack::CTargetTrack()
  76.         : m_vTargetPos(ZERO)
  77.         , m_vTargetDir(ZERO)
  78.         , m_eTargetType(AITARGET_NONE)
  79.         , m_eTargetContextType(AITARGET_CONTEXT_UNKNOWN)
  80.         , m_eTargetThreat(AITHREAT_NONE)
  81.         , m_uConfigHash(0)
  82.         , m_iLastUpdateFrame(0)
  83.         , m_fTrackValue(0.0f)
  84.         , m_fFirstVisualTime(0.0f)
  85.         , m_fLastVisualTime(0.0f)
  86.         , m_fThreatRatio(0.0f)
  87. {
  88. #ifdef TARGET_TRACK_DEBUG
  89.         m_fLastDebugDrawTime = 0.0f;
  90.         m_uDebugGraphIndex = 0;
  91. #endif //TARGET_TRACK_DEBUG
  92. }
  93.  
  94. //////////////////////////////////////////////////////////////////////////
  95. CTargetTrack::~CTargetTrack()
  96. {
  97.  
  98. }
  99.  
  100. //////////////////////////////////////////////////////////////////////////
  101. void CTargetTrack::Init(tAIObjectID aiGroupOwnerId, tAIObjectID aiObjectId, uint32 uConfigHash)
  102. {
  103.         assert(aiGroupOwnerId > 0);
  104.         assert(uConfigHash > 0);
  105.  
  106.         m_groupOwner = gAIEnv.pObjectContainer->GetWeakRef(aiGroupOwnerId);
  107.         m_object = gAIEnv.pObjectContainer->GetWeakRef(aiObjectId);
  108.         m_uConfigHash = uConfigHash;
  109. }
  110.  
  111. //////////////////////////////////////////////////////////////////////////
  112. void CTargetTrack::ResetForPool()
  113. {
  114.         m_vTargetPos.zero();
  115.         m_vTargetDir.zero();
  116.         m_eTargetType = AITARGET_NONE;
  117.         m_eTargetContextType = AITARGET_CONTEXT_UNKNOWN;
  118.         m_eTargetThreat = AITHREAT_NONE;
  119.  
  120.         m_groupOwner.Reset();
  121.         m_object.Reset();
  122.         m_uConfigHash = 0;
  123.  
  124.         m_fLastVisualTime = 0.0f;
  125.  
  126.         m_iLastUpdateFrame = 0;
  127.         m_fTrackValue = 0.0f;
  128.         m_fFirstVisualTime = 0.0f;
  129.         m_fThreatRatio = 0.0f;
  130.         m_StimuliInvocations.clear();
  131. }
  132.  
  133. //////////////////////////////////////////////////////////////////////////
  134. void CTargetTrack::Serialize(TSerialize ser)
  135. {
  136.         ser.Value("m_fTrackValue", m_fTrackValue);
  137.         ser.Value("m_fFirstVisualTime", m_fFirstVisualTime);
  138.         ser.Value("m_fThreatRatio", m_fThreatRatio);
  139.         ser.Value("m_StimuliInvocations", m_StimuliInvocations);
  140.  
  141.         if (ser.IsReading())
  142.                 m_iLastUpdateFrame = 0;
  143. }
  144.  
  145. //////////////////////////////////////////////////////////////////////////
  146. float CTargetTrack::GetHighestEnvelopeValue() const
  147. {
  148.         float fHighestEnvelopeValue = 0.0f;
  149.  
  150.         TStimuliInvocationContainer::const_iterator itStimulusInvoke = m_StimuliInvocations.begin();
  151.         TStimuliInvocationContainer::const_iterator itStimulusInvokeEnd = m_StimuliInvocations.end();
  152.         for (; itStimulusInvoke != itStimulusInvokeEnd; ++itStimulusInvoke)
  153.         {
  154.                 const SStimulusInvocation& invoke = itStimulusInvoke->second;
  155.                 fHighestEnvelopeValue = max(fHighestEnvelopeValue, invoke.m_envelopeData.m_fCurrentValue);
  156.         }
  157.  
  158.         return fHighestEnvelopeValue;
  159. }
  160.  
  161. //////////////////////////////////////////////////////////////////////////
  162. float CTargetTrack::GetUpdateInterval() const
  163. {
  164.         CPipeUser* pPipeUser = CastToCPipeUserSafe(m_groupOwner.GetAIObject());
  165.         if (pPipeUser)
  166.         {
  167.                 return pPipeUser->GetLastUpdateInterval();
  168.         }
  169.  
  170.         return GetAISystem()->GetUpdateInterval();
  171. }
  172.  
  173. //////////////////////////////////////////////////////////////////////////
  174. CWeakRef<CAIObject> CTargetTrack::GetAITarget() const
  175. {
  176.         // Check if has vehicle attached to it and use it if possible
  177.         CAIActor* pAIActor = CastToCAIActorSafe(m_object.GetAIObject());
  178.         IAIActorProxy* pAIProxy = (pAIActor ? pAIActor->GetProxy() : NULL);
  179.         if (pAIProxy)
  180.         {
  181.                 EntityId vehicleId = pAIProxy->GetLinkedVehicleEntityId();
  182.                 IEntity* pVehicle = (vehicleId > 0 ? gEnv->pEntitySystem->GetEntity(vehicleId) : NULL);
  183.  
  184.                 if (pVehicle)
  185.                 {
  186.                         CWeakRef<CAIObject> refVehicle = gAIEnv.pObjectContainer->GetWeakRef(pVehicle->GetAIObjectID());
  187.  
  188.                         CAIObject* vehicleAIObject = refVehicle.GetAIObject();
  189.                         CAIVehicle* aiVehicle = vehicleAIObject ? vehicleAIObject->CastToCAIVehicle() : 0;
  190.                         CAIActor* driver = aiVehicle ? aiVehicle->GetDriver() : 0;
  191.  
  192.                         if (driver == pAIActor)
  193.                         {
  194.                                 assert(refVehicle.IsValid());
  195.                                 return refVehicle;
  196.                         }
  197.                 }
  198.         }
  199.  
  200.         return m_object;
  201. }
  202.  
  203. //////////////////////////////////////////////////////////////////////////
  204. bool CTargetTrack::Update(float fCurrTime, TargetTrackHelpers::ITargetTrackConfigProxy* pConfigProxy)
  205. {
  206.         FUNCTION_PROFILER(GetISystem(), PROFILE_AI);
  207.  
  208.         CAISystem* pAISystem = GetAISystem();
  209.         assert(pAISystem);
  210.  
  211.         bool bHasTarget = true;
  212.         bool containsNonVisualStimulus = false;
  213.  
  214.         const int iFrameId = pAISystem->GetAITickCount();
  215.         if (iFrameId != m_iLastUpdateFrame)
  216.         {
  217.                 bHasTarget = false;
  218.                 m_iLastUpdateFrame = iFrameId;
  219.  
  220.                 float fLastInvokeTime = 0.0f;
  221.                 float fLastStartInvoke = 0.0f;
  222.                 m_fTrackValue = 0.0f;
  223.                 EAITargetType eNewTargetType = AITARGET_NONE;
  224.                 EAITargetContextType eNewTargetSubType = AITARGET_CONTEXT_UNKNOWN;
  225.                 EAITargetThreat eNewTargetThreat = AITHREAT_NONE;
  226.  
  227.                 // For a brief moment after the AI looses a visual target, the memory
  228.                 // position will be kept up to date. This is awesome for two reasons:
  229.                 // 1. The player can't quickly run closely by the AI and hide
  230.                 //    behind without the AI knowing where the player is. Win!
  231.                 // 2. When the player runs behind an object, the AI has an idea
  232.                 //    where the player is going to pop out. Cool!
  233.                 const float timeSinceVisual = fCurrTime - m_fLastVisualTime;
  234.                 const float intuitionTime = 1.0f;
  235.                 const bool intuition = (m_eTargetType == AITARGET_MEMORY) && (timeSinceVisual < intuitionTime);
  236.                 CAIObject* target = m_object.GetAIObject();
  237.  
  238.                 TStimuliInvocationContainer::iterator itStimulusInvoke = m_StimuliInvocations.begin();
  239.                 TStimuliInvocationContainer::iterator itStimulusInvokeEnd = m_StimuliInvocations.end();
  240.                 for (; itStimulusInvoke != itStimulusInvokeEnd; ++itStimulusInvoke)
  241.                 {
  242.                         const uint32 uStimulusHash = itStimulusInvoke->first;
  243.                         SStimulusInvocation& invoke = itStimulusInvoke->second;
  244.  
  245.                         const TargetTrackHelpers::STargetTrackStimulusConfig* pStimulusConfig = NULL;
  246.                         if (pConfigProxy->GetTargetTrackStimulusConfig(m_uConfigHash, uStimulusHash, pStimulusConfig))
  247.                         {
  248.                                 SStimData stimData;
  249.                                 const float fStimulusValue = UpdateStimulusValue(fCurrTime, invoke, pStimulusConfig, pConfigProxy, stimData);
  250.  
  251.                                 if (intuition && target)
  252.                                 {
  253.                                         invoke.m_vLastPos = target->GetPos();
  254.                                         invoke.m_vLastDir = target->GetEntityDir();
  255.                                 }
  256.  
  257.                                 // Update position to most recent invocation's info
  258.                                 if (invoke.m_envelopeData.m_fLastInvokeTime > fLastInvokeTime)
  259.                                 {
  260.                                         fLastInvokeTime = invoke.m_envelopeData.m_fLastInvokeTime;
  261.  
  262.                                         m_vTargetPos = invoke.m_vLastPos;
  263.                                         m_vTargetDir = invoke.m_vLastDir;
  264.                                 }
  265.  
  266.                                 //Context uses the most recent
  267.                                 if (invoke.m_envelopeData.m_fStartTime > fLastStartInvoke)
  268.                                 {
  269.                                         fLastStartInvoke = invoke.m_envelopeData.m_fStartTime;
  270.                                         eNewTargetSubType = invoke.m_eTargetContextType;
  271.                                 }
  272.  
  273.                                 //Note if at least one active invocation is not visual
  274.                                 if (fStimulusValue > 0.0f && invoke.m_eStimulusType != TargetTrackHelpers::eEST_Visual)
  275.                                 {
  276.                                         containsNonVisualStimulus = true;
  277.                                 }
  278.  
  279.                                 // Track value and threat uses the highest
  280.                                 m_fTrackValue = max(fStimulusValue, m_fTrackValue);
  281.  
  282. #ifdef TARGET_TRACK_DOTARGETTHREAT
  283.                                 eNewTargetThreat = max(eNewTargetThreat, invoke.m_eTargetThreat);
  284.  
  285.                                 const float currentRatio = (fabs(pStimulusConfig->m_fPeak) > FLT_EPSILON) ? stimData.envelopeValue / pStimulusConfig->m_fPeak : 1.0f; // Prevent div by 0
  286.  
  287.                                 TargetTrackHelpers::STargetTrackStimulusConfig::TThreatLevelContainer::const_iterator threatLevel = pStimulusConfig->m_threatLevels.begin();
  288.                                 TargetTrackHelpers::STargetTrackStimulusConfig::TThreatLevelContainer::const_iterator threatLevelEnd = pStimulusConfig->m_threatLevels.end();
  289.  
  290.                                 for (; threatLevel != threatLevelEnd; ++threatLevel)
  291.                                 {
  292.                                         const float threatLevelRatio = threatLevel->second;
  293.                                         if (currentRatio <= threatLevelRatio)
  294.                                         {
  295.                                                 invoke.m_eTargetThreat = threatLevel->first;
  296.                                                 break;
  297.                                         }
  298.                                 }
  299. #endif  //TARGET_TRACK_DOTARGETTHREAT
  300.  
  301. #ifdef TARGET_TRACK_DOTARGETTYPE
  302.                                 bHasTarget = UpdateTargetType(eNewTargetType, eNewTargetThreat, invoke);
  303.  
  304. #endif  //TARGET_TRACK_DOTARGETTYPE
  305.                         }
  306.  
  307.                         SStimulusInvocation::TPulseTriggersContainer::iterator itNewEnd = std::remove_if(invoke.m_pulseTriggers.begin(), invoke.m_pulseTriggers.end(), SStimulusInvocation::SPulseTrigger::IsObsolete);
  308.                         invoke.m_pulseTriggers.erase(itNewEnd, invoke.m_pulseTriggers.end());
  309.                 }
  310.  
  311.                 m_eTargetThreat = eNewTargetThreat;
  312.                 m_eTargetType = eNewTargetType;
  313.                 m_eTargetContextType = eNewTargetSubType;
  314.         }
  315.  
  316.         if (!bHasTarget || m_eTargetType != AITARGET_VISUAL)
  317.         {
  318.                 m_fFirstVisualTime = 0.0f;
  319.         }
  320.         else if (m_fFirstVisualTime <= 0.0f)  //  && (m_eTargetType == AITARGET_VISUAL)
  321.         {
  322.                 m_fFirstVisualTime = fCurrTime;
  323.         }
  324.  
  325.         if (m_eTargetType == AITARGET_VISUAL)
  326.         {
  327.                 m_fLastVisualTime = fCurrTime;
  328.         }
  329.  
  330. #ifdef TARGET_TRACK_DOTARGETTHREAT
  331.         if (bHasTarget && pConfigProxy)
  332.         {
  333.                 ModifyTargetThreat(pConfigProxy);
  334.  
  335.                 //If this memory has decayed to no threat, then remove it from the target track if there is something else stronger
  336.                 if (m_eTargetType == AITARGET_MEMORY && m_fThreatRatio < FLT_EPSILON && containsNonVisualStimulus)
  337.                 {
  338.                         //Kill ALL visual stimullii on this track. Allows AI which has not gone aggresive to target, to lose weak memories. - Morgan 01/12/2011
  339.                         TStimuliInvocationContainer::iterator itStimulusInvoke = m_StimuliInvocations.begin();
  340.                         for (; itStimulusInvoke != m_StimuliInvocations.end(); ++itStimulusInvoke)
  341.                         {
  342.                                 SStimulusInvocation& invoke = itStimulusInvoke->second;
  343.                                 if (invoke.m_eStimulusType == TargetTrackHelpers::eEST_Visual)
  344.                                 {
  345.                                         invoke.m_envelopeData.m_fCurrentValue = 0.0f;
  346.                                         invoke.m_envelopeData.m_fLastRunningValue = 0.0f;
  347.                                 }
  348.                         }
  349.                 }
  350.         }
  351.         else
  352.         {
  353.                 m_fThreatRatio = 0.0f;
  354.         }
  355. #endif //TARGET_TRACK_DOTARGETTHREAT
  356.  
  357.         return bHasTarget;
  358. }
  359.  
  360. //////////////////////////////////////////////////////////////////////////
  361. #ifdef TARGET_TRACK_DOTARGETTHREAT
  362. void CTargetTrack::ModifyTargetThreat(TargetTrackHelpers::ITargetTrackConfigProxy* pConfigProxy)
  363. {
  364.         assert(pConfigProxy);
  365.  
  366.         CAIObject* pOwner = m_groupOwner.GetAIObject();
  367.         CAIObject* pTarget = m_object.GetAIObject();
  368.  
  369.         const bool modifyTargetTrack = (pOwner != NULL) && (pTarget != NULL);
  370.         if (modifyTargetTrack)
  371.         {
  372.                 pConfigProxy->ModifyTargetThreat(*pOwner, *pTarget, *this, m_fThreatRatio, m_eTargetThreat);
  373.         }
  374. }
  375. #endif //TARGET_TRACK_DOTARGETTHREAT
  376.  
  377. //////////////////////////////////////////////////////////////////////////
  378. #ifdef TARGET_TRACK_DOTARGETTYPE
  379. bool CTargetTrack::UpdateTargetType(EAITargetType& outTargetType, EAITargetThreat eTargetThreat, const SStimulusInvocation& invoke)
  380. {
  381.         bool bResult = false;
  382.  
  383.         // Update the target type
  384.         switch (invoke.m_eStimulusType)
  385.         {
  386.         case TargetTrackHelpers::eEST_Visual:
  387.                 {
  388.                         if (outTargetType < AITARGET_VISUAL)
  389.                         {
  390.                                 outTargetType = (invoke.IsRunning(GetUpdateInterval()) && invoke.m_eTargetThreat == AITHREAT_AGGRESSIVE ? AITARGET_VISUAL : AITARGET_MEMORY);
  391.                         }
  392.                 }
  393.                 break;
  394.  
  395.         case TargetTrackHelpers::eEST_Sound:
  396.         case TargetTrackHelpers::eEST_BulletRain:
  397.         case TargetTrackHelpers::eEST_Generic:
  398.                 {
  399.                         if (outTargetType < AITARGET_SOUND)
  400.                                 outTargetType = AITARGET_SOUND;
  401.                 }
  402.                 break;
  403.         }
  404.  
  405.         bResult = (outTargetType != AITARGET_NONE);
  406.  
  407.         return bResult;
  408. }
  409. #endif //TARGET_TRACK_DOTARGETTYPE
  410.  
  411. //////////////////////////////////////////////////////////////////////////
  412. bool CTargetTrack::InvokeStimulus(const TargetTrackHelpers::STargetTrackStimulusEvent& stimulusEvent, uint32 uStimulusNameHash)
  413. {
  414.         FUNCTION_PROFILER(GetISystem(), PROFILE_AI);
  415.  
  416.         if (uStimulusNameHash > 0)
  417.         {
  418.                 {
  419.                         TStimuliInvocationContainer::iterator itInvoke = m_StimuliInvocations.find(uStimulusNameHash);
  420.  
  421.                         if (itInvoke != m_StimuliInvocations.end())
  422.                         {
  423.                                 SStimulusInvocation& invoke = itInvoke->second;
  424.                                 UpdateStimulusInvoke(invoke, stimulusEvent);
  425.  
  426.                                 return true;
  427.                         }
  428.                 }
  429.  
  430.                 SStimulusInvocation invoke;
  431.                 UpdateStimulusInvoke(invoke, stimulusEvent);
  432.                 m_StimuliInvocations[uStimulusNameHash] = invoke;
  433.  
  434.                 return true;
  435.         }
  436.  
  437.         return false;
  438. }
  439.  
  440. //////////////////////////////////////////////////////////////////////////
  441. bool CTargetTrack::TriggerPulse(uint32 uStimulusNameHash, uint32 uPulseNameHash)
  442. {
  443.         FUNCTION_PROFILER(GetISystem(), PROFILE_AI);
  444.  
  445.         if (uStimulusNameHash > 0 && uPulseNameHash > 0)
  446.         {
  447.                 {
  448.                         TStimuliInvocationContainer::iterator itInvoke = m_StimuliInvocations.find(uStimulusNameHash);
  449.  
  450.                         if (itInvoke != m_StimuliInvocations.end())
  451.                         {
  452.                                 SStimulusInvocation& invoke = itInvoke->second;
  453.                                 UpdateStimulusPulse(invoke, uPulseNameHash);
  454.  
  455.                                 return true;
  456.                         }
  457.                 }
  458.  
  459.                 SStimulusInvocation invoke;
  460.                 UpdateStimulusPulse(invoke, uPulseNameHash);
  461.                 m_StimuliInvocations[uStimulusNameHash] = invoke;
  462.  
  463.                 return true;
  464.         }
  465.  
  466.         return false;
  467. }
  468.  
  469. //////////////////////////////////////////////////////////////////////////
  470. void CTargetTrack::UpdateStimulusInvoke(SStimulusInvocation& invoke, const TargetTrackHelpers::STargetTrackStimulusEvent& stimulusEvent) const
  471. {
  472.         CAISystem* pAISystem = GetAISystem();
  473.         assert(pAISystem);
  474.  
  475.         const float fCurrTime = pAISystem->GetFrameStartTimeSeconds();
  476.  
  477.         if (!invoke.IsRunning(GetUpdateInterval()))
  478.         {
  479.                 //If the stimulus had a previous non-zero running value, then this stimululs was reinvoked.
  480.                 if (invoke.m_envelopeData.m_fLastRunningValue > 0.0f)
  481.                 {
  482.                         invoke.m_envelopeData.m_bReinvoked = true;
  483.                 }
  484.                 //Otherwsie make sure to clear the reinvoke flag
  485.                 else
  486.                 {
  487.                         invoke.m_envelopeData.m_bReinvoked = false;
  488.                 }
  489.                 invoke.m_envelopeData.m_fStartTime = fCurrTime;
  490.         }
  491.  
  492.         CWeakRef<CAIObject> refTarget = gAIEnv.pObjectContainer->GetWeakRef(stimulusEvent.m_targetId);
  493.         CAIObject* pTarget = refTarget.GetAIObject();
  494.  
  495.         if (!stimulusEvent.m_vTargetPos.IsZero())
  496.         {
  497.                 invoke.m_vLastPos = stimulusEvent.m_vTargetPos;
  498.         }
  499.         else
  500.         {
  501.                 if (pTarget)
  502.                         invoke.m_vLastPos = pTarget->GetPos();
  503.                 else
  504.                         CRY_ASSERT_MESSAGE(0, "No position could be set from invoked stimulus event!");
  505.         }
  506.  
  507.         if (pTarget)
  508.                 invoke.m_vLastDir = pTarget->GetEntityDir();
  509.  
  510.         invoke.m_envelopeData.m_fLastInvokeTime = fCurrTime;
  511.         invoke.m_eTargetThreat = stimulusEvent.m_eTargetThreat;
  512.         invoke.m_eStimulusType = stimulusEvent.m_eStimulusType;
  513.  
  514.         if (stimulusEvent.m_sStimulusName == "SoundWeapon")
  515.                 invoke.m_eTargetContextType = AITARGET_CONTEXT_GUNFIRE;
  516.  
  517.         invoke.m_bMustRun = true;
  518. }
  519.  
  520. //////////////////////////////////////////////////////////////////////////
  521. void CTargetTrack::UpdateStimulusPulse(SStimulusInvocation& invoke, uint32 uPulseNameHash) const
  522. {
  523.         assert(uPulseNameHash > 0);
  524.  
  525.         SStimulusInvocation::TPulseTriggersContainer::iterator itPulse = invoke.m_pulseTriggers.begin();
  526.         SStimulusInvocation::TPulseTriggersContainer::iterator itPulseEnd = invoke.m_pulseTriggers.end();
  527.         for (; itPulse != itPulseEnd; ++itPulse)
  528.         {
  529.                 SStimulusInvocation::SPulseTrigger& pulseTrigger = *itPulse;
  530.                 if (pulseTrigger.uPulseNameHash == uPulseNameHash)
  531.                 {
  532.                         UpdatePulseValue(pulseTrigger);
  533.                         return;
  534.                 }
  535.         }
  536.  
  537.         // Add new entry
  538.         SStimulusInvocation::SPulseTrigger pulseTrigger(uPulseNameHash);
  539.         UpdatePulseValue(pulseTrigger);
  540.         invoke.m_pulseTriggers.push_back(pulseTrigger);
  541. }
  542.  
  543. //////////////////////////////////////////////////////////////////////////
  544. void CTargetTrack::UpdatePulseValue(SStimulusInvocation::SPulseTrigger& pulseTrigger) const
  545. {
  546.         CAISystem* pAISystem = GetAISystem();
  547.         assert(pAISystem);
  548.  
  549.         const float fCurrTime = pAISystem->GetFrameStartTimeSeconds();
  550.  
  551.         pulseTrigger.fTriggerTime = fCurrTime;
  552.         pulseTrigger.bObsolete = false;
  553. }
  554.  
  555. //////////////////////////////////////////////////////////////////////////
  556. float CTargetTrack::UpdateStimulusValue(float fCurrTime, SStimulusInvocation& invoke, const TargetTrackHelpers::STargetTrackStimulusConfig* pStimulusConfig,
  557.                                         TargetTrackHelpers::ITargetTrackConfigProxy* pConfigProxy, SStimData& stimData)
  558. {
  559.         assert(pStimulusConfig);
  560.         assert(pConfigProxy);
  561.  
  562.         const float fEnvelopeValue = GetStimulusEnvelopeValue(fCurrTime, invoke, pStimulusConfig);
  563.         const float fPulseValue = GetStimulusPulseValue(fCurrTime, invoke, pStimulusConfig);
  564.         const float fModValue = GetStimulusModifierValue(invoke, pConfigProxy, pStimulusConfig);
  565.  
  566.         stimData.envelopeValue = fEnvelopeValue;
  567.  
  568.         invoke.m_envelopeData.m_fCurrentValue = fEnvelopeValue;
  569.  
  570.         if (invoke.IsRunning(GetUpdateInterval()))
  571.                 invoke.m_envelopeData.m_fLastRunningValue = fEnvelopeValue;
  572.         else
  573.                 invoke.m_envelopeData.m_fLastReleasingValue = fEnvelopeValue;
  574.  
  575.         invoke.m_bMustRun = false;
  576.  
  577.         return GetStimulusTotalValue(fCurrTime, fEnvelopeValue, fPulseValue, fModValue);
  578. }
  579.  
  580. //////////////////////////////////////////////////////////////////////////
  581. float CTargetTrack::GetStimulusTotalValue(float fCurrTime, float fEnvelopeValue, float fPulseValue, float fModValue) const
  582. {
  583.         return (fEnvelopeValue + fPulseValue) * fModValue;
  584. }
  585.  
  586. //////////////////////////////////////////////////////////////////////////
  587. float CTargetTrack::GetStimulusEnvelopeValue(float fCurrTime, const SStimulusInvocation& invoke, const TargetTrackHelpers::STargetTrackStimulusConfig* pStimulusConfig) const
  588. {
  589.         FUNCTION_PROFILER(GetISystem(), PROFILE_AI);
  590.  
  591.         assert(pStimulusConfig);
  592.  
  593.         if (invoke.IsRunning(GetUpdateInterval()))
  594.         {
  595.                 // Check if this stimulus should be ignored for a brief startup time when freshly invoked (new invoke or invocation from zero Stimulus)
  596.                 const bool bUseIgnoreTime = (invoke.m_envelopeData.m_fLastReleasingValue < FLT_EPSILON && !invoke.m_envelopeData.m_bReinvoked);
  597.                 const float fIgnoreEnd = invoke.m_envelopeData.m_fStartTime + (bUseIgnoreTime ? pStimulusConfig->m_fIgnore : 0.0f);
  598.                 if (bUseIgnoreTime && fCurrTime < fIgnoreEnd)
  599.                 {
  600.                         return 0.0f;
  601.                 }
  602.  
  603.                 //Attack
  604.                 const float fAttackEnd = fIgnoreEnd + pStimulusConfig->m_fAttack;
  605.                 //If the stimulus defines an attack value and we are in the attack period
  606.                 if (pStimulusConfig->m_fAttack && fCurrTime <= fAttackEnd)
  607.                 {
  608.                         const float fDuration = fAttackEnd - fIgnoreEnd;
  609.                         const float fAttackRatio = (fCurrTime - fIgnoreEnd) / (fDuration > FLT_EPSILON ? fDuration : 1.0f);
  610.                         return invoke.m_envelopeData.m_fLastReleasingValue + (pStimulusConfig->m_fPeak - invoke.m_envelopeData.m_fLastReleasingValue) * fAttackRatio;
  611.                 }
  612.  
  613.                 // Decay
  614.                 const float fDecayEnd = fAttackEnd + pStimulusConfig->m_fDecay;
  615.                 //If the stimulus defines a decay value and we are in the decay period
  616.                 if (pStimulusConfig->m_fDecay && fCurrTime <= fDecayEnd)
  617.                 {
  618.                         const float fDuration = fDecayEnd - fAttackEnd;
  619.                         const float fDecayRatio = (fCurrTime - fAttackEnd) / (fDuration > FLT_EPSILON ? fDuration : 1.0f);
  620.                         return (pStimulusConfig->m_fPeak - fDecayRatio * (pStimulusConfig->m_fPeak - pStimulusConfig->m_fPeak * pStimulusConfig->m_fSustainRatio));
  621.                 }
  622.  
  623.                 // Sustain
  624.                 return pStimulusConfig->m_fPeak * pStimulusConfig->m_fSustainRatio;
  625.         }
  626.  
  627.         // Release
  628.         const float fReleaseStart = invoke.m_envelopeData.m_fLastInvokeTime;
  629.         const float fReleaseEnd = fReleaseStart + pStimulusConfig->m_fRelease;
  630.         const float fReleaseDuration = fReleaseEnd - fReleaseStart;
  631.         const float fDeltaTime = fCurrTime - fReleaseStart;
  632.         const float fReleaseRatio = (fReleaseDuration > FLT_EPSILON) ? (fDeltaTime / fReleaseDuration) : fDeltaTime;
  633.         return max(0.0f, invoke.m_envelopeData.m_fLastRunningValue - fReleaseRatio * invoke.m_envelopeData.m_fLastRunningValue);
  634. }
  635.  
  636. //////////////////////////////////////////////////////////////////////////
  637. float CTargetTrack::GetStimulusPulseValue(float fCurrTime, const SStimulusInvocation& invoke, const TargetTrackHelpers::STargetTrackStimulusConfig* pStimulusConfig) const
  638. {
  639.         FUNCTION_PROFILER(GetISystem(), PROFILE_AI);
  640.  
  641.         assert(pStimulusConfig);
  642.  
  643.         // Apply combined pulse value
  644.         float fPulseValue = 0.0f;
  645.         SStimulusInvocation::TPulseTriggersContainer::const_iterator itPulse = invoke.m_pulseTriggers.begin();
  646.         SStimulusInvocation::TPulseTriggersContainer::const_iterator itPulseEnd = invoke.m_pulseTriggers.end();
  647.         for (; itPulse != itPulseEnd; ++itPulse)
  648.         {
  649.                 const SStimulusInvocation::SPulseTrigger& pulseTrigger = *itPulse;
  650.  
  651.                 TargetTrackHelpers::STargetTrackStimulusConfig::TPulseContainer::const_iterator itPulseDef = pStimulusConfig->m_pulses.find(pulseTrigger.uPulseNameHash);
  652.                 if (itPulseDef != pStimulusConfig->m_pulses.end())
  653.                 {
  654.                         const TargetTrackHelpers::STargetTrackPulseConfig& pulseDef = itPulseDef->second;
  655.  
  656.                         const float fDT = fCurrTime - pulseTrigger.fTriggerTime;
  657.                         const float fRatio = clamp_tpl((pulseDef.m_fDuration > FLT_EPSILON ? 1.0f - fDT / pulseDef.m_fDuration : 0.0f), 0.0f, 1.0f);
  658.                         fPulseValue += pulseDef.m_fValue * fRatio;
  659.  
  660.                         if (fRatio <= 0.0f)
  661.                         {
  662.                                 pulseTrigger.bObsolete = true;
  663.                         }
  664.                 }
  665.         }
  666.  
  667.         return fPulseValue;
  668. }
  669.  
  670. //////////////////////////////////////////////////////////////////////////
  671. float CTargetTrack::GetStimulusModifierValue(const SStimulusInvocation& invoke, TargetTrackHelpers::ITargetTrackConfigProxy* pConfigProxy, const TargetTrackHelpers::STargetTrackStimulusConfig* pStimulusConfig) const
  672. {
  673.         FUNCTION_PROFILER(GetISystem(), PROFILE_AI);
  674.  
  675.         assert(pStimulusConfig);
  676.         assert(pConfigProxy);
  677.  
  678.         // Value is used as a product
  679.         float fModValue = 1.0f;
  680.  
  681.         TargetTrackHelpers::STargetTrackStimulusConfig::TModifierContainer::const_iterator itMod = pStimulusConfig->m_modifiers.begin();
  682.         TargetTrackHelpers::STargetTrackStimulusConfig::TModifierContainer::const_iterator itModEnd = pStimulusConfig->m_modifiers.end();
  683.         for (; itMod != itModEnd; ++itMod)
  684.         {
  685.                 const TargetTrackHelpers::STargetTrackModifierConfig& modifierInfo = itMod->second;
  686.                 const ITargetTrackModifier* pModifier = pConfigProxy->GetTargetTrackModifier(modifierInfo.m_uId);
  687.  
  688.                 if (pModifier)
  689.                 {
  690.                         fModValue *= pModifier->GetModValue(this, invoke.m_eStimulusType, invoke.m_vLastPos,
  691.                                                             invoke.m_envelopeData, modifierInfo);
  692.                 }
  693.         }
  694.  
  695.         return fModValue;
  696. }
  697.  
  698. #ifdef TARGET_TRACK_DEBUG
  699. //////////////////////////////////////////////////////////////////////////
  700. void CTargetTrack::DebugDraw(CDebugDrawContext& dc, int iIndex, float& fColumnX, float& fColumnY, TargetTrackHelpers::ITargetTrackConfigProxy* pConfigProxy) const
  701. {
  702.         CAIObject* pObject = m_object.GetAIObject();
  703.         CAISystem* pAISystem = GetAISystem();
  704.         assert(pAISystem);
  705.  
  706.         const float fCurrTime = pAISystem->GetFrameStartTimeSeconds();
  707.  
  708.         const ColorB textCol(255, 255, 255, 255);
  709.         const ColorB textActiveCol(0, 128, 0, 255);
  710.  
  711.         dc->Draw2dLabel(fColumnX, fColumnY, 1.5f, iIndex > 0 ? textCol : textActiveCol, false, "Track \'%s\' [%.3f - %d]", pObject ? pObject->GetName() : "(Null)", m_fTrackValue, iIndex + 1);
  712.  
  713.         TStimuliInvocationContainer::const_iterator itStimulusInvoke = m_StimuliInvocations.begin();
  714.         TStimuliInvocationContainer::const_iterator itStimulusInvokeEnd = m_StimuliInvocations.end();
  715.         for (; itStimulusInvoke != itStimulusInvokeEnd; ++itStimulusInvoke)
  716.         {
  717.                 fColumnY += 15.0f;
  718.  
  719.                 const uint32 uStimulusHash = itStimulusInvoke->first;
  720.                 const SStimulusInvocation& invoke = itStimulusInvoke->second;
  721.                 string sStimulusName = "Unknown";
  722.                 float fStimulusValue = 0.0f;
  723.                 float fEnvelopeValue = 0.0f;
  724.                 float fPulseValue = 0.0f;
  725.                 float fModValue = 1.0f;
  726.  
  727.                 const TargetTrackHelpers::STargetTrackStimulusConfig* pStimulusConfig = NULL;
  728.                 if (pConfigProxy->GetTargetTrackStimulusConfig(m_uConfigHash, uStimulusHash, pStimulusConfig))
  729.                 {
  730.                         sStimulusName = pStimulusConfig->m_sStimulus;
  731.                         fEnvelopeValue = GetStimulusEnvelopeValue(fCurrTime, invoke, pStimulusConfig);
  732.                         fPulseValue = GetStimulusPulseValue(fCurrTime, invoke, pStimulusConfig);
  733.                         fModValue = GetStimulusModifierValue(invoke, pConfigProxy, pStimulusConfig);
  734.                         fStimulusValue = GetStimulusTotalValue(fCurrTime, fEnvelopeValue, fPulseValue, fModValue);
  735.                 }
  736.  
  737.                 dc->Draw2dLabel(fColumnX + 5.0f, fColumnY, 1.2f, textCol, false, "Stimulus \'%s\' @ [%.3f : E = %.3f : P = %.3f : M = %.3f]", sStimulusName.c_str(), fStimulusValue, fEnvelopeValue, fPulseValue, fModValue);
  738.                 fColumnY += 15.0f;
  739.  
  740.                 dc->Draw2dLabel(fColumnX + 10.0f, fColumnY, 1.0f, textCol, false, "Running: %d (P = %" PRISIZE_T ")", invoke.IsRunning(GetUpdateInterval()) ? 1 : 0, invoke.m_pulseTriggers.size());
  741.                 dc->Draw2dLabel(fColumnX + 150.0f, fColumnY, 1.0f, textCol, false, "Start: %.3f", invoke.m_envelopeData.m_fStartTime);
  742.                 dc->Draw2dLabel(fColumnX + 220.0f, fColumnY, 1.0f, textCol, false, "Last: %.3f", invoke.m_envelopeData.m_fLastInvokeTime);
  743.         }
  744. }
  745. #endif //TARGET_TRACK_DEBUG
  746.  
downloadTargetTrack.cpp Source code - Download CRYENGINE Source code
Related Source Codes/Software:
postal - 2017-06-11
reactide - Reactide is the first dedicated IDE for React web ... 2017-06-11
rkt - rkt is a pod-native container engine for Linux. It... 2017-06-11
uWebSockets - Tiny WebSockets https://for... 2017-06-11
realworld - TodoMVC for the RealWorld - Exemplary fullstack Me... 2017-06-11
CRYENGINE - CRYENGINE is a powerful real-time game development... 2017-06-11
goreplay - GoReplay is an open-source tool for capturing and ... 2017-06-10
pyenv - Simple Python version management 2017-06-10
redux-saga - An alternative side effect model for Redux apps ... 2017-06-10
angular-starter - 2017-06-10

 Back to top