BVB Source Codes

CRYENGINE Show DebugDraw.cpp Source code

Return Download CRYENGINE: download DebugDraw.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:   DebugDraw.cpp
  6.    $Id$
  7.    Description: move all the debug drawing functionality from AISystem. Need to clean it up eventually and
  8.    make nice debug output functions, instead of one huge.
  9.  
  10.    -------------------------------------------------------------------------
  11.    History:
  12.    - 29:11:2004   19:02 : Created by Kirill Bulatsev
  13.  
  14.  *********************************************************************/
  15.  
  16. #include "StdAfx.h"
  17.  
  18. #ifdef CRYAISYSTEM_DEBUG
  19.  
  20. // AI includes
  21.         #include "CAISystem.h"
  22.         #include "DebugDrawContext.h"
  23.         #include "AILog.h"
  24.  
  25.         #include "Graph.h"
  26.         #include "Puppet.h"
  27.         #include "AIVehicle.h"
  28.         #include "GoalPipe.h"
  29.         #include "GoalOp.h"
  30.         #include "AIPlayer.h"
  31.         #include "PipeUser.h"
  32.         #include "Leader.h"
  33.         #include "NavRegion.h"
  34.         #include "SmartObjects.h"
  35.         #include "PathFollower.h"
  36.         #include "Shape.h"
  37.         #include "CodeCoverageGUI.h"
  38.         #include "StatsManager.h"
  39.         #include "PerceptionManager.h"
  40.         #include "FireCommand.h"
  41.  
  42. // (MATT) TODO Get a lightweight DebugDraw interface rather than pulling in this header file {2008/12/04}
  43.         #include "TacticalPointSystem/TacticalPointSystem.h"
  44.         #include "TargetSelection/TargetTrackManager.h"
  45.         #include "Communication/CommunicationManager.h"
  46.         #include "Cover/CoverSystem.h"
  47.         #include "Navigation/NavigationSystem/NavigationSystem.h"
  48.         #include "SelectionTree/SelectionTree.h"
  49.         #include "CollisionAvoidance/CollisionAvoidanceSystem.h"
  50.         #include "Group/GroupManager.h"
  51.         #include "CentralInterestManager.h"
  52.         #include "PersonalInterestManager.h"
  53.         #include "BehaviorTree/BehaviorTreeManager.h"
  54.  
  55.         #include <CryAISystem/IAIBubblesSystem.h>
  56.  
  57.         #pragma warning(disable: 4244)
  58.  
  59.         #define whiteTrans ColorB(255, 255, 255, 179)
  60.         #define redTrans   ColorB(255, 0, 0, 179)
  61.  
  62. void CAISystem::DebugDrawRecorderRange() const
  63. {
  64.         FUNCTION_PROFILER(GetISystem(), PROFILE_AI);
  65.  
  66.         const float fRecorderDrawStart = m_recorderDebugContext.fStartPos;
  67.         const float fRecorderDrawEnd = m_recorderDebugContext.fEndPos;
  68.         const float fRecorderDrawCursor = m_recorderDebugContext.fCursorPos;
  69.  
  70.         const bool bTimelineValid = (fabsf(fRecorderDrawEnd - fRecorderDrawStart) > FLT_EPSILON);
  71.         const bool bCursorValid = bTimelineValid ? (fRecorderDrawCursor >= fRecorderDrawStart && fRecorderDrawCursor <= fRecorderDrawEnd) : (fRecorderDrawCursor > FLT_EPSILON);
  72.  
  73.         const ColorB colGray(128, 128, 128, 255);
  74.  
  75.         CDebugDrawContext dc;
  76.  
  77.         // Debug all of the objects
  78.         TDebugObjectsArray::const_iterator itObject = m_recorderDebugContext.DebugObjects.begin();
  79.         TDebugObjectsArray::const_iterator itObjectEnd = m_recorderDebugContext.DebugObjects.end();
  80.         for (; itObject != itObjectEnd; ++itObject)
  81.         {
  82.                 const SAIRecorderObjectDebugContext& objectContext = *itObject;
  83.                 if (false == objectContext.bEnableDrawing)
  84.                         continue;
  85.  
  86.                 CAIObject* pAIObject = gAIEnv.pAIObjectManager->GetAIObjectByName(objectContext.sName.c_str());
  87.                 if (!pAIObject)
  88.                         continue;
  89.  
  90.                 IAIDebugRecord* pRecord = pAIObject->GetAIDebugRecord();
  91.                 if (!pRecord)
  92.                         continue;
  93.  
  94.                 IAIDebugStream* pPosStream = pRecord->GetStream(IAIRecordable::E_AGENTPOS);
  95.                 IAIDebugStream* pDirStream = pRecord->GetStream(IAIRecordable::E_AGENTDIR);
  96.                 if (!pPosStream || !pDirStream)
  97.                         continue;
  98.  
  99.                 const ColorB colDebug = objectContext.color;
  100.                 float fCurrPosTime = 0.0f;
  101.                 float fCurrDirTime = 0.0f;
  102.                 Vec3* pPos = NULL;
  103.                 Vec3* pDir = NULL;
  104.  
  105.                 // Draw range
  106.                 if (bTimelineValid && fRecorderDrawStart < pPosStream->GetEndTime() && fRecorderDrawEnd > pPosStream->GetStartTime())
  107.                 {
  108.                         pPosStream->Seek(fRecorderDrawStart);
  109.                         pDirStream->Seek(fRecorderDrawStart);
  110.                         pPos = (Vec3*)(pPosStream->GetCurrent(fCurrPosTime));
  111.                         pDir = (Vec3*)(pDirStream->GetCurrent(fCurrDirTime));
  112.  
  113.                         // Draw start cursor pos
  114.                         if (pPos)
  115.                         {
  116.                                 const Vec3& vPos(*pPos);
  117.                                 dc->DrawSphere(vPos, 0.25f, colGray);
  118.  
  119.                                 if (pDir)
  120.                                 {
  121.                                         const Vec3& vDir(*pDir);
  122.                                         dc->DrawArrow(vPos, vDir, 0.25f, colGray);
  123.                                 }
  124.  
  125.                                 dc->DrawCone(vPos + Vec3(0, 0, 5), Vec3(0, 0, -1), 0.5f, 4.0f, colGray);
  126.                                 dc->Draw3dLabel(vPos + Vec3(0, 0, 0.8f), 1.0f, "%s START\n%.1fs", pAIObject->GetName(), fCurrPosTime);
  127.                         }
  128.  
  129.                         int j = 0;
  130.                         while (fCurrPosTime <= fRecorderDrawEnd && pPosStream->GetCurrentIdx() < pPosStream->GetSize())
  131.                         {
  132.                                 float fNextPosTime = 0.0f;
  133.                                 float fNextDirTime = 0.0f;
  134.                                 Vec3* pNextPos = (Vec3*)(pPosStream->GetNext(fNextPosTime));
  135.                                 pDirStream->Seek(fNextPosTime);
  136.                                 Vec3* pNextDir = (Vec3*)(pDirStream->GetNext(fNextDirTime));
  137.                                 if (pPos && pNextPos)
  138.                                 {
  139.                                         const Vec3& vPos(*pPos);
  140.                                         const Vec3& vNext(*pNextPos);
  141.                                         const Vec3& vNextDir = (pNextDir ? *pNextDir : Vec3Constants<float>::fVec3_Zero);
  142.  
  143.                                         if ((j & 1) == 0)
  144.                                         {
  145.                                                 dc->DrawLine(vPos, colDebug, vNext, colDebug);
  146.                                                 if (!vNextDir.IsZero())
  147.                                                         dc->DrawArrow(vNext, vNextDir, 0.25f, colDebug);
  148.                                         }
  149.                                         else
  150.                                         {
  151.                                                 dc->DrawLine(vPos, colGray, vNext, colGray);
  152.                                                 if (!vNextDir.IsZero())
  153.                                                         dc->DrawArrow(vNext, vNextDir, 0.25f, colGray);
  154.                                         }
  155.                                 }
  156.  
  157.                                 fCurrPosTime = fNextPosTime;
  158.                                 pPos = pNextPos;
  159.                                 ++j;
  160.                         }
  161.  
  162.                         // Draw start end pos
  163.                         pPosStream->Seek(fRecorderDrawEnd);
  164.                         pDirStream->Seek(fRecorderDrawEnd);
  165.                         pPos = (Vec3*)(pPosStream->GetCurrent(fCurrPosTime));
  166.                         pDir = (Vec3*)(pDirStream->GetCurrent(fCurrDirTime));
  167.                         if (pPos)
  168.                         {
  169.                                 const Vec3& vPos(*pPos);
  170.                                 dc->DrawSphere(vPos, 0.25f, colGray);
  171.  
  172.                                 if (pDir)
  173.                                 {
  174.                                         const Vec3& vDir(*pDir);
  175.                                         dc->DrawArrow(vPos, vDir, 0.25f, colGray);
  176.                                 }
  177.  
  178.                                 dc->DrawCone(vPos + Vec3(0, 0, 5), Vec3(0, 0, -1), 0.5f, 4.0f, colGray);
  179.                                 dc->Draw3dLabel(vPos + Vec3(0, 0, 0.8f), 1.0f, "%s END\n%.1fs", pAIObject->GetName(), fCurrPosTime);
  180.                         }
  181.                 }
  182.  
  183.                 // Draw cursor current pos
  184.                 if (bCursorValid)
  185.                 {
  186.                         Vec3 vCurrPos;
  187.  
  188.                         pPosStream->Seek(fRecorderDrawCursor);
  189.                         pDirStream->Seek(fRecorderDrawCursor);
  190.                         pPos = (Vec3*)(pPosStream->GetCurrent(fCurrPosTime));
  191.                         pDir = (Vec3*)(pDirStream->GetCurrent(fCurrDirTime));
  192.                         if (pPos)
  193.                         {
  194.                                 const Vec3& vDir = (pDir ? *pDir : Vec3Constants<float>::fVec3_OneZ);
  195.  
  196.                                 // Create label text that depicts everything that happened at this moment from all streams
  197.                                 string sCursorText;
  198.                                 sCursorText.Format("%s CURRENT\n%.1fs", pAIObject->GetName(), fCurrPosTime);
  199.  
  200.                                 for (int i = IAIRecordable::E_NONE; i < IAIRecordable::E_COUNT; ++i)
  201.                                 {
  202.                                         IAIDebugStream* pEventStream = pRecord->GetStream((IAIRecordable::e_AIDbgEvent)i);
  203.                                         if (!pEventStream)
  204.                                                 continue;
  205.  
  206.                                         string sShortLabel, sText;
  207.                                         pEventStream->Seek(fRecorderDrawCursor);
  208.                                         if (pEventStream->GetCurrentString(sShortLabel, fCurrPosTime) &&
  209.                                             fabsf(fCurrPosTime - fRecorderDrawCursor) <= 0.1f)
  210.                                         {
  211.                                                 sText.Format("\n%s: %s", pEventStream->GetName(), sShortLabel.c_str());
  212.                                                 sCursorText += sText;
  213.                                         }
  214.                                 }
  215.  
  216.                                 vCurrPos = *pPos;
  217.                                 dc->DrawSphere(vCurrPos, 0.25f, colDebug);
  218.                                 dc->DrawCone(vCurrPos + Vec3(0, 0, 5), Vec3(0, 0, -1), 0.5f, 4.0f, colDebug);
  219.                                 dc->Draw3dLabel(vCurrPos + Vec3(0, 0, 0.8f), 1.0f, "%s", sCursorText.c_str());
  220.                         }
  221.  
  222.                         // Current attention target info
  223.                         IAIDebugStream* pAttTargetPosStream = pRecord->GetStream(IAIRecordable::E_ATTENTIONTARGETPOS);
  224.                         if (pAttTargetPosStream)
  225.                         {
  226.                                 pAttTargetPosStream->Seek(fRecorderDrawCursor);
  227.                                 Vec3* pAttTargetPos = (Vec3*)(pAttTargetPosStream->GetCurrent(fCurrPosTime));
  228.                                 if (pAttTargetPos)
  229.                                 {
  230.                                         string sName = "Att Target: ";
  231.  
  232.                                         IAIDebugStream* pAttTargetStream = pRecord->GetStream(IAIRecordable::E_ATTENTIONTARGET);
  233.                                         if (pAttTargetStream)
  234.                                         {
  235.                                                 pAttTargetStream->Seek(fRecorderDrawCursor);
  236.                                                 sName += (const char*)(pAttTargetStream->GetCurrent(fCurrPosTime));
  237.                                         }
  238.                                         else
  239.                                         {
  240.                                                 sName += "Unknown";
  241.                                         }
  242.  
  243.                                         Vec3 vPos(*pAttTargetPos);
  244.                                         ColorB colAttTargetDebug = colDebug;
  245.                                         colAttTargetDebug.a /= 2;
  246.                                         dc->DrawSphere(vPos, 0.25f, colAttTargetDebug);
  247.                                         dc->DrawCone(vPos + Vec3(0, 0, 5), Vec3(0, 0, -1), 0.5f, 4.0f, colAttTargetDebug);
  248.                                         dc->DrawLine(vCurrPos, colDebug, vPos, colAttTargetDebug);
  249.                                         dc->Draw3dLabel(vPos + Vec3(0, 0, 0.8f), 1.0f, "%s", sName.c_str());
  250.                                 }
  251.                         }
  252.                 }
  253.         }
  254. }
  255.  
  256. //
  257. //-----------------------------------------------------------------------------------------------------------
  258. void CAISystem::DebugDrawDamageControlGraph() const
  259. {
  260.         FUNCTION_PROFILER(GetISystem(), PROFILE_AI);
  261.  
  262.         CDebugDrawContext dc;
  263.         Vec3 camPos = dc->GetCameraPos();
  264.  
  265.         static std::vector<CPuppet*> shooters;
  266.         shooters.clear();
  267.  
  268.         AIActorSet::const_iterator it = m_enabledAIActorsSet.begin();
  269.         AIActorSet::const_iterator itEnd = m_enabledAIActorsSet.end();
  270.         for (; it != itEnd; ++it)
  271.         {
  272.                 CAIActor* pAIActor = it->GetAIObject();
  273.                 if (!pAIActor)
  274.                         continue;
  275.  
  276.                 CPuppet* pPuppet = pAIActor->CastToCPuppet();
  277.                 if (!pPuppet)
  278.                         continue;
  279.  
  280.                 if (pPuppet->CastToCAIVehicle())
  281.                         continue;
  282.  
  283.                 if (!pPuppet->m_targetDamageHealthThrHistory)
  284.                         continue;
  285.  
  286.                 if (Distance::Point_PointSq(camPos, pPuppet->GetPos()) > sqr(150.f))
  287.                         continue;
  288.  
  289.                 shooters.push_back(pPuppet);
  290.         }
  291.  
  292.         if (shooters.empty())
  293.                 return;
  294.  
  295.         dc->Init2DMode();
  296.         dc->SetAlphaBlended(true);
  297.         dc->SetBackFaceCulling(false);
  298.  
  299.         const Vec3 u(1, 0, 0);
  300.         const Vec3 v(0, -1, 0);
  301.         const Vec3 w(0, 0, 1);
  302.  
  303.         static std::vector<Vec3> values;
  304.  
  305.         if (gAIEnv.CVars.DebugDrawDamageControl > 2)
  306.         {
  307.                 // Combined graph
  308.                 static std::vector<CAIActor*> targets;
  309.                 targets.clear();
  310.                 for (unsigned int i = 0; i < shooters.size(); ++i)
  311.                 {
  312.                         CPuppet* pPuppet = shooters[i];
  313.                         if (pPuppet->GetAttentionTarget())
  314.                         {
  315.                                 CAIActor* pTargetActor = 0;
  316.                                 CAIObject* pTarget = (CAIObject*)pPuppet->GetAttentionTarget();
  317.                                 assert(pTarget);
  318.                                 if (pTarget->IsAgent())
  319.                                         pTargetActor = pTarget->CastToCAIActor();
  320.                                 else
  321.                                 {
  322.                                         CAIActor* pActor = CastToCAIActorSafe(pTarget->GetAssociation().GetAIObject());
  323.                                         if (pActor && pActor->IsAgent())
  324.                                                 pTargetActor = pActor;
  325.                                 }
  326.                                 if (pTargetActor)
  327.                                 {
  328.                                         for (unsigned int j = 0; j < targets.size(); ++j)
  329.                                         {
  330.                                                 if (pTargetActor == targets[j])
  331.                                                 {
  332.                                                         pTargetActor = 0;
  333.                                                         break;
  334.                                                 }
  335.                                         }
  336.                                         if (pTargetActor)
  337.                                                 targets.push_back(pTargetActor);
  338.                                 }
  339.                         }
  340.                 }
  341.  
  342.                 const Vec3 u2(1, 0, 0);
  343.                 const Vec3 v2(0, -1, 0);
  344.                 const Vec3 w2(0, 0, 1);
  345.  
  346.                 const float sizex = 0.7f;
  347.                 const float sizey = 0.2f;
  348.  
  349.                 Vec3 orig = Vec3(0.15f, 1 - 0.05f, 0);
  350.  
  351.                 // dim BG
  352.                 ColorB bg1(0, 0, 0, 128);
  353.                 ColorB bg2(128, 128, 128, 64);
  354.                 dc->DrawTriangle(orig, bg1, orig + u2 * sizex, bg1, orig + u2 * sizex + v2 * sizey, bg2);
  355.                 dc->DrawTriangle(orig, bg1, orig + u2 * sizex + v2 * sizey, bg2, orig + v2 * sizey, bg2);
  356.  
  357.         #ifdef CRYAISYSTEM_DEBUG
  358.                 CValueHistory<float>* history = 0;
  359.  
  360.                 float timeLen = 1.0f;
  361.                 float maxVal = 1.0f;
  362.                 for (unsigned int i = 0; i < targets.size(); ++i)
  363.                 {
  364.                         if (!targets[i]->m_healthHistory) continue;
  365.  
  366.                         float maxHealth = (float)targets[i]->GetProxy()->GetActorMaxHealth();
  367.                         float maxHealthArmor = (float)(targets[i]->GetProxy()->GetActorMaxHealth() + targets[i]->GetProxy()->GetActorMaxArmor());
  368.                         maxVal = max(maxVal, maxHealthArmor / maxHealth);
  369.  
  370.                         timeLen = max(timeLen, (float)(targets[i]->m_healthHistory->GetMaxSampleCount() *
  371.                                                        targets[i]->m_healthHistory->GetSampleInterval()));
  372.                 }
  373.  
  374.                 // Draw value lines
  375.                 dc->DrawLine(orig, ColorB(255, 255, 255, 128), orig + u2 * sizex, ColorB(255, 255, 255, 128));
  376.                 dc->DrawLine(orig + v2 * sizey * (0.5f / maxVal), ColorB(255, 255, 255, 64), orig + u2 * sizex + v2 * sizey * (0.5f / maxVal), ColorB(255, 255, 255, 64));
  377.                 dc->DrawLine(orig + v2 * sizey * (1.0f / maxVal), ColorB(255, 255, 255, 128), orig + u2 * sizex + v2 * sizey * (1.0f / maxVal), ColorB(255, 255, 255, 128));
  378.  
  379.                 // Draw time lines
  380.                 const float tickInterval = 1.0f; //seconds
  381.                 unsigned int tickCount = (unsigned int)floor(timeLen / tickInterval);
  382.                 for (unsigned int j = 0; j < tickCount; ++j)
  383.                 {
  384.                         float t = ((j * tickInterval) / timeLen) * sizex;
  385.                         dc->DrawLine(orig + t * u2, ColorB(255, 255, 255, 64), orig + t * u2 + v2 * sizey, ColorB(255, 255, 255, 64));
  386.                 }
  387.  
  388.                 const float s = 1.0f / maxVal;
  389.  
  390.                 // Draw targets
  391.                 for (unsigned int i = 0; i < targets.size(); ++i)
  392.                 {
  393.                         history = targets[i]->m_healthHistory;
  394.                         if (history)
  395.                         {
  396.                                 unsigned int n = history->GetSampleCount();
  397.                                 values.resize(n);
  398.                                 float dt = history->GetSampleInterval();
  399.  
  400.                                 for (unsigned int j = 0; j < n; ++j)
  401.                                 {
  402.                                         float val = min(history->GetSample(j) * s, 1.0f) * sizey;
  403.                                         float t = ((timeLen - j * dt) / timeLen) * sizex;
  404.                                         values[j] = orig + t * u2 + v2 * val;
  405.                                 }
  406.                                 if (n > 0)
  407.                                         dc->DrawPolyline(&values[0], n, false, ColorB(255, 255, 255, 160), 1.5f);
  408.                         }
  409.                 }
  410.  
  411.                 // Draw shooters
  412.                 for (unsigned int i = 0; i < shooters.size(); ++i)
  413.                 {
  414.                         history = shooters[i]->m_targetDamageHealthThrHistory;
  415.                         if (history)
  416.                         {
  417.                                 unsigned int n = history->GetSampleCount();
  418.                                 values.resize(n);
  419.                                 float dt = history->GetSampleInterval();
  420.                                 for (unsigned int j = 0; j < n; ++j)
  421.                                 {
  422.                                         float val = min(history->GetSample(j) * s, 1.0f) * sizey;
  423.                                         float t = ((timeLen - j * dt) / timeLen) * sizex;
  424.                                         values[j] = orig + t * u2 + v2 * val;
  425.                                 }
  426.                                 if (n > 0)
  427.                                         dc->DrawPolyline(&values[0], n, false, ColorB(240, 32, 16, 240));
  428.                         }
  429.                 }
  430.         #endif // ifdef _DEBUG
  431.         }
  432.         else
  433.         {
  434.                 // Separate graphs
  435.                 const float spacingy = min(0.9f / (shooters.size() + 1.f), 0.2f);
  436.                 const float sizex = 0.25f;
  437.                 const float sizey = spacingy * 0.95f;
  438.  
  439.                 int sw = dc->GetWidth();
  440.                 int sh = dc->GetHeight();
  441.  
  442.                 const ColorB white(0, 192, 255);
  443.  
  444.                 for (unsigned int i = 0; i < shooters.size(); ++i)
  445.                 {
  446.                         CPuppet* pPuppet = shooters[i];
  447.                         Vec3 orig = Vec3(0.05f, 0.05f + (i + 1) * spacingy, 0);
  448.  
  449.                         // dim BG
  450.                         ColorB bg1(0, 0, 0, 128);
  451.                         ColorB bg2(128, 128, 128, 64);
  452.                         dc->DrawTriangle(orig, bg1, orig + u * sizex, bg1, orig + u * sizex + v * sizey, bg2);
  453.                         dc->DrawTriangle(orig, bg1, orig + u * sizex + v * sizey, bg2, orig + v * sizey, bg2);
  454.  
  455.         #ifdef CRYAISYSTEM_DEBUG
  456.                         // Draw time lines
  457.                         float timeLen = pPuppet->m_targetDamageHealthThrHistory->GetMaxSampleCount() *
  458.                                         pPuppet->m_targetDamageHealthThrHistory->GetSampleInterval();
  459.                         const float tickInterval = 1.0f; //seconds
  460.                         unsigned int tickCount = (unsigned int)floor(timeLen / tickInterval);
  461.                         for (unsigned int j = 0; j < tickCount; ++j)
  462.                         {
  463.                                 float t = ((j * tickInterval) / timeLen) * sizex;
  464.                                 dc->DrawLine(orig + t * u, ColorB(255, 255, 255, 64), orig + t * u + v * sizey, ColorB(255, 255, 255, 64));
  465.                         }
  466.  
  467.                         // Draw curve
  468.                         CValueHistory<float>* history = 0;
  469.  
  470.                         float s = 1.0f;
  471.  
  472.                         if (pPuppet->GetAttentionTarget())
  473.                         {
  474.                                 CAIActor* pTargetActor = 0;
  475.                                 CAIObject* pTarget = (CAIObject*)pPuppet->GetAttentionTarget();
  476.                                 assert(pTarget);
  477.                                 if (pTarget->IsAgent())
  478.                                         pTargetActor = pTarget->CastToCAIActor();
  479.                                 else
  480.                                 {
  481.                                         CAIActor* pActor = CastToCAIActorSafe(pTarget->GetAssociation().GetAIObject());
  482.                                         if (pActor && pActor->IsAgent())
  483.                                                 pTargetActor = pActor;
  484.                                 }
  485.  
  486.                                 if (pTargetActor)
  487.                                 {
  488.                                         history = pTargetActor->m_healthHistory;
  489.                                         if (history)
  490.                                         {
  491.                                                 float maxHealth = (float)pTargetActor->GetProxy()->GetActorMaxHealth();
  492.                                                 float maxHealthArmor = (float)(pTargetActor->GetProxy()->GetActorMaxHealth() + pTargetActor->GetProxy()->GetActorMaxArmor());
  493.                                                 float maxVal = maxHealthArmor / maxHealth;
  494.  
  495.                                                 s = 1.0f / maxVal;
  496.  
  497.                                                 // Draw value lines
  498.                                                 dc->DrawLine(orig, ColorB(255, 255, 255, 128), orig + u * sizex, ColorB(255, 255, 255, 128));
  499.                                                 dc->DrawLine(orig + v * sizey * 0.5f * s, ColorB(255, 255, 255, 64), orig + u * sizex + v * sizey * 0.5f * s, ColorB(255, 255, 255, 64));
  500.                                                 dc->DrawLine(orig + v * sizey * s, ColorB(255, 255, 255, 128), orig + u * sizex + v * sizey * s, ColorB(255, 255, 255, 128));
  501.  
  502.                                                 unsigned int n = history->GetSampleCount();
  503.                                                 values.resize(n);
  504.                                                 float dt = history->GetSampleInterval();
  505.                                                 for (unsigned int j = 0; j < n; ++j)
  506.                                                 {
  507.                                                         float val = min(history->GetSample(j) * s, 1.0f) * sizey;
  508.                                                         float t = ((timeLen - j * dt) / timeLen) * sizex;
  509.                                                         values[j] = orig + t * u + v * val;
  510.                                                 }
  511.                                                 if (n > 0)
  512.                                                         dc->DrawPolyline(&values[0], n, false, ColorB(255, 255, 255, 160), 1.5f);
  513.                                         }
  514.                                 }
  515.                         }
  516.                         else
  517.                         {
  518.                                 float maxVal = max(1.0f, pPuppet->m_targetDamageHealthThrHistory->GetMaxSampleValue());
  519.                                 s = 1.0f / maxVal;
  520.                         }
  521.  
  522.                         history = pPuppet->m_targetDamageHealthThrHistory;
  523.                         if (history)
  524.                         {
  525.                                 unsigned int n = history->GetSampleCount();
  526.                                 values.resize(n);
  527.                                 float dt = history->GetSampleInterval();
  528.                                 for (unsigned int j = 0; j < n; ++j)
  529.                                 {
  530.                                         float val = min(history->GetSample(j) * s, 1.0f) * sizey;
  531.                                         float t = ((timeLen - j * dt) / timeLen) * sizex;
  532.                                         values[j] = orig + t * u + v * val;
  533.                                 }
  534.                                 if (n > 0)
  535.                                         dc->DrawPolyline(&values[0], n, false, ColorB(240, 32, 16, 240));
  536.                         }
  537.         #endif
  538.  
  539.                         char* szZone = "";
  540.                         switch (pPuppet->m_targetZone)
  541.                         {
  542.                         case AIZONE_OUT:
  543.                                 szZone = "Out";
  544.                                 break;
  545.                         case AIZONE_WARN:
  546.                                 szZone = "Warn";
  547.                                 break;
  548.                         case AIZONE_COMBAT_NEAR:
  549.                                 szZone = "Combat-Near";
  550.                                 break;
  551.                         case AIZONE_COMBAT_FAR:
  552.                                 szZone = "Combat-Far";
  553.                                 break;
  554.                         case AIZONE_KILL:
  555.                                 szZone = "Kill";
  556.                                 break;
  557.                         case AIZONE_IGNORE:
  558.                                 szZone = "Ignored";
  559.                                 break;
  560.                         }
  561.  
  562.                         // Shooter name
  563.                         dc->Draw2dLabel(orig.x * sw + 3, (orig.y - spacingy + sizey) * sh - 25, 1.2f, white, false, "%s", pPuppet->GetName());
  564.  
  565.                         float aliveTime = pPuppet->GetTargetAliveTime();
  566.                         const float accuracy = pPuppet->GetParameters().m_fAccuracy;
  567.                         char szAlive[32] = "inf";
  568.                         if (accuracy > 0.001f)
  569.                                 cry_sprintf(szAlive, "%.1fs", aliveTime / accuracy);
  570.  
  571.                         IAIObject* pAttTarget = pPuppet->GetAttentionTarget();
  572.                         const float fFireReactionTime = (pAttTarget ? pPuppet->GetFiringReactionTime(pAttTarget->GetPos()) : 0.0f);
  573.                         const float fCurrentReactionTime = pPuppet->GetCurrentFiringReactionTime();
  574.                         const bool bFireReactionPassed = pPuppet->HasFiringReactionTimePassed();
  575.  
  576.                         dc->Draw2dLabel(orig.x * sw + 3, (orig.y - spacingy + sizey) * sh - 10, 1.1f, (bFireReactionPassed ? whiteTrans : redTrans), false, "Thr: %.2f Alive: %s  React: %.1f / %.1f  Acc: %.3f  Zone: %s  %s",
  577.                                         pPuppet->m_targetDamageHealthThr, szAlive, max(fFireReactionTime - fCurrentReactionTime, 0.0f), fFireReactionTime,
  578.                                         accuracy, szZone, pPuppet->IsAllowedToHitTarget() ? "FIRE" : "");
  579.                 }
  580.         }
  581.  
  582. }
  583.  
  584. void CAISystem::DrawDebugShape(const SDebugSphere& sphere)
  585. {
  586.         FUNCTION_PROFILER(GetISystem(), PROFILE_AI);
  587.  
  588.         CDebugDrawContext dc;
  589.         dc->DrawSphere(sphere.pos, sphere.radius, sphere.color);
  590. }
  591.  
  592. void CAISystem::DrawDebugShape(const SDebugBox& box)
  593. {
  594.         FUNCTION_PROFILER(GetISystem(), PROFILE_AI);
  595.  
  596.         CDebugDrawContext dc;
  597.         dc->DrawOBB(box.obb, box.pos, true, box.color, eBBD_Faceted);
  598. }
  599.  
  600. void CAISystem::DrawDebugShape(const SDebugLine& line)
  601. {
  602.         FUNCTION_PROFILER(GetISystem(), PROFILE_AI);
  603.  
  604.         CDebugDrawContext dc;
  605.         dc->DrawLine(line.start, line.color, line.end, line.color, line.thickness);
  606. }
  607.  
  608. void CAISystem::DrawDebugShape(const SDebugCylinder& cylinder)
  609. {
  610.         FUNCTION_PROFILER(GetISystem(), PROFILE_AI);
  611.  
  612.         CDebugDrawContext dc;
  613.         dc->DrawCylinder(cylinder.pos, cylinder.dir, cylinder.radius, cylinder.height, cylinder.color);
  614. }
  615.  
  616. void CAISystem::DrawDebugShape(const SDebugCone& cone)
  617. {
  618.         FUNCTION_PROFILER(GetISystem(), PROFILE_AI);
  619.  
  620.         CDebugDrawContext dc;
  621.         dc->DrawCone(cone.pos, cone.dir, cone.radius, cone.height, cone.color);
  622. }
  623.  
  624. template<typename ShapeContainer>
  625. void CAISystem::DrawDebugShapes(ShapeContainer& shapes, float dt)
  626. {
  627.         FUNCTION_PROFILER(GetISystem(), PROFILE_AI);
  628.  
  629.         for (unsigned int i = 0; i < shapes.size(); )
  630.         {
  631.                 typename ShapeContainer::value_type& shape = shapes[i];
  632.                 // NOTE Mai 29, 2007: <pvl> draw it at least once
  633.                 DrawDebugShape(shape);
  634.  
  635.                 shape.time -= dt;
  636.                 if (shape.time < 0)
  637.                 {
  638.                         shapes[i] = shapes.back();
  639.                         shapes.pop_back();
  640.                 }
  641.                 else
  642.                 {
  643.                         ++i;
  644.                 }
  645.         }
  646. }
  647.  
  648. void CAISystem::DebugDrawFakeTracers() const
  649. {
  650.         FUNCTION_PROFILER(GetISystem(), PROFILE_AI);
  651.  
  652.         CDebugDrawContext dc;
  653.         dc->SetAlphaBlended(true);
  654.  
  655.         for (size_t i = 0; i < m_DEBUG_fakeTracers.size(); ++i)
  656.         {
  657.                 Vec3 p0 = m_DEBUG_fakeTracers[i].p0;
  658.                 Vec3 p1 = m_DEBUG_fakeTracers[i].p1;
  659.                 Vec3 dir = p1 - p0;
  660.                 float u = 1 - m_DEBUG_fakeTracers[i].t / m_DEBUG_fakeTracers[i].tmax;
  661.                 p0 += dir * u * 0.5f;
  662.                 p1 = p0 + dir * 0.5f;
  663.  
  664.                 float a = (m_DEBUG_fakeTracers[i].a * m_DEBUG_fakeTracers[i].t / m_DEBUG_fakeTracers[i].tmax) * 0.75f + 0.25f;
  665.                 Vec3 mid((p0 + p1) / 2);
  666.                 dc->DrawLine(p0, ColorB(128, 128, 128, 0), mid, ColorB(255, 255, 255, (uint8)(255 * a)), 6.0f);
  667.                 dc->DrawLine(p1, ColorB(128, 128, 128, 0), mid, ColorB(255, 255, 255, (uint8)(255 * a)), 6.0f);
  668.         }
  669. }
  670.  
  671. void CAISystem::DebugDrawFakeHitEffects() const
  672. {
  673.         FUNCTION_PROFILER(GetISystem(), PROFILE_AI);
  674.  
  675.         CDebugDrawContext dc;
  676.         dc->SetAlphaBlended(true);
  677.  
  678.         for (size_t i = 0; i < m_DEBUG_fakeHitEffect.size(); ++i)
  679.         {
  680.                 float a = m_DEBUG_fakeHitEffect[i].t / m_DEBUG_fakeHitEffect[i].tmax;
  681.                 Vec3 pos = m_DEBUG_fakeHitEffect[i].p + m_DEBUG_fakeHitEffect[i].n * (1 - sqr(a));
  682.                 float r = m_DEBUG_fakeHitEffect[i].r * (0.5f + (1 - a) * 0.5f);
  683.                 dc->DrawSphere(pos, r, ColorB(m_DEBUG_fakeHitEffect[i].c.r, m_DEBUG_fakeHitEffect[i].c.g, m_DEBUG_fakeHitEffect[i].c.b, (uint8)(m_DEBUG_fakeHitEffect[i].c.a * a)));
  684.         }
  685. }
  686.  
  687. void CAISystem::DebugDrawFakeDamageInd() const
  688. {
  689.         FUNCTION_PROFILER(GetISystem(), PROFILE_AI);
  690.  
  691.         int mode = gAIEnv.CVars.DrawFakeDamageInd;
  692.  
  693.         CAIObject* pPlayer = GetPlayer();
  694.         if (pPlayer)
  695.         {
  696.                 // full screen quad
  697.                 CDebugDrawContext dc;
  698.                 dc->Init2DMode();
  699.                 dc->SetAlphaBlended(true);
  700.                 dc->SetBackFaceCulling(false);
  701.  
  702.                 // Fullscreen flash for damage indication.
  703.                 if (m_DEBUG_screenFlash > 0.0f)
  704.                 {
  705.                         float f = m_DEBUG_screenFlash * 2.0f;
  706.                         float a = clamp_tpl(f, 0.0f, 1.0f);
  707.                         ColorB color(239, 50, 25, (uint8)(a * 255));
  708.                         dc->DrawTriangle(Vec3(0, 0, 0), color, Vec3(1, 0, 0), color, Vec3(1, 1, 0), color);
  709.                         dc->DrawTriangle(Vec3(0, 0, 0), color, Vec3(1, 1, 0), color, Vec3(0, 1, 0), color);
  710.                 }
  711.  
  712.                 // Damage indicator triangles
  713.                 Matrix33 basis;
  714.                 basis.SetRotationVDir(pPlayer->GetViewDir());
  715.                 Vec3 u = basis.GetColumn0();
  716.                 Vec3 v = basis.GetColumn1();
  717.                 Vec3 w = basis.GetColumn2();
  718.  
  719.                 float rw = (float)dc->GetWidth();
  720.                 float rh = (float)dc->GetHeight();
  721.                 float as = rh / rw;
  722.  
  723.                 const float FOV = dc->GetCameraFOV() * 0.95f;
  724.  
  725.                 for (unsigned int i = 0; i < m_DEBUG_fakeDamageInd.size(); ++i)
  726.                 {
  727.                         Vec3 dir = m_DEBUG_fakeDamageInd[i].p - pPlayer->GetPos();
  728.                         dir.NormalizeSafe();
  729.                         float x = u.Dot(dir);
  730.                         float y = v.Dot(dir);
  731.                         float d = sqrtf(sqr(x) + sqr(y));
  732.                         if (d < 0.00001f)
  733.                                 continue;
  734.                         x /= d;
  735.                         y /= d;
  736.                         float nx = y;
  737.                         float ny = -x;
  738.  
  739.                         const float r0 = 0.15f;
  740.                         const float r1 = 0.25f;
  741.                         const float wi = 0.04f;
  742.  
  743.                         float a = 1 - sqr(1 - m_DEBUG_fakeDamageInd[i].t / m_DEBUG_fakeDamageInd[i].tmax);
  744.  
  745.                         bool targetVis = false;
  746.  
  747.                         if (mode == 2)
  748.                         {
  749.                                 Vec3 dirLocal(u.Dot(dir), v.Dot(dir), w.Dot(dir));
  750.                                 if (dirLocal.y > 0.1f)
  751.                                 {
  752.                                         dirLocal.x /= dirLocal.y;
  753.                                         dirLocal.z /= dirLocal.y;
  754.  
  755.                                         float tz = tanf(FOV / 2);
  756.                                         float tx = rw / rh * tz;
  757.  
  758.                                         if (fabsf(dirLocal.x) < tx && fabsf(dirLocal.z) < tz)
  759.                                                 targetVis = true;
  760.                                 }
  761.                         }
  762.  
  763.                         ColorB color(239, 50, 25, (uint8)(a * 255));
  764.  
  765.                         if (!targetVis)
  766.                         {
  767.                                 dc->DrawTriangle(Vec3(0.5f + (x * r0) * as, 0.5f - (y * r0), 0), color,
  768.                                                  Vec3(0.5f + (x * r1 + nx * wi) * as, 0.5f - (y * r1 + ny * wi), 0), color,
  769.                                                  Vec3(0.5f + (x * r1 - nx * wi) * as, 0.5f - (y * r1 - ny * wi), 0), color);
  770.                         }
  771.                         else
  772.                         {
  773.                                 // Draw silhouette when on FOV.
  774.                                 static std::vector<Vec3> pos2d;
  775.                                 static std::vector<Vec3> pos2dSil;
  776.                                 static std::vector<ColorB> colorSil;
  777.                                 pos2d.resize(m_DEBUG_fakeDamageInd[i].verts.size());
  778.  
  779.                                 for (unsigned int j = 0, j_aux = 0; j < m_DEBUG_fakeDamageInd[i].verts.size(); ++j)
  780.                                 {
  781.                                         const Vec3& v2 = m_DEBUG_fakeDamageInd[i].verts[j];
  782.                                         Vec3& o = pos2d[j_aux];
  783.  
  784.                                         if (dc->ProjectToScreen(v2.x, v2.y, v2.z, &o.x, &o.y, &o.z))
  785.                                         {
  786.                                                 o.x /= 100.0f;
  787.                                                 o.y /= 100.0f;
  788.                                                 ++j_aux;
  789.                                         }
  790.                                 }
  791.  
  792.                                 pos2dSil.clear();
  793.                                 ConvexHull2D(pos2dSil, pos2d);
  794.  
  795.                                 if (pos2dSil.size() > 2)
  796.                                 {
  797.                                         colorSil.resize(pos2dSil.size());
  798.                                         float miny = FLT_MAX, maxy = -FLT_MAX;
  799.                                         for (unsigned int j = 0; j < pos2dSil.size(); ++j)
  800.                                         {
  801.                                                 miny = min(miny, pos2dSil[j].y);
  802.                                                 maxy = max(maxy, pos2dSil[j].y);
  803.                                         }
  804.                                         float range = maxy - miny;
  805.                                         if (range > 0.0001f)
  806.                                                 range = 1.0f / range;
  807.                                         for (unsigned int j = 0; j < pos2dSil.size(); ++j)
  808.                                         {
  809.                                                 float aa = clamp_tpl((1 - (pos2dSil[j].y - miny) * range) * 2.0f, 0.0f, 1.0f);
  810.                                                 colorSil[j] = color;
  811.                                                 colorSil[j].a *= (uint8)(aa * a);
  812.                                         }
  813.                                         dc->DrawPolyline(&pos2dSil[0], pos2dSil.size(), true, &colorSil[0], 2.0f);
  814.                                 }
  815.                         }
  816.                 }
  817.  
  818.                 // Draw ambient fire indicators
  819.                 if (gAIEnv.CVars.DebugDrawDamageControl > 1)
  820.                 {
  821.                         const Vec3& playerPos = pPlayer->GetPos();
  822.                         AIObjectOwners::const_iterator aio = gAIEnv.pAIObjectManager->m_Objects.find(AIOBJECT_ACTOR);
  823.                         for (; aio != gAIEnv.pAIObjectManager->m_Objects.end(); ++aio)
  824.                         {
  825.                                 if (aio->first != AIOBJECT_ACTOR) break;
  826.                                 CPuppet* pPuppet = aio->second.GetAIObject()->CastToCPuppet();
  827.                                 if (!pPuppet) continue;
  828.                                 if (!pPuppet->IsEnabled()) continue;
  829.                                 if (Distance::Point_PointSq(playerPos, pPuppet->GetPos()) > sqr(150.0f)) continue;
  830.  
  831.                                 Vec3 dir = pPuppet->GetPos() - playerPos;
  832.                                 float x = u.Dot(dir);
  833.                                 float y = v.Dot(dir);
  834.                                 float d = sqrtf(sqr(x) + sqr(y));
  835.                                 if (d < 0.00001f)
  836.                                         continue;
  837.                                 x /= d;
  838.                                 y /= d;
  839.                                 float nx = y;
  840.                                 float ny = -x;
  841.  
  842.                                 const float r0 = 0.25f;
  843.                                 const float r1 = 0.28f;
  844.                                 const float w2 = 0.01f;
  845.  
  846.                                 ColorB color(255, 255, 255, pPuppet->IsAllowedToHitTarget() ? 255 : 64);
  847.                                 dc->DrawTriangle(Vec3(0.5f + (x * r0) * as, 0.5f - (y * r0), 0), color,
  848.                                                  Vec3(0.5f + (x * r1 + nx * w2) * as, 0.5f - (y * r1 + ny * w2), 0), color,
  849.                                                  Vec3(0.5f + (x * r1 - nx * w2) * as, 0.5f - (y * r1 - ny * w2), 0), color);
  850.                         }
  851.                 }
  852.         }
  853. }
  854.  
  855. // Draw rings around player to assist in gauging target distance
  856. void CAISystem::DebugDrawPlayerRanges() const
  857. {
  858.         FUNCTION_PROFILER(GetISystem(), PROFILE_AI);
  859.  
  860.         CDebugDrawContext dc;
  861.         dc->SetAlphaBlended(true);
  862.  
  863.         CAIObject* player = GetPlayer();
  864.         if (player && !player->GetPos().IsZero())
  865.                 dc->DrawCircles(player->GetPos(), 5.f, 20.f, 4, Vec3(1, 0, 0), Vec3(1, 1, 0));
  866. }
  867.  
  868. // Draw Perception Indicators
  869. void CAISystem::DebugDrawPerceptionIndicators()
  870. {
  871.         FUNCTION_PROFILER(GetISystem(), PROFILE_AI);
  872.  
  873.         static CTimeValue lastTime(-1.0f);
  874.         if (lastTime.GetSeconds() < 0.0f)
  875.                 lastTime = GetFrameStartTime();
  876.         CTimeValue time = GetFrameStartTime();
  877.         float dt = (time - lastTime).GetSeconds();
  878.         lastTime = time;
  879.  
  880.         CDebugDrawContext dc;
  881.         dc->SetAlphaBlended(true);
  882.  
  883.         for (std::list<SPerceptionDebugLine>::iterator lineIt = m_lstDebugPerceptionLines.begin(); lineIt != m_lstDebugPerceptionLines.end(); )
  884.         {
  885.                 SPerceptionDebugLine& line = (*lineIt);
  886.                 line.time -= dt;
  887.                 if (line.time < 0)
  888.                         lineIt = m_lstDebugPerceptionLines.erase(lineIt);
  889.                 else
  890.                 {
  891.                         dc->DrawLine(line.start, line.color, line.end, line.color, line.thickness);
  892.                         ++lineIt;
  893.                 }
  894.         }
  895. }
  896.  
  897. // Draw Perception Modifiers
  898. void CAISystem::DebugDrawPerceptionModifiers()
  899. {
  900.         FUNCTION_PROFILER(GetISystem(), PROFILE_AI);
  901.  
  902.         CDebugDrawContext dc;
  903.         dc->SetAlphaBlended(true);
  904.  
  905.         ColorB color(20, 255, 255);
  906.         PerceptionModifierShapeMap::iterator pmsi = m_mapPerceptionModifiers.begin(), pmsiEnd = m_mapPerceptionModifiers.end();
  907.         for (; pmsi != pmsiEnd; ++pmsi)
  908.         {
  909.                 SPerceptionModifierShape& shape = pmsi->second;
  910.                 if (shape.shape.empty()) continue;
  911.  
  912.                 ListPositions::iterator first = shape.shape.begin();
  913.                 ListPositions::iterator second = shape.shape.begin();
  914.                 ++second;
  915.                 for (; first != shape.shape.end(); ++first, ++second)
  916.                 {
  917.                         Vec3 firstTop(first->x, first->y, shape.aabb.max.z);
  918.                         Vec3 firstBottom(first->x, first->y, shape.aabb.min.z);
  919.  
  920.                         if (second == shape.shape.end())
  921.                         {
  922.                                 // Handle the last side of shape based on whether shape is open or closed
  923.                                 if (!shape.closed)
  924.                                 {
  925.                                         dc->DrawLine(firstBottom, color, firstTop, color, 1.f);
  926.                                         continue;
  927.                                 }
  928.                                 else
  929.                                         second = shape.shape.begin();
  930.                         }
  931.  
  932.                         Vec3 secondTop(second->x, second->y, shape.aabb.max.z);
  933.                         Vec3 secondBottom(second->x, second->y, shape.aabb.min.z);
  934.  
  935.                         dc->DrawLine(firstBottom, color, secondBottom, color, 1.f);
  936.                         dc->DrawLine(firstBottom, color, firstTop, color, 1.f);
  937.                         dc->DrawLine(firstTop, color, secondTop, color, 1.f);
  938.                 }
  939.         }
  940. }
  941.  
  942. void CAISystem::DebugDrawTargetTracks() const
  943. {
  944.         FUNCTION_PROFILER(GetISystem(), PROFILE_AI);
  945.  
  946.         gAIEnv.pTargetTrackManager->DebugDraw();
  947. }
  948.  
  949. void CAISystem::DebugDrawDebugAgent()
  950. {
  951.         if (IEntity* entity = gEnv->pEntitySystem->GetEntity(m_agentDebugTarget))
  952.         {
  953.                 if (IAIObject* ai = entity->GetAI())
  954.                 {
  955.                         // Show a visual cue to make it clear which entity we're debugging picked
  956.                         AddDebugSphere(ai->GetPos() + Vec3(0.0f, 0.0f, 0.5f), 0.1f, 0, 255, 0, 0.0f);
  957.                 }
  958.         }
  959. }
  960.  
  961. void CAISystem::DebugDrawCodeCoverage() const
  962. {
  963.         FUNCTION_PROFILER(GetISystem(), PROFILE_AI);
  964.  
  965.         gAIEnv.pCodeCoverageGUI->DebugDraw(gAIEnv.CVars.CodeCoverage);
  966. }
  967.  
  968. void CAISystem::DebugDrawPerceptionManager()
  969. {
  970.         FUNCTION_PROFILER(GetISystem(), PROFILE_AI);
  971.  
  972.         gAIEnv.pPerceptionManager->DebugDraw(gAIEnv.CVars.DebugPerceptionManager);
  973.         gAIEnv.pPerceptionManager->DebugDrawPerformance(gAIEnv.CVars.DebugPerceptionManager);
  974. }
  975.  
  976. void CAISystem::DebugDrawNavigation() const
  977. {
  978.         FUNCTION_PROFILER(GetISystem(), PROFILE_AI);
  979.  
  980.         m_pNavigation->DebugDraw();
  981. }
  982.  
  983. void CAISystem::DebugDrawGraph(int debugDrawValue) const
  984. {
  985.         FUNCTION_PROFILER(GetISystem(), PROFILE_AI);
  986.  
  987.         CDebugDrawContext dc;
  988.  
  989.         if (debugDrawValue == 72)
  990.                 DebugDrawGraphErrors(m_pGraph);
  991.         else if (debugDrawValue == 74)
  992.                 DebugDrawGraph(m_pGraph);
  993.         else if (debugDrawValue == 79 || debugDrawValue == 179 || debugDrawValue == 279)
  994.         {
  995.                 std::vector<Vec3> pos;
  996.                 pos.push_back(dc->GetCameraPos());
  997.                 DebugDrawGraph(m_pGraph, &pos, 15);
  998.         }
  999. }
  1000.  
  1001. void CAISystem::DebugDrawLightManager()
  1002. {
  1003.         FUNCTION_PROFILER(GetISystem(), PROFILE_AI);
  1004.  
  1005.         m_lightManager.DebugDraw();
  1006. }
  1007.  
  1008. void CAISystem::DebugDrawP0AndP1() const
  1009. {
  1010.         FUNCTION_PROFILER(GetISystem(), PROFILE_AI);
  1011.  
  1012.         CDebugDrawContext dc;
  1013.  
  1014.         IEntity* ent0 = gEnv->pEntitySystem->FindEntityByName("p0");
  1015.         IEntity* ent1 = gEnv->pEntitySystem->FindEntityByName("p1");
  1016.         if (ent0 && ent1)
  1017.         {
  1018.                 Vec3 p0 = ent0->GetWorldPos();
  1019.                 Vec3 p1 = ent1->GetWorldPos();
  1020.  
  1021.                 dc->DrawSphere(p0, 0.7f, ColorB(255, 255, 255, 128));
  1022.                 dc->DrawLine(p0, ColorB(255, 255, 255), p1, ColorB(255, 255, 255));
  1023.  
  1024.                 Vec3 hit;
  1025.                 float hitDist = 0;
  1026.                 if (IntersectSweptSphere(&hit, hitDist, Lineseg(p0, p1), 0.65f, AICE_STATIC))
  1027.                 {
  1028.                         Vec3 dir = p1 - p0;
  1029.                         dir.Normalize();
  1030.                         dc->DrawSphere(p0 + dir * hitDist, 0.7f, ColorB(255, 0, 0));
  1031.                 }
  1032.         }
  1033. }
  1034.  
  1035. void CAISystem::DebugDrawPuppetPaths()
  1036. {
  1037.         FUNCTION_PROFILER(GetISystem(), PROFILE_AI);
  1038.  
  1039.         CAIObject* pAI = gAIEnv.pAIObjectManager->GetAIObjectByName("DebugRequestPathInDirection");
  1040.         if (!pAI)
  1041.                 return;
  1042.  
  1043.         unsigned short int nType = pAI->GetType();
  1044.         if ((nType != AIOBJECT_ACTOR) && (nType != AIOBJECT_VEHICLE))
  1045.                 return;
  1046.  
  1047.         CPipeUser* pPipeUser = pAI->CastToCPipeUser();
  1048.         if (!pPipeUser)
  1049.                 return;
  1050.  
  1051.         static CTimeValue lastTime = GetAISystem()->GetFrameStartTime();
  1052.         CTimeValue thisTime = GetAISystem()->GetFrameStartTime();
  1053.         const float regenTime = 1.0f;
  1054.  
  1055.         if ((thisTime - lastTime).GetSeconds() > regenTime)
  1056.         {
  1057.                 lastTime = thisTime;
  1058.                 pPipeUser->m_Path.Clear("DebugRequestPathInDirection");
  1059.                 Vec3 vStartPos = pPipeUser->GetPhysicsPos();
  1060.                 const float maxDist = 15.0f;
  1061.         }
  1062.  
  1063.         DebugDrawPathSingle(pPipeUser);
  1064. }
  1065.  
  1066. void CAISystem::DebugDrawCheckCapsules() const
  1067. {
  1068.         FUNCTION_PROFILER(GetISystem(), PROFILE_AI);
  1069.  
  1070.         IEntity* ent = gEnv->pEntitySystem->FindEntityByName("CheckCapsule");
  1071.         if (ent)
  1072.         {
  1073.                 // match the params in CheckWalkability
  1074.                 const float radius = WalkabilityRadius;
  1075.                 const Vec3 dir(0, 0, 0.9f);
  1076.  
  1077.                 const Vec3& pos = ent->GetPos();
  1078.  
  1079.                 bool result = OverlapCapsule(Lineseg(pos, pos + dir), radius, AICE_ALL);
  1080.                 ColorB color;
  1081.                 if (result)
  1082.                         color.set(255, 0, 0, 255);
  1083.                 else
  1084.                         color.set(0, 255, 0, 255);
  1085.                 CDebugDrawContext dc;
  1086.                 dc->DrawSphere(pos, radius, color);
  1087.                 dc->DrawSphere(pos + dir, radius, color);
  1088.         }
  1089. }
  1090.  
  1091. void CAISystem::DebugDrawCheckRay() const
  1092. {
  1093.         FUNCTION_PROFILER(GetISystem(), PROFILE_AI);
  1094.  
  1095.         IEntity* entFrom = gEnv->pEntitySystem->FindEntityByName("CheckRayFrom");
  1096.         IEntity* entTo = gEnv->pEntitySystem->FindEntityByName("CheckRayTo");
  1097.         if (entFrom && entTo)
  1098.         {
  1099.                 const Vec3& posFrom = entFrom->GetPos();
  1100.                 const Vec3& posTo = entTo->GetPos();
  1101.  
  1102.                 bool result = OverlapSegment(Lineseg(posFrom, posTo), AICE_ALL);
  1103.                 ColorB color;
  1104.                 if (result)
  1105.                         color.set(255, 0, 0, 255);
  1106.                 else
  1107.                         color.set(0, 255, 0, 255);
  1108.  
  1109.                 CDebugDrawContext dc;
  1110.                 dc->DrawLine(posFrom, color, posTo, color);
  1111.         }
  1112. }
  1113.  
  1114. void CAISystem::DebugDrawCheckWalkability()
  1115. {
  1116.         FUNCTION_PROFILER(GetISystem(), PROFILE_AI);
  1117.  
  1118.         IEntity* entFrom = gEnv->pEntitySystem->FindEntityByName("CheckWalkabilityFrom");
  1119.         IEntity* entTo = gEnv->pEntitySystem->FindEntityByName("CheckWalkabilityTo");
  1120.         if (entFrom && entTo)
  1121.         {
  1122.                 CDebugDrawContext dc;
  1123.  
  1124.                 {
  1125.                         static CTimeValue lastTime = gEnv->pTimer->GetAsyncTime();
  1126.                         CTimeValue thisTime = gEnv->pTimer->GetAsyncTime();
  1127.                         float deltaT = (thisTime - lastTime).GetSeconds();
  1128.                         static float testsPerSec = 0.0f;
  1129.                         if (deltaT > 2.0f)
  1130.                         {
  1131.                                 lastTime = thisTime;
  1132.                                 testsPerSec = g_CheckWalkabilityCalls / deltaT;
  1133.                                 g_CheckWalkabilityCalls = 0;
  1134.                         }
  1135.                         const int column = 5;
  1136.                         const int row = 50;
  1137.                         char buff[256];
  1138.                         cry_sprintf(buff, "%5.2f walkability calls per sec", testsPerSec);
  1139.                         dc->Draw2dLabel(column, row, buff, ColorB(255, 0, 255));
  1140.                 }
  1141.  
  1142.                 const Vec3& posFrom = entFrom->GetPos();
  1143.                 const Vec3& posTo = entTo->GetPos();
  1144.                 int nBuildingID;
  1145.                 m_pNavigation->CheckNavigationType(posFrom, nBuildingID, IAISystem::NAV_WAYPOINT_HUMAN);
  1146.                 const SpecialArea* sa = m_pNavigation->GetSpecialArea(nBuildingID);
  1147.                 const float radius = 0.3f;
  1148.                 bool result = CheckWalkability(posFrom, posTo, 0.35f, sa ? sa->GetPolygon() : ListPositions());
  1149.                 ColorB color;
  1150.                 if (result)
  1151.                         color.set(0, 255, 0, 255);
  1152.                 else
  1153.                         color.set(255, 0, 0, 255);
  1154.                 dc->DrawSphere(posFrom, radius, color);
  1155.                 dc->DrawSphere(posTo, radius, color);
  1156.         }
  1157. }
  1158.  
  1159. void CAISystem::DebugDrawCheckWalkabilityTime() const
  1160. {
  1161.         FUNCTION_PROFILER(GetISystem(), PROFILE_AI);
  1162.  
  1163.         IEntity* entFrom = gEnv->pEntitySystem->FindEntityByName("CheckWalkabilityTimeFrom");
  1164.         IEntity* entTo = gEnv->pEntitySystem->FindEntityByName("CheckWalkabilityTimeTo");
  1165.         if (entFrom && entTo)
  1166.         {
  1167.                 const Vec3& posFrom = entFrom->GetPos();
  1168.                 const Vec3& posTo = entTo->GetPos();
  1169.                 const float radius = 0.3f;
  1170.                 bool result;
  1171.                 const int num = 100;
  1172.                 CTimeValue startTime = gEnv->pTimer->GetAsyncTime();
  1173.                 for (int i = 0; i < num; ++i)
  1174.                         result = CheckWalkability(posFrom, posTo, 0.35f, ListPositions());
  1175.                 CTimeValue endTime = gEnv->pTimer->GetAsyncTime();
  1176.                 ColorB color;
  1177.                 if (result)
  1178.                         color.set(0, 255, 0, 255);
  1179.                 else
  1180.                         color.set(255, 0, 0, 255);
  1181.                 CDebugDrawContext dc;
  1182.                 dc->DrawSphere(posFrom, radius, color);
  1183.                 dc->DrawSphere(posTo, radius, color);
  1184.                 float time = (endTime - startTime).GetSeconds();
  1185.  
  1186.                 const int column = 5;
  1187.                 const int row = 50;
  1188.                 char buff[256];
  1189.                 cry_sprintf(buff, "%d walkability calls in %5.2f sec", num, time);
  1190.                 dc->Draw2dLabel(column, row, buff, ColorB(255, 0, 255));
  1191.         }
  1192. }
  1193.  
  1194. void CAISystem::DebugDrawCheckFloorPos() const
  1195. {
  1196.         FUNCTION_PROFILER(GetISystem(), PROFILE_AI);
  1197.  
  1198.         IEntity* ent = gEnv->pEntitySystem->FindEntityByName("CheckFloorPos");
  1199.         if (ent)
  1200.         {
  1201.                 const Vec3& pos = ent->GetPos();
  1202.                 const float up = 0.5f;
  1203.                 const float down = 5.0f;
  1204.                 const float radius = 0.1f;
  1205.                 Vec3 floorPos;
  1206.                 bool result = GetFloorPos(floorPos, pos, up, down, radius, AICE_ALL);
  1207.                 ColorB color;
  1208.                 if (result)
  1209.                         color.set(0, 255, 0, 255);
  1210.                 else
  1211.                         color.set(255, 0, 0, 255);
  1212.  
  1213.                 CDebugDrawContext dc;
  1214.                 dc->DrawSphere(floorPos, radius, color);
  1215.         }
  1216. }
  1217.  
  1218. void CAISystem::DebugDrawCheckGravity() const
  1219. {
  1220.         FUNCTION_PROFILER(GetISystem(), PROFILE_AI);
  1221.  
  1222.         IEntity* ent = gEnv->pEntitySystem->FindEntityByName("CheckGravity");
  1223.         if (ent)
  1224.         {
  1225.                 Vec3 pos = ent->GetPos();
  1226.                 Vec3 gravity;
  1227.                 pe_params_buoyancy junk;
  1228.                 gEnv->pPhysicalWorld->CheckAreas(pos, gravity, &junk);
  1229.                 ColorB color(255, 255, 255);
  1230.                 const float lenScale = 0.3f;
  1231.                 CDebugDrawContext dc;
  1232.                 dc->DrawLine(pos, color, pos + lenScale * gravity, color);
  1233.         }
  1234. }
  1235.  
  1236. void CAISystem::DebugDrawGetTeleportPos() const
  1237. {
  1238.         FUNCTION_PROFILER(GetISystem(), PROFILE_AI);
  1239.  
  1240.         IEntity* ent = gEnv->pEntitySystem->FindEntityByName("GetTeleportPos");
  1241.         if (ent)
  1242.         {
  1243.                 const Vec3& pos = ent->GetPos();
  1244.                 Vec3 teleportPos = pos;
  1245.  
  1246.                 IAISystem::tNavCapMask navCapMask = IAISystem::NAV_TRIANGULAR | IAISystem::NAV_WAYPOINT_HUMAN;
  1247.  
  1248.                 int nBuildingID;
  1249.                 IAISystem::ENavigationType currentNavType = m_pNavigation->CheckNavigationType(pos, nBuildingID, navCapMask);
  1250.  
  1251.                 bool canTeleport = gAIEnv.pNavigation->GetNavRegion(currentNavType, gAIEnv.pGraph)->GetTeleportPosition(pos, teleportPos, "GetTeleportPos");
  1252.  
  1253.                 CDebugDrawContext dc;
  1254.                 if (canTeleport)
  1255.                         dc->DrawSphere(teleportPos, 0.5f, ColorB(0, 255, 0));
  1256.                 else
  1257.                         dc->DrawSphere(pos, 0.5f, ColorB(255, 0, 0));
  1258.         }
  1259. }
  1260.  
  1261. // Draw debug shapes
  1262. // These shapes come from outside the AI system (such as some debug code in script bind in CryAction) but related to AI.
  1263. void CAISystem::DebugDrawDebugShapes()
  1264. {
  1265.         FUNCTION_PROFILER(GetISystem(), PROFILE_AI);
  1266.  
  1267.         const float dt = GetFrameDeltaTime();
  1268.         DrawDebugShapes(m_vecDebugLines, dt);
  1269.         DrawDebugShapes(m_vecDebugBoxes, dt);
  1270.         DrawDebugShapes(m_vecDebugSpheres, dt);
  1271.         DrawDebugShapes(m_vecDebugCylinders, dt);
  1272.         DrawDebugShapes(m_vecDebugCones, dt);
  1273. }
  1274.  
  1275. void CAISystem::DebugDrawGroupTactic()
  1276. {
  1277.         FUNCTION_PROFILER(GetISystem(), PROFILE_AI);
  1278.  
  1279.         for (AIGroupMap::iterator it = m_mapAIGroups.begin(); it != m_mapAIGroups.end(); ++it)
  1280.                 it->second->DebugDraw();
  1281. }
  1282.  
  1283. void CAISystem::DebugDrawDamageParts() const
  1284. {
  1285.         FUNCTION_PROFILER(GetISystem(), PROFILE_AI);
  1286.  
  1287.         CAIPlayer* pPlayer = CastToCAIPlayerSafe(GetPlayer());
  1288.         CDebugDrawContext dc;
  1289.         if (pPlayer && pPlayer->GetDamageParts())
  1290.         {
  1291.                 DamagePartVector* parts = pPlayer->GetDamageParts();
  1292.                 for (DamagePartVector::iterator it = parts->begin(); it != parts->end(); ++it)
  1293.                 {
  1294.                         SAIDamagePart& part = *it;
  1295.                         dc->Draw3dLabel(part.pos, 1, "^ DMG:%.2f\n  VOL:%.1f", part.damageMult, part.volume);
  1296.                 }
  1297.         }
  1298. }
  1299.  
  1300. // Draw the approximate stance size for the player.
  1301. void CAISystem::DebugDrawStanceSize() const
  1302. {
  1303.         FUNCTION_PROFILER(GetISystem(), PROFILE_AI);
  1304.  
  1305.         CAIObject* playerObject = GetPlayer();
  1306.         if (playerObject)
  1307.         {
  1308.                 if (CAIPlayer* player = playerObject->CastToCAIPlayer())
  1309.                 {
  1310.                         const SAIBodyInfo& bodyInfo = player->GetBodyInfo();
  1311.                         Vec3 pos = player->GetPhysicsPos();
  1312.                         AABB aabb(bodyInfo.stanceSize);
  1313.  
  1314.                         aabb.Move(pos);
  1315.                         CDebugDrawContext dc;
  1316.                         dc->DrawAABB(aabb, true, ColorB(255, 255, 255, 128), eBBD_Faceted);
  1317.                 }
  1318.         }
  1319. }
  1320.  
  1321. void CAISystem::DebugDrawForceAGSignal() const
  1322. {
  1323.         FUNCTION_PROFILER(GetISystem(), PROFILE_AI);
  1324.  
  1325.         ColorB colorRed(255, 0, 0);
  1326.         const char* szInput = gAIEnv.CVars.ForceAGSignal;
  1327.  
  1328.         CDebugDrawContext dc;
  1329.         dc->Draw2dLabel(10, dc->GetHeight() - 90, 2.0f, colorRed, false, "Forced AG Signal Input: %s", szInput);
  1330. }
  1331.  
  1332. void CAISystem::DebugDrawForceAGAction() const
  1333. {
  1334.         FUNCTION_PROFILER(GetISystem(), PROFILE_AI);
  1335.  
  1336.         ColorB colorRed(255, 0, 0);
  1337.         const char* szInput = gAIEnv.CVars.ForceAGAction;
  1338.  
  1339.         CDebugDrawContext dc;
  1340.         dc->Draw2dLabel(10, dc->GetHeight() - 60, 2.0f, colorRed, false, "Forced AG Action Input: %s", szInput);
  1341. }
  1342.  
  1343. void CAISystem::DebugDrawForceStance() const
  1344. {
  1345.         FUNCTION_PROFILER(GetISystem(), PROFILE_AI);
  1346.  
  1347.         ColorB colorRed(255, 0, 0);
  1348.         const char* szStance = GetStanceName(gAIEnv.CVars.ForceStance);
  1349.  
  1350.         CDebugDrawContext dc;
  1351.         dc->Draw2dLabel(10, dc->GetHeight() - 30, 2.0f, colorRed, false, "Forced Stance: %s", szStance);
  1352. }
  1353.  
  1354. void CAISystem::DebugDrawForcePosture() const
  1355. {
  1356.         FUNCTION_PROFILER(GetISystem(), PROFILE_AI);
  1357.  
  1358.         ColorB colorRed(255, 0, 0);
  1359.         const char* szPosture = gAIEnv.CVars.ForcePosture;
  1360.  
  1361.         CDebugDrawContext dc;
  1362.         dc->Draw2dLabel(10, dc->GetHeight() - 30, 2.0f, colorRed, false, "Forced Posture: %s", szPosture);
  1363. }
  1364.  
  1365. // Player actions
  1366. void CAISystem::DebugDrawPlayerActions() const
  1367. {
  1368.         FUNCTION_PROFILER(GetISystem(), PROFILE_AI);
  1369.  
  1370.         CAIPlayer* pPlayer = CastToCAIPlayerSafe(GetPlayer());
  1371.         if (pPlayer)
  1372.                 pPlayer->DebugDraw();
  1373. }
  1374.  
  1375. void CAISystem::DebugDrawCrowdControl()
  1376. {
  1377.         FUNCTION_PROFILER(GetISystem(), PROFILE_AI);
  1378.  
  1379.         CDebugDrawContext dc;
  1380.  
  1381.         Vec3 camPos = dc->GetCameraPos();
  1382.  
  1383.         VectorSet<const CAIActor*> avoidedActors;
  1384.  
  1385.         AIObjectOwners::const_iterator ai = gAIEnv.pAIObjectManager->m_Objects.find(AIOBJECT_ACTOR);
  1386.         for (; ai != gAIEnv.pAIObjectManager->m_Objects.end(); ++ai)
  1387.         {
  1388.                 if (ai->first != AIOBJECT_ACTOR)
  1389.                         break;
  1390.                 CAIObject* obj = ai->second.GetAIObject();
  1391.                 CPuppet* pPuppet = obj->CastToCPuppet();
  1392.                 if (!pPuppet)
  1393.                         continue;
  1394.                 if (!pPuppet->IsEnabled())
  1395.                         continue;
  1396.                 if (!pPuppet->m_steeringEnabled)
  1397.                         continue;
  1398.                 if (Distance::Point_PointSq(camPos, pPuppet->GetPos()) > sqr(150.0f))
  1399.                         continue;
  1400.  
  1401.                 Vec3 center = pPuppet->GetPhysicsPos() + Vec3(0, 0, 0.75f);
  1402.                 const float rad = pPuppet->GetMovementAbility().pathRadius;
  1403.  
  1404.                 /* Draw circle sector */
  1405.                 pPuppet->m_steeringOccupancy.DebugDraw(center, ColorB(0, 196, 255, 240));
  1406.  
  1407.                 for (unsigned int i = 0, ni = pPuppet->m_steeringObjects.size(); i < ni; ++i)
  1408.                 {
  1409.                         const CAIActor* pActor = pPuppet->m_steeringObjects[i]->CastToCAIActor();
  1410.                         avoidedActors.insert(pActor);
  1411.                 }
  1412.         }
  1413.  
  1414.         for (unsigned int i = 0, ni = avoidedActors.size(); i < ni; ++i)
  1415.         {
  1416.                 const CAIActor* pActor = avoidedActors[i];
  1417.                 if (pActor->GetType() == AIOBJECT_VEHICLE)
  1418.                 {
  1419.                         IEntity* pActorEnt = pActor->GetEntity();
  1420.                         AABB localBounds;
  1421.                         pActorEnt->GetLocalBounds(localBounds);
  1422.                         const Matrix34& tm = pActorEnt->GetWorldTM();
  1423.  
  1424.                         SAIRect3 r;
  1425.                         GetFloorRectangleFromOrientedBox(tm, localBounds, r);
  1426.                         // Extend the box based on velocity.
  1427.                         Vec3 vel = pActor->GetVelocity();
  1428.                         float speedu = r.axisu.Dot(vel) * 0.25f;
  1429.                         float speedv = r.axisv.Dot(vel) * 0.25f;
  1430.                         if (speedu > 0)
  1431.                                 r.max.x += speedu;
  1432.                         else
  1433.                                 r.min.x += speedu;
  1434.                         if (speedv > 0)
  1435.                                 r.max.y += speedv;
  1436.                         else
  1437.                                 r.min.y += speedv;
  1438.  
  1439.                         Vec3 rect[4];
  1440.                         rect[0] = r.center + r.axisu * r.min.x + r.axisv * r.min.y;
  1441.                         rect[1] = r.center + r.axisu * r.max.x + r.axisv * r.min.y;
  1442.                         rect[2] = r.center + r.axisu * r.max.x + r.axisv * r.max.y;
  1443.                         rect[3] = r.center + r.axisu * r.min.x + r.axisv * r.max.y;
  1444.  
  1445.                         /* ??? */
  1446.                         dc->DrawPolyline(rect, 4, true, ColorB(0, 196, 255, 128));
  1447.                 }
  1448.                 else
  1449.                 {
  1450.                         Vec3 pos = avoidedActors[i]->GetPhysicsPos() + Vec3(0, 0, 0.5f);
  1451.                         const float rad = avoidedActors[i]->GetMovementAbility().pathRadius;
  1452.                         /* Draw additional cyan circle around puppets */
  1453.                         dc->DrawCircleOutline(pos, rad, ColorB(0, 196, 255, 128));
  1454.                 }
  1455.         }
  1456. }
  1457.  
  1458. static const char* GetMovemengtUrgencyLabel(int idx)
  1459. {
  1460.         switch (idx > 0 ? idx : -idx)
  1461.         {
  1462.         case 0:
  1463.                 return "Zero";
  1464.                 break;
  1465.         case 1:
  1466.                 return "Slow";
  1467.                 break;
  1468.         case 2:
  1469.                 return "Walk";
  1470.                 break;
  1471.         case 3:
  1472.                 return "Run";
  1473.                 break;
  1474.         default:
  1475.                 break;
  1476.         }
  1477.         return "Sprint";
  1478. }
  1479.  
  1480. void CAISystem::DebugDrawAdaptiveUrgency() const
  1481. {
  1482.         FUNCTION_PROFILER(GetISystem(), PROFILE_AI);
  1483.  
  1484.         CDebugDrawContext dc;
  1485.  
  1486.         Vec3 camPos = dc->GetCameraPos();
  1487.  
  1488.         int mode = gAIEnv.CVars.DebugDrawAdaptiveUrgency;
  1489.  
  1490.         AIObjectOwners::const_iterator ai = gAIEnv.pAIObjectManager->m_Objects.find(AIOBJECT_ACTOR);
  1491.         for (; ai != gAIEnv.pAIObjectManager->m_Objects.end(); ++ai)
  1492.         {
  1493.                 if (ai->first != AIOBJECT_ACTOR)
  1494.                         break;
  1495.                 CAIObject* obj = ai->second.GetAIObject();
  1496.                 CPuppet* pPuppet = obj->CastToCPuppet();
  1497.                 if (!pPuppet)
  1498.                         continue;
  1499.                 if (!pPuppet->IsEnabled())
  1500.                         continue;
  1501.                 if (Distance::Point_PointSq(camPos, pPuppet->GetPos()) > sqr(150.0f))
  1502.                         continue;
  1503.  
  1504.                 if (pPuppet->m_adaptiveUrgencyScaleDownPathLen <= 0.0001f)
  1505.                         continue;
  1506.  
  1507.                 int minIdx = MovementUrgencyToIndex(pPuppet->m_adaptiveUrgencyMin);
  1508.                 int maxIdx = MovementUrgencyToIndex(pPuppet->m_adaptiveUrgencyMax);
  1509.                 int curIdx = MovementUrgencyToIndex(pPuppet->GetState().fMovementUrgency);
  1510.  
  1511.                 const SAIBodyInfo& bi = pPuppet->GetBodyInfo();
  1512.  
  1513.                 AABB stanceSize(bi.stanceSize);
  1514.                 stanceSize.Move(pPuppet->GetPhysicsPos());
  1515.  
  1516.                 Vec3 top = stanceSize.GetCenter() + Vec3(0, 0, stanceSize.GetSize().z / 2 + 0.3f);
  1517.  
  1518.                 if (mode > 1)
  1519.                         dc->DrawAABB(stanceSize, false, ColorB(240, 220, 0, 128), eBBD_Faceted);
  1520.  
  1521.                 if (curIdx < maxIdx)
  1522.                 {
  1523.                         dc->DrawAABB(stanceSize, true, ColorB(240, 220, 0, 128), eBBD_Faceted);
  1524.                         dc->Draw3dLabel(top, 1.1f, "%s -> %s\n%d", GetMovemengtUrgencyLabel(maxIdx), GetMovemengtUrgencyLabel(curIdx), maxIdx - curIdx);
  1525.                 }
  1526.         }
  1527. }
  1528.  
  1529. static void DrawRadarCircle(const Vec3& pos, float radius, const ColorB& color, const Matrix34& world, const Matrix34& screen)
  1530. {
  1531.         Vec3 last;
  1532.  
  1533.         float r = world.TransformVector(Vec3(radius, 0, 0)).GetLength();
  1534.         unsigned int n = (unsigned int)((r * gf_PI2) / 5.0f);
  1535.         if (n < 5) n = 5;
  1536.         if (n > 50) n = 50;
  1537.  
  1538.         CDebugDrawContext dc;
  1539.         for (unsigned int i = 0; i < n; i++)
  1540.         {
  1541.                 float a = (float)i / (float)(n - 1) * gf_PI2;
  1542.                 Vec3 p = world.TransformPoint(pos + Vec3(cosf(a) * radius, sinf(a) * radius, 0));
  1543.                 if (i > 0)
  1544.                         dc->DrawLine(screen.TransformPoint(last), color, screen.TransformPoint(p), color);
  1545.                 last = p;
  1546.         }
  1547. }
  1548.  
  1549. void CAISystem::DrawRadarPath(CPipeUser* pPipeUser, const Matrix34& world, const Matrix34& screen)
  1550. {
  1551.         FUNCTION_PROFILER(GetISystem(), PROFILE_AI);
  1552.  
  1553.         const char* pName = gAIEnv.CVars.DrawPath;
  1554.         if (!pName)
  1555.                 return;
  1556.         CAIObject* pTargetObject = gAIEnv.pAIObjectManager->GetAIObjectByName(pName);
  1557.         if (pTargetObject)
  1558.         {
  1559.                 CPipeUser* pTargetPipeUser = pTargetObject->CastToCPipeUser();
  1560.                 if (!pTargetPipeUser)
  1561.                         return;
  1562.                 DebugDrawPathSingle(pTargetPipeUser);
  1563.                 return;
  1564.         }
  1565.         if (strcmp(pName, "all"))
  1566.                 return;
  1567.  
  1568.         // draw the first part of the path in a different colour
  1569.         if (!pPipeUser->m_OrigPath.GetPath().empty())
  1570.         {
  1571.                 TPathPoints::const_iterator li, linext;
  1572.                 li = pPipeUser->m_OrigPath.GetPath().begin();
  1573.                 linext = li;
  1574.                 ++linext;
  1575.                 // (MATT) BUG! Surely. m_Path or m_OrigPath, which is it? Appears elsewhere too. {2008/05/29}
  1576.                 Vec3 endPt = pPipeUser->m_Path.GetNextPathPos();
  1577.                 CDebugDrawContext dc;
  1578.                 while (linext != pPipeUser->m_OrigPath.GetPath().end())
  1579.                 {
  1580.                         Vec3 p0 = world.TransformPoint(li->vPos);
  1581.                         Vec3 p1 = world.TransformPoint(linext->vPos);
  1582.                         dc->DrawLine(screen.TransformPoint(p0), ColorB(255, 0, 255), screen.TransformPoint(p1), ColorB(255, 0, 255));
  1583.                         li = linext++;
  1584.                 }
  1585.         }
  1586. }
  1587.  
  1588. void CAISystem::DebugDrawRadar()
  1589. {
  1590.         FUNCTION_PROFILER(GetISystem(), PROFILE_AI);
  1591.  
  1592.         int size = gAIEnv.CVars.DrawRadar;
  1593.         if (size == 0)
  1594.                 return;
  1595.  
  1596.         CDebugDrawContext dc;
  1597.         dc->Init2DMode();
  1598.         dc->SetAlphaBlended(true);
  1599.         dc->SetBackFaceCulling(false);
  1600.  
  1601.         int w = dc->GetWidth();
  1602.         int h = dc->GetHeight();
  1603.  
  1604.         int centerx = w / 2;
  1605.         int centery = h / 2;
  1606.  
  1607.         int radarDist = gAIEnv.CVars.DrawRadarDist;
  1608.         float worldSize = radarDist * 2.0f;
  1609.  
  1610.         Matrix34 worldToScreen;
  1611.         worldToScreen.SetIdentity();
  1612.         CCamera& cam = GetISystem()->GetViewCamera();
  1613.         Vec3 camPos = cam.GetPosition();
  1614.         Vec3 camForward = cam.GetMatrix().TransformVector(FORWARD_DIRECTION);
  1615.         float rot(atan2f(camForward.x, camForward.y));
  1616.         // inv camera
  1617.         //      worldToScreen.SetRotationZ(-rot);
  1618.         worldToScreen.AddTranslation(-camPos);
  1619.         worldToScreen = Matrix34::CreateRotationZ(rot) * worldToScreen;
  1620.         // world to screenspace conversion
  1621.         float s = (float)size / worldSize;
  1622.         worldToScreen = Matrix34::CreateScale(Vec3(s, s, 0)) * worldToScreen;
  1623.         // offset the position to upper right corner
  1624.         worldToScreen.AddTranslation(Vec3(centerx, centery, 0));
  1625.         // Inverse Y
  1626.         worldToScreen = Matrix34::CreateScale(Vec3(1, -1, 0)) * worldToScreen;
  1627.         worldToScreen.AddTranslation(Vec3(0, h, 0));
  1628.  
  1629.         Matrix34 screenToNorm;
  1630.         screenToNorm.SetIdentity();
  1631.         // normalize to 0..1
  1632.         screenToNorm = Matrix34::CreateScale(Vec3(1.0f / (float)w, 1.0f / (float)h, 1)) * screenToNorm;
  1633.  
  1634.         // Draw 15m circle.
  1635.         DrawRadarCircle(camPos, 0.5f, ColorB(255, 255, 255, 128), worldToScreen, screenToNorm);
  1636.         for (int i = 0; i < (radarDist / 5); i++)
  1637.         {
  1638.                 ColorB color(120, 120, 120, 64);
  1639.                 if (i & 1) color.a = 128;
  1640.                 DrawRadarCircle(camPos, (1 + i) * 5.0f, color, worldToScreen, screenToNorm);
  1641.         }
  1642.  
  1643.         const ColorB white(255, 255, 255);
  1644.         const ColorB green(137, 226, 9);
  1645.         const ColorB orange(255, 162, 0);
  1646.         const ColorB red(239, 50, 25);
  1647.         const ColorB black(0, 0, 0, 179);
  1648.  
  1649.         const CAISystem::AIActorSet& enabledAIActorsSet = GetAISystem()->GetEnabledAIActorSet();
  1650.         for (CAISystem::AIActorSet::const_iterator it = enabledAIActorsSet.begin(), itend = enabledAIActorsSet.end(); it != itend; ++it)
  1651.         {
  1652.                 CAIActor* pAIActor = it->GetAIObject();
  1653.                 if (!pAIActor)
  1654.                         continue;
  1655.  
  1656.                 CPuppet* pPuppet = pAIActor->CastToCPuppet();
  1657.  
  1658.                 if (Distance::Point_PointSq(pAIActor->GetPos(), camPos) > sqr(radarDist * 1.25f))
  1659.                         continue;
  1660.  
  1661.                 float rad(pAIActor->GetParameters().m_fPassRadius);
  1662.  
  1663.                 Vec3 pos, forw, right;
  1664.                 pos = worldToScreen.TransformPoint(pAIActor->GetPos());
  1665.                 forw = worldToScreen.TransformVector(pAIActor->GetViewDir() * rad);
  1666.                 //                      forw.NormalizeSafe();
  1667.                 right.Set(-forw.y, forw.x, 0);
  1668.  
  1669.                 ColorB color(255, 0, 0, 128);
  1670.  
  1671.                 int alertness = pAIActor->GetProxy()->GetAlertnessState();
  1672.                 if (alertness == 0)
  1673.                         color = green;
  1674.                 else if (alertness == 1)
  1675.                         color = orange;
  1676.                 else if (alertness == 2)
  1677.                         color = red;
  1678.                 color.a = 255;
  1679.                 if (!pAIActor->IsEnabled())
  1680.                         color.a = 64;
  1681.  
  1682.                 const float arrowSize = 1.5f;
  1683.  
  1684.                 dc->DrawTriangle(screenToNorm.TransformVector(pos - forw * 0.71f * arrowSize + right * 0.71f * arrowSize), color,
  1685.                                  screenToNorm.TransformVector(pos - forw * 0.71f * arrowSize - right * 0.71f * arrowSize), color,
  1686.                                  screenToNorm.TransformVector(pos + forw * arrowSize), color);
  1687.                 DrawRadarCircle(pAIActor->GetPos(), rad, ColorB(255, 255, 255, 64), worldToScreen, screenToNorm);
  1688.  
  1689.                 if (pPuppet)
  1690.                         DrawRadarPath(pPuppet, worldToScreen, screenToNorm);
  1691.  
  1692.                 if (pAIActor->GetState().fire)
  1693.                 {
  1694.                         ColorB fireColor(255, 26, 0);
  1695.                         if (pPuppet && !pPuppet->IsAllowedToHitTarget())
  1696.                                 fireColor.set(255, 255, 255, 128);
  1697.                         Vec3 tgt = worldToScreen.TransformPoint(pAIActor->GetState().vShootTargetPos);
  1698.                         dc->DrawLine(screenToNorm.TransformVector(pos), fireColor, screenToNorm.TransformVector(tgt), fireColor);
  1699.                 }
  1700.  
  1701.                 float accuracy = 0.0f;
  1702.                 if (pPuppet && pPuppet->GetFireTargetObject())
  1703.                         accuracy = pPuppet->GetAccuracy(pPuppet->GetFireTargetObject());
  1704.  
  1705.                 char szMsg[256];
  1706.  
  1707.                 if (pPuppet && !pPuppet->IsAllowedToHitTarget())
  1708.                         cry_sprintf(szMsg, "%s\nAcc:%.3f\nAMBIENT", pAIActor->GetName(), accuracy);
  1709.                 else
  1710.                         cry_sprintf(szMsg, "%s\nAcc:%.3f\n", pAIActor->GetName(), accuracy);
  1711.  
  1712.                 dc->Draw2dLabel(pos.x + 1, pos.y - 1, 1.2f, black, true, "%s", szMsg);
  1713.                 dc->Draw2dLabel(pos.x, pos.y, 1.2f, white, true, "%s", szMsg);
  1714.         }
  1715. }
  1716.  
  1717. void CAISystem::DebugDrawDistanceLUT()
  1718. {
  1719.         FUNCTION_PROFILER(GetISystem(), PROFILE_AI);
  1720.  
  1721.         if (gAIEnv.CVars.DrawDistanceLUT < 1)
  1722.                 return;
  1723. }
  1724.  
  1725. struct SSlopeTriangle
  1726. {
  1727.         SSlopeTriangle(const Triangle& tri, float slope) : triangle(tri), slope(slope) {}
  1728.         SSlopeTriangle() : triangle(Vec3(ZERO), Vec3(ZERO), Vec3(ZERO)), slope(0.0f) {}
  1729.         Triangle triangle;
  1730.         float    slope;
  1731. };
  1732.  
  1733. //====================================================================
  1734. // DebugDrawSteepSlopes
  1735. // Caches triangles first time this is enabled - then on subsequent
  1736. // calls just draws. Gets reset when the debug draw value changes
  1737. //====================================================================
  1738. void CAISystem::DebugDrawSteepSlopes()
  1739. {
  1740.         FUNCTION_PROFILER(GetISystem(), PROFILE_AI);
  1741.  
  1742.         static std::vector<SSlopeTriangle> triangles;
  1743.         /// Current centre for the region we draw
  1744.         static Vec3 currentPos(0.0f, 0.0f, 0.0f);
  1745.  
  1746.         // Size of the area to calculate/use
  1747.         const float drawBoxWidth = 200.0f;
  1748.         // update when current position is greater than this (horizontally)
  1749.         // distance from lastPos
  1750.         const float drawUpdateDist = drawBoxWidth * 0.25f;
  1751.         const float zOffset = 0.05f;
  1752.  
  1753.         CDebugDrawContext dc;
  1754.  
  1755.         Vec3 playerPos = dc->GetCameraPos();
  1756.         playerPos.z = 0.0f;
  1757.  
  1758.         if ((playerPos - currentPos).GetLength() > drawUpdateDist)
  1759.         {
  1760.                 currentPos = playerPos;
  1761.                 triangles.resize(0); // force a refresh
  1762.         }
  1763.         if (gAIEnv.CVars.DebugDraw != 85)
  1764.         {
  1765.                 triangles.resize(0);
  1766.                 return;
  1767.         }
  1768.  
  1769.         if (gEnv->IsEditor())
  1770.         {
  1771.                 triangles.resize(0);
  1772.         }
  1773.  
  1774.         float criticalSlopeUp = gAIEnv.CVars.SteepSlopeUpValue;
  1775.         float criticalSlopeAcross = gAIEnv.CVars.SteepSlopeAcrossValue;
  1776.  
  1777.         if (triangles.empty())
  1778.         {
  1779.                 I3DEngine* pEngine = gEnv->p3DEngine;
  1780.  
  1781.                 int terrainArraySize = pEngine->GetTerrainSize();
  1782.                 float dx = pEngine->GetHeightMapUnitSize();
  1783.  
  1784.                 float minX = currentPos.x - 0.5f * drawBoxWidth;
  1785.                 float minY = currentPos.y - 0.5f * drawBoxWidth;
  1786.                 float maxX = currentPos.x + 0.5f * drawBoxWidth;
  1787.                 float maxY = currentPos.y + 0.5f * drawBoxWidth;
  1788.                 int minIx = (int)(minX / dx);
  1789.                 int minIy = (int)(minY / dx);
  1790.                 int maxIx = (int)(maxX / dx);
  1791.                 int maxIy = (int)(maxY / dx);
  1792.                 Limit(minIx, 1, terrainArraySize - 1);
  1793.                 Limit(minIy, 1, terrainArraySize - 1);
  1794.                 Limit(maxIx, 1, terrainArraySize - 1);
  1795.                 Limit(maxIy, 1, terrainArraySize - 1);
  1796.  
  1797.                 // indices start at +1 so we can use the previous indices
  1798.                 for (int ix = minIx; ix < maxIx; ++ix)
  1799.                 {
  1800.                         for (int iy = minIy; iy < maxIy; ++iy)
  1801.                         {
  1802.                                 Vec3 v11(dx * ix, dx * iy, 0.0f);
  1803.                                 Vec3 v01(dx * (ix - 1), dx * iy, 0.0f);
  1804.                                 Vec3 v10(dx * ix, dx * (iy - 1), 0.0f);
  1805.                                 Vec3 v00(dx * (ix - 1), dx * (iy - 1), 0.0f);
  1806.  
  1807.                                 v11.z = zOffset + dc->GetDebugDrawZ(v11, true);
  1808.                                 v01.z = zOffset + dc->GetDebugDrawZ(v01, true);
  1809.                                 v10.z = zOffset + dc->GetDebugDrawZ(v10, true);
  1810.                                 v00.z = zOffset + dc->GetDebugDrawZ(v00, true);
  1811.  
  1812.                                 Vec3 n1 = ((v10 - v00) % (v01 - v00)).GetNormalized();
  1813.                                 float slope1 = fabs(sqrtf(1.0f - n1.z * n1.z) / n1.z);
  1814.                                 if (slope1 > criticalSlopeUp)
  1815.                                         triangles.push_back(SSlopeTriangle(Triangle(v00, v10, v01), slope1));
  1816.                                 else if (slope1 > criticalSlopeAcross)
  1817.                                         triangles.push_back(SSlopeTriangle(Triangle(v00, v10, v01), -slope1));
  1818.  
  1819.                                 Vec3 n2 = ((v11 - v10) % (v01 - v10)).GetNormalized();
  1820.                                 float slope2 = fabs(sqrtf(1.0f - n2.z * n2.z) / n2.z);
  1821.                                 if (slope2 > criticalSlopeUp)
  1822.                                         triangles.push_back(SSlopeTriangle(Triangle(v10, v11, v01), slope2));
  1823.                                 else if (slope2 > criticalSlopeAcross)
  1824.                                         triangles.push_back(SSlopeTriangle(Triangle(v10, v11, v01), -slope2));
  1825.                         }
  1826.                 }
  1827.         }
  1828.  
  1829.         unsigned int numTris = triangles.size();
  1830.         for (unsigned int i = 0; i < numTris; ++i)
  1831.         {
  1832.                 const SSlopeTriangle& tri = triangles[i];
  1833.                 ColorF color;
  1834.                 // convert slope into 0-1 (the z-value of a unit vector having that slope)
  1835.                 float slope = tri.slope > 0.0f ? tri.slope : -tri.slope;
  1836.                 float a = sqrtf(slope * slope / (1.0f + slope * slope));
  1837.                 if (tri.slope > 0.0f)
  1838.                         color.set(1.0f - 0.5f * a, 0.0f, 0.0f, 1.0f);
  1839.                 else
  1840.                         color.set(0.0f, 1.0f - 0.5f * a, 1.0f, 1.0f);
  1841.                 dc->DrawTriangle(tri.triangle.v0, color, tri.triangle.v1, color, tri.triangle.v2, color);
  1842.         }
  1843. }
  1844.  
  1845. //===================================================================
  1846. // DebugDrawVegetationCollision
  1847. //===================================================================
  1848. void CAISystem::DebugDrawVegetationCollision()
  1849. {
  1850.         FUNCTION_PROFILER(GetISystem(), PROFILE_AI);
  1851.  
  1852.         float range = gAIEnv.CVars.DebugDrawVegetationCollisionDist;
  1853.         if (range < 0.1f)
  1854.                 return;
  1855.  
  1856.         I3DEngine* pEngine = gEnv->p3DEngine;
  1857.  
  1858.         CDebugDrawContext dc;
  1859.  
  1860.         Vec3 playerPos = dc->GetCameraPos();
  1861.         playerPos.z = pEngine->GetTerrainElevation(playerPos.x, playerPos.y);
  1862.  
  1863.         AABB aabb(AABB::RESET);
  1864.         aabb.Add(playerPos + Vec3(range, range, range));
  1865.         aabb.Add(playerPos - Vec3(range, range, range));
  1866.  
  1867.         ColorB triCol(128, 255, 255);
  1868.         const float zOffset = 0.05f;
  1869.  
  1870.         IPhysicalEntity** pObstacles;
  1871.         int count = gAIEnv.pWorld->GetEntitiesInBox(aabb.min, aabb.max, pObstacles, ent_static | ent_ignore_noncolliding);
  1872.         for (int i = 0; i < count; ++i)
  1873.         {
  1874.                 IPhysicalEntity* pPhysics = pObstacles[i];
  1875.  
  1876.                 pe_status_pos status;
  1877.                 status.ipart = 0;
  1878.                 pPhysics->GetStatus(&status);
  1879.  
  1880.                 Vec3 obstPos = status.pos;
  1881.                 Matrix33 obstMat = Matrix33(status.q);
  1882.                 obstMat *= status.scale;
  1883.  
  1884.                 IGeometry* geom = status.pGeom;
  1885.                 int type = geom->GetType();
  1886.                 if (type == GEOM_TRIMESH)
  1887.                 {
  1888.                         const primitives::primitive* prim = geom->GetData();
  1889.                         const mesh_data* mesh = static_cast<const mesh_data*>(prim);
  1890.  
  1891.                         int numVerts = mesh->nVertices;
  1892.                         int numTris = mesh->nTris;
  1893.  
  1894.                         static std::vector<Vec3> vertices;
  1895.                         vertices.resize(numVerts);
  1896.  
  1897.                         for (int j = 0; j < numVerts; j++)
  1898.                                 vertices[j] = obstPos + obstMat * mesh->pVertices[j];
  1899.  
  1900.                         for (int j = 0; j < numTris; ++j)
  1901.                         {
  1902.                                 int vidx0 = mesh->pIndices[j * 3 + 0];
  1903.                                 int vidx1 = mesh->pIndices[j * 3 + 1];
  1904.                                 int vidx2 = mesh->pIndices[j * 3 + 2];
  1905.  
  1906.                                 Vec3 pt0 = vertices[vidx0];
  1907.                                 Vec3 pt1 = vertices[vidx1];
  1908.                                 Vec3 pt2 = vertices[vidx2];
  1909.  
  1910.                                 float z0 = pEngine->GetTerrainElevation(pt0.x, pt0.y);
  1911.                                 float z1 = pEngine->GetTerrainElevation(pt1.x, pt1.y);
  1912.                                 float z2 = pEngine->GetTerrainElevation(pt2.x, pt2.y);
  1913.  
  1914.                                 const float criticalAlt = 1.8f;
  1915.                                 if (pt0.z < z0 && pt1.z < z1 && pt2.z < z2)
  1916.                                         continue;
  1917.                                 if (pt0.z > z0 + criticalAlt && pt1.z > z1 + criticalAlt && pt2.z > z2 + criticalAlt)
  1918.                                         continue;
  1919.                                 pt0.z = z0 + zOffset;
  1920.                                 pt1.z = z1 + zOffset;
  1921.                                 pt2.z = z2 + zOffset;
  1922.  
  1923.                                 dc->DrawTriangle(pt0, triCol, pt1, triCol, pt2, triCol);
  1924.                         }
  1925.                 }
  1926.         }
  1927. }
  1928.  
  1929. struct SHidePos
  1930. {
  1931.         SHidePos(const Vec3& pos = ZERO, const Vec3& dir = Vec3Constants<float>::fVec3_Zero) : pos(pos), dir(dir) {}
  1932.         Vec3 pos;
  1933.         Vec3 dir;
  1934. };
  1935.  
  1936. struct SVolumeFunctor
  1937. {
  1938.         SVolumeFunctor(std::vector<SHidePos>& hidePositions) : hidePositions(hidePositions) {}
  1939.         void operator()(SVolumeHideSpot& hs, float) { hidePositions.push_back(SHidePos(hs.pos, hs.dir)); }
  1940.         std::vector<SHidePos>& hidePositions;
  1941. };
  1942.  
  1943. //====================================================================
  1944. // DebugDrawHideSpots
  1945. // need to evaluate all navigation/hide types
  1946. //====================================================================
  1947. void CAISystem::DebugDrawHideSpots()
  1948. {
  1949.         FUNCTION_PROFILER(GetISystem(), PROFILE_AI);
  1950.  
  1951.         float range = gAIEnv.CVars.DebugDrawHideSpotRange;
  1952.         if (range < 0.1f)
  1953.                 return;
  1954.  
  1955.         CDebugDrawContext dc;
  1956.  
  1957.         Vec3 playerPos = dc->GetCameraPos();
  1958.  
  1959.         Vec3 groundPos = playerPos;
  1960.         I3DEngine* pEngine = gEnv->p3DEngine;
  1961.         groundPos.z = pEngine->GetTerrainElevation(groundPos.x, groundPos.y);
  1962.         dc->DrawSphere(groundPos, 0.01f * (playerPos.z - groundPos.z), ColorB(255, 0, 0));
  1963.  
  1964.         MultimapRangeHideSpots hidespots;
  1965.         MapConstNodesDistance traversedNodes;
  1966.         // can't get SO since we have no entity...
  1967.         GetHideSpotsInRange(hidespots, traversedNodes, playerPos, range,
  1968.                             IAISystem::NAV_TRIANGULAR | IAISystem::NAV_WAYPOINT_HUMAN | IAISystem::NAV_WAYPOINT_3DSURFACE |
  1969.                             IAISystem::NAV_VOLUME | IAISystem::NAV_SMARTOBJECT, 0.0f, false, 0);
  1970.  
  1971.         /// for profiling (without draw overhead)
  1972.         const bool skipDrawing = false;
  1973.         if (skipDrawing)
  1974.                 return;
  1975.  
  1976.         for (MultimapRangeHideSpots::const_iterator it = hidespots.begin(); it != hidespots.end(); ++it)
  1977.         {
  1978.                 float distance = it->first;
  1979.                 const SHideSpot& hs = it->second;
  1980.  
  1981.                 const Vec3& pos = hs.info.pos;
  1982.                 Vec3 dir = hs.info.dir;
  1983.  
  1984.                 const float radius = 0.3f;
  1985.                 const float height = 0.3f;
  1986.                 const float triHeight = 5.0f;
  1987.                 int alpha = 255;
  1988.                 if (hs.pObstacle && !hs.pObstacle->IsCollidable())
  1989.                 {
  1990.                         alpha = 128;
  1991.                 }
  1992.                 else if (hs.pAnchorObject && hs.pAnchorObject->GetType() == AIANCHOR_COMBAT_HIDESPOT_SECONDARY)
  1993.                 {
  1994.                         alpha = 128;
  1995.                         dir.zero();
  1996.                 }
  1997.                 dc->DrawSphere(pos, 0.2f * radius, ColorB(0, 255, 0, alpha));
  1998.                 if (dir.IsZero())
  1999.                         dc->DrawCone(pos + Vec3(0, 0, triHeight), Vec3(0, 0, -1), radius, triHeight, ColorB(0, 255, 0, alpha));
  2000.                 else
  2001.                         dc->DrawCone(pos + height * dir, -dir, radius, height, ColorB(0, 255, 0, alpha));
  2002.  
  2003.         }
  2004.  
  2005.         // INTEGRATION : (MATT) These yellow cones kindof get in the way in G04 but handy for Crysis I believe {2007/05/31:17:29:30}
  2006.         ColorB color(255, 255, 0);
  2007.         for (MapConstNodesDistance::const_iterator it = traversedNodes.begin(); it != traversedNodes.end(); ++it)
  2008.         {
  2009.                 const GraphNode* pNode = it->first;
  2010.                 float dist = it->second;
  2011.                 Vec3 pos = pNode->GetPos();
  2012.                 float radius = 0.3f;
  2013.                 float coneHeight = 1.0f;
  2014.                 dc->DrawCone(pos + Vec3(0, 0, coneHeight), Vec3(0, 0, -1), radius, coneHeight, ColorB(255, 255, 0, 100));
  2015.                 dc->Draw3dLabelEx(pos + Vec3(0, 0, 0.3f), 1.0f, color, true, false, false, false, "%5.2f", dist);
  2016.         }
  2017. }
  2018.  
  2019. //====================================================================
  2020. // DebugDrawDynamicHideObjects
  2021. //====================================================================
  2022. void CAISystem::DebugDrawDynamicHideObjects()
  2023. {
  2024.         FUNCTION_PROFILER(GetISystem(), PROFILE_AI);
  2025.  
  2026.         float range = gAIEnv.CVars.DebugDrawDynamicHideObjectsRange;
  2027.         if (range < 0.1f)
  2028.                 return;
  2029.  
  2030.         Vec3 cameraPos = GetISystem()->GetViewCamera().GetPosition();
  2031.         Vec3 cameraDir = GetISystem()->GetViewCamera().GetViewdir();
  2032.  
  2033.         Vec3 pos = cameraPos + cameraDir * (range / 2);
  2034.         Vec3 size(range / 2, range / 2, range / 2);
  2035.  
  2036.         SEntityProximityQuery query;
  2037.         query.box.min = pos - size;
  2038.         query.box.max = pos + size;
  2039.         query.nEntityFlags = (uint32)ENTITY_FLAG_AI_HIDEABLE; // Filter by entity flag.
  2040.  
  2041.         CDebugDrawContext dc;
  2042.         gEnv->pEntitySystem->QueryProximity(query);
  2043.         for (int i = 0; i < query.nCount; ++i)
  2044.         {
  2045.                 IEntity* pEntity = query.pEntities[i];
  2046.                 if (!pEntity) continue;
  2047.  
  2048.                 AABB bbox;
  2049.                 pEntity->GetLocalBounds(bbox);
  2050.                 dc->DrawAABB(bbox, pEntity->GetWorldTM(), true, ColorB(255, 0, 0, 128), eBBD_Faceted);
  2051.         }
  2052.  
  2053.         m_dynHideObjectManager.DebugDraw();
  2054. }
  2055.  
  2056. //====================================================================
  2057. // DebugDrawGraphErrors
  2058. //====================================================================
  2059. void CAISystem::DebugDrawGraphErrors(CGraph* pGraph) const
  2060. {
  2061.         FUNCTION_PROFILER(GetISystem(), PROFILE_AI);
  2062.  
  2063.         CDebugDrawContext dc;
  2064.  
  2065.         unsigned int numErrors = pGraph->mBadGraphData.size();
  2066.  
  2067.         std::vector<Vec3> positions;
  2068.         const float minRadius = 0.1f;
  2069.         const float maxRadius = 2.0f;
  2070.         const int numCircles = 2;
  2071.         for (unsigned int iError = 0; iError < numErrors; ++iError)
  2072.         {
  2073.                 const CGraph::SBadGraphData& error = pGraph->mBadGraphData[iError];
  2074.                 Vec3 errorPos1 = error.mPos1;
  2075.                 errorPos1.z = dc->GetDebugDrawZ(errorPos1, true);
  2076.                 Vec3 errorPos2 = error.mPos2;
  2077.                 errorPos2.z = dc->GetDebugDrawZ(errorPos2, true);
  2078.  
  2079.                 positions.push_back(errorPos1);
  2080.  
  2081.                 switch (error.mType)
  2082.                 {
  2083.                 case CGraph::SBadGraphData::BAD_PASSABLE:
  2084.                         dc->DrawCircles(errorPos1, minRadius, maxRadius, numCircles, Vec3(1, 0, 0), Vec3(1, 1, 0));
  2085.                         dc->DrawCircles(errorPos2, minRadius, maxRadius, numCircles, Vec3(1, 0, 0), Vec3(1, 1, 0));
  2086.                         dc->DrawLine(errorPos1, ColorB(255, 255, 0), errorPos2, ColorB(255, 255, 0));
  2087.                         break;
  2088.                 case CGraph::SBadGraphData::BAD_IMPASSABLE:
  2089.                         dc->DrawCircles(errorPos1, minRadius, maxRadius, numCircles, Vec3(0, 1, 0), Vec3(1, 1, 0));
  2090.                         dc->DrawCircles(errorPos2, minRadius, maxRadius, numCircles, Vec3(0, 1, 0), Vec3(1, 1, 0));
  2091.                         dc->DrawLine(errorPos1, ColorB(255, 255, 0), errorPos2, ColorB(255, 255, 0));
  2092.                         break;
  2093.                 }
  2094.         }
  2095.         const float errorRadius = 10.0f;
  2096.         // draw the basic graph just in this region
  2097.         DebugDrawGraph(m_pGraph, &positions, errorRadius);
  2098. }
  2099.  
  2100. //====================================================================
  2101. // CheckDistance
  2102. //====================================================================
  2103. static inline bool CheckDistance(const Vec3 pos1, const std::vector<Vec3>* focusPositions, float radius)
  2104. {
  2105.         if (!focusPositions)
  2106.                 return true;
  2107.         const std::vector<Vec3>& positions = *focusPositions;
  2108.  
  2109.         for (unsigned int i = 0; i < positions.size(); ++i)
  2110.         {
  2111.                 Vec3 delta = pos1 - positions[i];
  2112.                 delta.z = 0.0f;
  2113.                 if (delta.GetLengthSquared() < radius * radius)
  2114.                         return true;
  2115.         }
  2116.         return false;
  2117. }
  2118.  
  2119. // A bit ugly, but make this global - it caches the debug graph that needs to be drawn.
  2120. // If it's empty then DebugDrawGraph tries to fill it. Otherwise we just draw it
  2121. // It will get zeroed when the graph is regenerated.
  2122. std::vector<const GraphNode*> g_DebugGraphNodesToDraw;
  2123. static CGraph* lastDrawnGraph = 0; // detects swapping between hide and nav
  2124.  
  2125. //====================================================================
  2126. // DebugDrawGraph
  2127. //====================================================================
  2128. void CAISystem::DebugDrawGraph(CGraph* pGraph, const std::vector<Vec3>* focusPositions, float focusRadius) const
  2129. {
  2130.         FUNCTION_PROFILER(GetISystem(), PROFILE_AI);
  2131.  
  2132.         //      if (pGraph != lastDrawnGraph)
  2133.         {
  2134.                 lastDrawnGraph = pGraph;
  2135.                 g_DebugGraphNodesToDraw.clear();
  2136.         }
  2137.  
  2138.         if (g_DebugGraphNodesToDraw.empty())
  2139.         {
  2140.                 CAllNodesContainer& allNodes = pGraph->GetAllNodes();
  2141.                 CAllNodesContainer::Iterator it(allNodes, NAV_TRIANGULAR | NAV_WAYPOINT_HUMAN | NAV_WAYPOINT_3DSURFACE | NAV_VOLUME | NAV_ROAD | NAV_SMARTOBJECT | NAV_CUSTOM_NAVIGATION);
  2142.                 while (unsigned currentNodeIndex = it.Increment())
  2143.                 {
  2144.                         GraphNode* pCurrent = pGraph->GetNodeManager().GetNode(currentNodeIndex);
  2145.  
  2146.                         g_DebugGraphNodesToDraw.push_back(pCurrent);
  2147.                 }
  2148.         }
  2149.         // now just render
  2150.         const bool renderPassRadii = false;
  2151.         const float ballRad = 0.04f;
  2152.  
  2153.         CDebugDrawContext dc;
  2154.  
  2155.         unsigned int nNodes = g_DebugGraphNodesToDraw.size();
  2156.         for (unsigned int iNode = 0; iNode < nNodes; ++iNode)
  2157.         {
  2158.                 const GraphNode* node = g_DebugGraphNodesToDraw[iNode];
  2159.                 AIAssert(node);
  2160.  
  2161.                 ColorB color(0, 0, 0);
  2162.                 Vec3 pos = node->GetPos();
  2163.                 pos.z = dc->GetDebugDrawZ(pos, node->navType == IAISystem::NAV_TRIANGULAR);
  2164.  
  2165.                 switch (node->navType)
  2166.                 {
  2167.                 case IAISystem::NAV_TRIANGULAR:
  2168.                         {
  2169.                                 // NAV_TRIANGULAR is not supported anymore, it's replaced by MNM.
  2170.                                 assert(false);
  2171.                         }
  2172.                         break;
  2173.  
  2174.                 case IAISystem::NAV_ROAD:
  2175.                         {
  2176.                                 color.set(255, 255, 255, 255);
  2177.                                 dc->DrawSphere(pos, ballRad * 3, color);
  2178.                         }
  2179.                         break;
  2180.  
  2181.                 case IAISystem::NAV_CUSTOM_NAVIGATION:
  2182.                         {
  2183.                                 color.set(255, 255, 255, 255);
  2184.                                 dc->DrawSphere(pos + Vec3(0.0f, 0.0f, 0.5f), ballRad * 3.0f, color);
  2185.                         }
  2186.                         break;
  2187.  
  2188.                 // Cover all other cases to provide a real view of the graph
  2189.                 default:
  2190.                         {
  2191.                                 color.set(255, 0, 255, 255);
  2192.                                 dc->Draw3dLabelEx(pos + Vec3(0.0f, 0.0f, 0.7f), 2.0f, ColorB(255, 255, 0), true, false, false, false, "T:%x", node->navType);
  2193.                                 dc->DrawSphere(pos + Vec3(0.0f, 0.0f, 0.5f), ballRad * 4.0f, color);
  2194.                         }
  2195.                         break;
  2196.                 }
  2197.  
  2198.                 for (unsigned link = node->firstLinkIndex; link; link = pGraph->GetLinkManager().GetNextLink(link))
  2199.                 {
  2200.                         unsigned int nextIndex = pGraph->GetLinkManager().GetNextNode(link);
  2201.                         const GraphNode* next = pGraph->GetNodeManager().GetNode(nextIndex);
  2202.                         AIAssert(next);
  2203.  
  2204.                         ColorB endColor;
  2205.                         if (pGraph->GetLinkManager().GetRadius(link) > 0.0f)
  2206.                                 endColor = ColorB(255, 255, 255);
  2207.                         else
  2208.                                 endColor = ColorB(0, 0, 0);
  2209.  
  2210.                         if (CheckDistance(pos, focusPositions, focusRadius))
  2211.                         {
  2212.                                 Vec3 v0 = node->GetPos();
  2213.                                 Vec3 v1 = next->GetPos();
  2214.                                 v0.z = dc->GetDebugDrawZ(v0, node->navType == IAISystem::NAV_TRIANGULAR);
  2215.                                 v1.z = dc->GetDebugDrawZ(v1, node->navType == IAISystem::NAV_TRIANGULAR);
  2216.                                 if (pGraph->GetLinkManager().GetStartIndex(link) != pGraph->GetLinkManager().GetEndIndex(link))
  2217.                                 {
  2218.                                         Vec3 mid = pGraph->GetLinkManager().GetEdgeCenter(link);
  2219.                                         mid.z = dc->GetDebugDrawZ(mid, node->navType == IAISystem::NAV_TRIANGULAR);
  2220.                                         dc->DrawLine(v0, endColor, mid, ColorB(0, 255, 255));
  2221.                                         if (renderPassRadii)
  2222.                                                 dc->Draw3dLabel(mid, 1, "%.2f", pGraph->GetLinkManager().GetRadius(link));
  2223.  
  2224.                                         int debugDrawVal = gAIEnv.CVars.DebugDraw;
  2225.                                         if (debugDrawVal == 179)
  2226.                                                 dc->Draw3dLabel(mid, 2, "%x", link);
  2227.                                         else if (debugDrawVal == 279)
  2228.                                         {
  2229.                                                 float waterDepth = pGraph->GetLinkManager().GetMaxWaterDepth(link);
  2230.                                                 if (waterDepth > 0.6f)
  2231.                                                 {
  2232.                                                         dc->Draw3dLabelEx(mid, 1, ColorB(255, 0, 0), true, false, false, false, "%.2f", waterDepth);
  2233.                                                 }
  2234.                                                 else
  2235.                                                 {
  2236.                                                         dc->Draw3dLabelEx(mid, 1, ColorB(255, 255, 255), true, false, false, false, "%.2f", waterDepth);
  2237.                                                 }
  2238.                                         }
  2239.                                 }
  2240.                                 else
  2241.                                 {
  2242.                                         dc->DrawLine(v0 + Vec3(0, 0, 0.5), endColor, v1 + Vec3(0, 0, 0.5), endColor);
  2243.                                         if (renderPassRadii)
  2244.                                         {
  2245.                                                 dc->Draw3dLabel(0.5f * (v0 + v1), 1, "%.2f", pGraph->GetLinkManager().GetRadius(link));
  2246.                                         }
  2247.                                 }
  2248.                         } // range check
  2249.                 }
  2250.         }
  2251. }
  2252.  
  2253. //
  2254. //-----------------------------------------------------------------------------------------------------------
  2255. void CAISystem::DebugDrawPath()
  2256. {
  2257.         FUNCTION_PROFILER(GetISystem(), PROFILE_AI);
  2258.  
  2259.         const char* pName = gAIEnv.CVars.DrawPath;
  2260.         if (!pName)
  2261.                 return;
  2262.         CAIObject* pTargetObject = gAIEnv.pAIObjectManager->GetAIObjectByName(pName);
  2263.         if (pTargetObject)
  2264.         {
  2265.                 CPipeUser* pTargetPipeUser = pTargetObject->CastToCPipeUser();
  2266.                 if (!pTargetPipeUser)
  2267.                         return;
  2268.                 DebugDrawPathSingle(pTargetPipeUser);
  2269.                 return;
  2270.         }
  2271.         if (strcmp(pName, "all"))
  2272.                 return;
  2273.         const CAISystem::AIActorSet& enabledAIActorsSet = GetAISystem()->GetEnabledAIActorSet();
  2274.         for (CAISystem::AIActorSet::const_iterator it = enabledAIActorsSet.begin(), itEnd = enabledAIActorsSet.end(); it != itEnd; ++it)
  2275.         {
  2276.                 CAIActor* pAIActor = it->GetAIObject();
  2277.                 if (!pAIActor)
  2278.                         continue;
  2279.  
  2280.                 CPipeUser* pPipeUser = pAIActor->CastToCPipeUser();
  2281.                 if (!pPipeUser)
  2282.                         continue;
  2283.  
  2284.                 DebugDrawPathSingle(pPipeUser);
  2285.         }
  2286. }
  2287.  
  2288. //===================================================================
  2289. // DebugDrawPathAdjustments
  2290. //===================================================================
  2291. void CAISystem::DebugDrawPathAdjustments() const
  2292. {
  2293.         FUNCTION_PROFILER(GetISystem(), PROFILE_AI);
  2294.  
  2295.         const char* pName = gAIEnv.CVars.DrawPathAdjustment;
  2296.         if (!pName)
  2297.                 return;
  2298.         CAIObject* pTargetObject = gAIEnv.pAIObjectManager->GetAIObjectByName(pName);
  2299.         if (pTargetObject)
  2300.         {
  2301.                 if (CPuppet* pTargetPuppet = pTargetObject->CastToCPuppet())
  2302.                         pTargetPuppet->GetPathAdjustmentObstacles(false).DebugDraw();
  2303.                 if (CAIVehicle* pTargetVehicle = pTargetObject->CastToCAIVehicle())
  2304.                         pTargetVehicle->GetPathAdjustmentObstacles(false).DebugDraw();
  2305.                 return;
  2306.         }
  2307.         if (strcmp(pName, "all"))
  2308.                 return;
  2309.         // find if there are any puppets
  2310.         int cnt = 0;
  2311.         AIObjectOwners::const_iterator ai;
  2312.         if ((ai = gAIEnv.pAIObjectManager->m_Objects.find(AIOBJECT_ACTOR)) != gAIEnv.pAIObjectManager->m_Objects.end())
  2313.         {
  2314.                 for (; ai != gAIEnv.pAIObjectManager->m_Objects.end(); ++ai)
  2315.                 {
  2316.                         if (ai->first != AIOBJECT_ACTOR)
  2317.                                 break;
  2318.                         cnt++;
  2319.                         CPuppet* pPuppet = (CPuppet*)ai->second.GetAIObject();
  2320.                         pPuppet->GetPathAdjustmentObstacles(false).DebugDraw();
  2321.                 }
  2322.         }
  2323.         if ((ai = gAIEnv.pAIObjectManager->m_Objects.find(AIOBJECT_VEHICLE)) != gAIEnv.pAIObjectManager->m_Objects.end())
  2324.         {
  2325.                 for (; ai != gAIEnv.pAIObjectManager->m_Objects.end(); ++ai)
  2326.                 {
  2327.                         if (ai->first != AIOBJECT_VEHICLE)
  2328.                                 break;
  2329.                         cnt++;
  2330.                         CAIVehicle* pVehicle = (CAIVehicle*)ai->second.GetAIObject();
  2331.                         pVehicle->GetPathAdjustmentObstacles(false).DebugDraw();
  2332.                 }
  2333.         }
  2334. }
  2335.  
  2336. //
  2337. //-----------------------------------------------------------------------------------------------------------
  2338. void CAISystem::DebugDrawPathSingle(const CPipeUser* pPipeUser) const
  2339. {
  2340.         FUNCTION_PROFILER(GetISystem(), PROFILE_AI);
  2341.  
  2342.         if (!pPipeUser->IsEnabled())
  2343.                 return;
  2344.  
  2345.         // debug path draws all the path
  2346.         // m_Path gets nodes popped off the front...
  2347.         pPipeUser->m_Path.Draw();
  2348.         if (pPipeUser->m_pPathFollower)
  2349.                 pPipeUser->m_pPathFollower->Draw();
  2350.  
  2351.         // draw the first part of the path in a different colour
  2352.         if (!pPipeUser->m_OrigPath.GetPath().empty())
  2353.         {
  2354.                 TPathPoints::const_iterator li, linext;
  2355.                 li = pPipeUser->m_OrigPath.GetPath().begin();
  2356.                 linext = li;
  2357.                 ++linext;
  2358.                 Vec3 endPt = pPipeUser->m_Path.GetNextPathPos();
  2359.                 CDebugDrawContext dc;
  2360.                 while (linext != pPipeUser->m_OrigPath.GetPath().end())
  2361.                 {
  2362.                         Vec3 p0 = li->vPos;
  2363.                         Vec3 p1 = linext->vPos;
  2364.                         p0.z = dc->GetDebugDrawZ(p0, li->navType == IAISystem::NAV_TRIANGULAR);
  2365.                         p1.z = dc->GetDebugDrawZ(p1, li->navType == IAISystem::NAV_TRIANGULAR);
  2366.                         dc->DrawLine(p0, ColorB(255, 0, 255), p1, ColorB(255, 0, 255));
  2367.                         endPt.z = li->vPos.z;
  2368.                         if (endPt.IsEquivalent(li->vPos, 0.1f))
  2369.                                 break;
  2370.                         li = linext++;
  2371.                 }
  2372.         }
  2373. }
  2374.  
  2375. //
  2376. //-----------------------------------------------------------------------------------------------------------
  2377. void CAISystem::DebugDrawAgents() const
  2378. {
  2379.         FUNCTION_PROFILER(GetISystem(), PROFILE_AI);
  2380.  
  2381.         if (gAIEnv.CVars.AgentStatsDist <= 1.0f)
  2382.                 return;
  2383.  
  2384.         bool filterName = strcmp("", gAIEnv.CVars.FilterAgentName) != 0;
  2385.  
  2386.         CDebugDrawContext dc;
  2387.         const float drawDistSq = sqr(gAIEnv.CVars.AgentStatsDist);
  2388.  
  2389.         CryFixedArray<GroupID, 128> enabledGroups;
  2390.  
  2391.         stack_string groups = gAIEnv.CVars.DrawAgentStatsGroupFilter;
  2392.  
  2393.         if (!groups.empty())
  2394.         {
  2395.                 int start = 0;
  2396.                 stack_string groupIDFilter = groups.Tokenize(", ", start);
  2397.  
  2398.                 while (!groupIDFilter.empty())
  2399.                 {
  2400.                         char* end;
  2401.                         GroupID groupID = strtol(groupIDFilter.c_str(), &end, 0);
  2402.  
  2403.                         stl::push_back_unique(enabledGroups, groupID);
  2404.                         groupIDFilter = groups.Tokenize(":", start);
  2405.                 }
  2406.         }
  2407.  
  2408.         const CAISystem::AIActorSet& enabledAIActorsSet = GetAISystem()->GetEnabledAIActorSet();
  2409.         for (CAISystem::AIActorSet::const_iterator it = enabledAIActorsSet.begin(), itEnd = enabledAIActorsSet.end(); it != itEnd; ++it)
  2410.         {
  2411.                 CAIActor* pAIActor = it->GetAIObject();
  2412.                 if (!pAIActor)
  2413.                         continue;
  2414.  
  2415.                 float distSq = (dc->GetCameraPos() - pAIActor->GetPos()).GetLengthSquared();
  2416.                 if (distSq > drawDistSq)
  2417.                         continue;
  2418.  
  2419.                 if ((!enabledGroups.size() || (std::find(enabledGroups.begin(), enabledGroups.end(), pAIActor->GetGroupId()) != enabledGroups.end())) &&
  2420.                     !filterName || !strcmp(pAIActor->GetName(), gAIEnv.CVars.FilterAgentName))
  2421.                         DebugDrawAgent(pAIActor);
  2422.         }
  2423.  
  2424.         // output all vehicles
  2425.         const AIObjectOwners& objects = gAIEnv.pAIObjectManager->m_Objects;
  2426.         AIObjectOwners::const_iterator ai = objects.find(AIOBJECT_VEHICLE);
  2427.         for (; ai != objects.end(); ++ai)
  2428.         {
  2429.                 if (ai->first != AIOBJECT_VEHICLE)
  2430.                         break;
  2431.  
  2432.                 float distSq = (dc->GetCameraPos() - (ai->second.GetAIObject())->GetPos()).GetLengthSquared();
  2433.                 if (distSq > drawDistSq)
  2434.                         continue;
  2435.  
  2436.                 CAIObject* aiObject = ai->second.GetAIObject();
  2437.  
  2438.                 if (aiObject &&
  2439.                     ((!enabledGroups.size() || (std::find(enabledGroups.begin(), enabledGroups.end(), aiObject->GetGroupId(&