BVB Source Codes

CRYENGINE Show AIGroup.cpp Source code

Return Download CRYENGINE: download AIGroup.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:   AIGroup.cpp
  6.    $Id$
  7.    Description:
  8.  
  9.    -------------------------------------------------------------------------
  10.    History:
  11.    - 2006                               : Created by Mikko Mononen
  12.  
  13.  *********************************************************************/
  14.  
  15. #include "StdAfx.h"
  16. #include <CryAISystem/IAISystem.h>
  17. #include "CAISystem.h"
  18. #include "AIPlayer.h"
  19. #include "AIGroup.h"
  20. #include "Puppet.h"
  21. #include "AIVehicle.h"
  22. #include <float.h>
  23. #include "DebugDrawContext.h"
  24.  
  25. // Serialises a container of AI references
  26. // Perhaps this is too heavy on the templating and it could be virtualised
  27. template<class T>
  28. bool SerializeWeakRefVector(TSerialize ser, const char* containerName, std::vector<CWeakRef<T>>& container)
  29. {
  30.         ser.BeginGroup(containerName);
  31.         unsigned numItems = container.size();
  32.         ser.Value("numItems", numItems);
  33.         if (ser.IsReading())
  34.                 container.resize(numItems);
  35.  
  36.         for (typename std::vector<CWeakRef<T>>::iterator itr(container.begin()); itr != container.end(); ++itr)
  37.         {
  38.                 ser.BeginGroup("i");
  39.                 itr->Serialize(ser, "v");
  40.                 ser.EndGroup();
  41.         }
  42.         ser.EndGroup();
  43.         return true;
  44. }
  45.  
  46. //====================================================================
  47. // CAIGroup
  48. //====================================================================
  49. CAIGroup::CAIGroup(int groupID) :
  50.         m_groupID(groupID),
  51.         m_pLeader(0),
  52.         m_bUpdateEnemyStats(true),
  53.         m_vEnemyPositionKnown(0, 0, 0),
  54.         m_vAverageEnemyPosition(0, 0, 0),
  55.         m_vAverageLiveEnemyPosition(0, 0, 0),
  56.         m_countMax(0),
  57.         m_countEnabledMax(0),
  58.         m_reinforcementSpotsAcquired(false),
  59.         m_reinforcementState(REINF_NONE),
  60.         m_countDead(0),
  61.         m_countCheckedDead(0),
  62.         m_count(0),
  63.         m_countEnabled(0),
  64.         m_reinforcementSpotsAllAlerted(0),
  65.         m_reinforcementSpotsCombat(0),
  66.         m_reinforcementSpotsBodyCount(0),
  67.         m_pendingDecSpotsAllAlerted(false),
  68.         m_pendingDecSpotsCombat(false),
  69.         m_pendingDecSpotsBodyCount(false)
  70. {
  71.         CCCPOINT(CAIGroup_CAIGroup)
  72. }
  73.  
  74. //====================================================================
  75. // ~CAIGroup
  76. //====================================================================
  77. CAIGroup::~CAIGroup()
  78. {
  79.         CCCPOINT(CAIGroup_Destructor)
  80. }
  81.  
  82. //====================================================================
  83. // SetLeader
  84. //====================================================================
  85. void CAIGroup::SetLeader(CLeader* pLeader)
  86. {
  87.         CCCPOINT(CAIGroup_SetLeader)
  88.         m_pLeader = pLeader;
  89.         if (pLeader)
  90.                 pLeader->SetAIGroup(this);
  91. }
  92.  
  93. //====================================================================
  94. // GetLeader
  95. //====================================================================
  96. CLeader* CAIGroup::GetLeader()
  97. {
  98.         return m_pLeader;
  99. }
  100.  
  101. //====================================================================
  102. // AddMember
  103. //====================================================================
  104. void CAIGroup::AddMember(CAIActor* pMember)
  105. {
  106.         CCCPOINT(CAIGroup_AddMember)
  107.  
  108.         // everywhere assumes that pMember is non-null
  109.         AIAssert(pMember);
  110.         // check if it's already a member of team
  111.         if (GetUnit(pMember) != m_Units.end())
  112.                 return;
  113.         CUnitImg newUnit;
  114.         newUnit.m_refUnit = GetWeakRef(pMember);
  115.         SetUnitClass(newUnit);
  116.  
  117.         IEntity* pEntity = pMember->GetEntity();
  118.         if (pEntity)
  119.         {
  120.                 IPhysicalEntity* pPhysEntity = pEntity->GetPhysics();
  121.                 if (pPhysEntity)
  122.                 {
  123.                         CCCPOINT(CAIGroup_AddMember_Phys)
  124.  
  125.                         float radius;
  126.                         pe_status_pos status;
  127.                         pPhysEntity->GetStatus(&status);
  128.                         radius = fabsf(status.BBox[1].x - status.BBox[0].x);
  129.                         float radius2 = fabsf(status.BBox[1].y - status.BBox[0].y);
  130.                         if (radius < radius2)
  131.                                 radius = radius2;
  132.                         float myHeight = status.BBox[1].z - status.BBox[0].z;
  133.                         newUnit.SetWidth(radius);
  134.                         newUnit.SetHeight(myHeight);
  135.                 }
  136.         }
  137.         m_Units.push_back(newUnit);
  138.  
  139.         if (m_pLeader)
  140.         {
  141.                 m_pLeader->AddUnitNotify(pMember);
  142.         }
  143. }
  144.  
  145. //====================================================================
  146. // RemoveMember
  147. //====================================================================
  148. bool CAIGroup::RemoveMember(CAIActor* pMember)
  149. {
  150.         if (!pMember)
  151.                 return false;
  152.  
  153.         CCCPOINT(CAIGroup_RemoveMember);
  154.  
  155.         // (MATT) This will need cleanup {2009/02/12}
  156.         if (m_refReinfPendingUnit == pMember)
  157.                 NotifyReinfDone(pMember, false);
  158.  
  159.         if (pMember->GetProxy() && pMember->GetProxy()->IsDead())
  160.                 m_countDead++;
  161.  
  162.         TUnitList::iterator theUnit = std::find(m_Units.begin(), m_Units.end(), pMember);
  163.  
  164.         if (m_pLeader)
  165.         {
  166.                 CAIActor* pMemberActor = pMember->CastToCAIActor();
  167.                 if (m_pLeader->GetFormationOwner() == pMember && pMemberActor->GetGroupId() == m_pLeader->GetGroupId())
  168.                         m_pLeader->ReleaseFormation();
  169.  
  170.                 if (m_pLeader->GetAssociation() == pMember)
  171.                         m_pLeader->SetAssociation(NILREF);
  172.         }
  173.  
  174.         LeaveAllGroupScopesForActor(pMember);
  175.  
  176.         if (theUnit != m_Units.end())
  177.         {
  178.                 m_Units.erase(theUnit);
  179.                 if (m_pLeader)
  180.                 {
  181.                         // if empty group - remove the leader; nobody owns it, will hang there forever
  182.                         // ok, don't remove leader here - all serialization issues are taken care of; make sure chain-loading is fine
  183.                         //                      if(m_Units.empty())
  184.                         //                      {
  185.                         //                              if(deleting)
  186.                         //                              {
  187.                         //                                      GetAISystem()->RemoveObject(m_pLeader);
  188.                         //                                      m_pLeader = 0;
  189.                         //                              }
  190.                         //                      }
  191.                         //                      else
  192.                         if (!m_Units.empty())
  193.                         {
  194.                                 m_pLeader->DeadUnitNotify(pMember);
  195.                         }
  196.                 }
  197.                 m_bUpdateEnemyStats = true;
  198.  
  199.                 return true;
  200.         }
  201.         return false;
  202. }
  203.  
  204. //====================================================================
  205. // NotifyBodyChecked
  206. //====================================================================
  207. void CAIGroup::NotifyBodyChecked(const CAIObject* pObject)
  208. {
  209.         m_countCheckedDead++;
  210. }
  211.  
  212. //====================================================================
  213. // GetUnit
  214. //====================================================================
  215. TUnitList::iterator CAIGroup::GetUnit(const CAIActor* pAIObject)
  216. {
  217.         CCCPOINT(CAIGroup_GetUnit);
  218.         return std::find(m_Units.begin(), m_Units.end(), pAIObject);
  219. }
  220.  
  221. //====================================================================
  222. // SetUnitClass
  223. //====================================================================
  224. void CAIGroup::SetUnitClass(CUnitImg& UnitImg) const
  225. {
  226. #ifdef USE_DEPRECATED_AI_CHARACTER_SYSTEM
  227.         CAIObject* const pObject = UnitImg.m_refUnit.GetAIObject();
  228.         IEntity* const pEntity = (pObject ? pObject->GetEntity() : NULL);
  229.         if (pEntity)
  230.         {
  231.                 IScriptTable* pTable = pEntity->GetScriptTable();
  232.                 SmartScriptTable pEntityProperties;
  233.                 if (pTable && pTable->GetValue("Properties", pEntityProperties))
  234.                 {
  235.                         const char* sCharacter = NULL;
  236.                         pEntityProperties->GetValue("aicharacter_character", sCharacter);
  237.                         IScriptSystem* pSS = pTable->GetScriptSystem();
  238.                         if (pSS)
  239.                         {
  240.                                 SmartScriptTable pGlobalCharacterTable;
  241.                                 if (pSS->GetGlobalValue("AICharacter", pGlobalCharacterTable))
  242.                                 {
  243.                                         SmartScriptTable pMyCharacterTable;
  244.                                         if (pGlobalCharacterTable->GetValue(sCharacter, pMyCharacterTable))
  245.                                         {
  246.                                                 int soldierClass;
  247.                                                 if (pMyCharacterTable->GetValue("Class", soldierClass))
  248.                                                 {
  249.                                                         CCCPOINT(CAIGroup_SetUnitClass);
  250.  
  251.                                                         UnitImg.SetClass(static_cast<int>(soldierClass));
  252.                                                         return;
  253.                                                 }
  254.                                         }
  255.                                 }
  256.                         }
  257.                 }
  258.         }
  259. #endif
  260.         UnitImg.SetClass(UNIT_CLASS_UNDEFINED);
  261. }
  262.  
  263. //====================================================================
  264. // IsMember
  265. //====================================================================
  266. bool CAIGroup::IsMember(const IAIObject* pMember) const
  267. {
  268.         const CAIActor* pActor = pMember->CastToCAIActor();
  269.         for (TUnitList::const_iterator itUnit = m_Units.begin(); itUnit != m_Units.end(); ++itUnit)
  270.                 if ((*itUnit) == pActor)
  271.                         return true;
  272.         return false;
  273. }
  274.  
  275. //====================================================================
  276. // SetUnitProperties
  277. //====================================================================
  278. void CAIGroup::SetUnitProperties(const IAIObject* obj, uint32 properties)
  279. {
  280.         const CAIActor* pActor = obj->CastToCAIActor();
  281.         TUnitList::iterator senderUnit = std::find(m_Units.begin(), m_Units.end(), pActor);
  282.  
  283.         if (senderUnit != m_Units.end())
  284.                 senderUnit->SetProperties(properties);
  285. }
  286.  
  287. //====================================================================
  288. // GetAveragePosition
  289. //====================================================================
  290. Vec3 CAIGroup::GetAveragePosition(IAIGroup::eAvPositionMode mode, uint32 unitClassMask) const
  291. {
  292.         // (MATT) Restructured this {2009/02/13}
  293.  
  294.         int count = 0;
  295.         Vec3 average(ZERO);
  296.         TUnitList::const_iterator it, itEnd = m_Units.end();
  297.         for (it = m_Units.begin(); it != itEnd; ++it)
  298.         {
  299.                 CAIObject* const pUnit = it->m_refUnit.GetAIObject();
  300.                 if (!pUnit->IsEnabled())
  301.                         continue;
  302.                 bool bInclude = false;
  303.  
  304.                 switch (mode)
  305.                 {
  306.                 case AVMODE_ANY:
  307.                         bInclude = true;
  308.                         break;
  309.                 case AVMODE_CLASS:
  310.                         bInclude = (it->GetClass() & unitClassMask) != 0;
  311.                         break;
  312.                 case AVMODE_PROPERTIES:
  313.                         bInclude = (it->GetProperties() & unitClassMask) != 0;
  314.                         break;
  315.                 default:
  316.                         break;
  317.                 }
  318.  
  319.                 CCCPOINT(CAIGroup_GetAveragePosition);
  320.  
  321.                 if (bInclude)
  322.                 {
  323.                         ++count;
  324.                         average += pUnit->GetPos();
  325.                 }
  326.         }
  327.         return (count ? average / float(count) : average);
  328. }
  329.  
  330. //====================================================================
  331. // GetUnitCount
  332. //====================================================================
  333. int CAIGroup::GetUnitCount(uint32 unitPropMask) const
  334. {
  335.  
  336.         int count = 0;
  337.         TUnitList::const_iterator it, itEnd = m_Units.end();
  338.         for (it = m_Units.begin(); it != itEnd; ++it)
  339.                 if (it->m_refUnit.GetAIObject()->IsEnabled() && (it->GetProperties() & unitPropMask))
  340.                 {
  341.                         CCCPOINT(CAIGroup_GetUnitCount);
  342.                         ++count;
  343.                 }
  344.         return count;
  345. }
  346.  
  347. //====================================================================
  348. // GetAttentionTarget
  349. //====================================================================
  350. // Suppressed passedByValue warnings for smart pointers like CWeakRef<>
  351. // cppcheck-suppress passedByValue
  352. CWeakRef<CAIObject> CAIGroup::GetAttentionTarget(bool bHostileOnly, bool bLiveOnly, const CWeakRef<CAIObject> refSkipTarget) const
  353. {
  354.         CCCPOINT(CAIGroup_GetAttentionTarget);
  355.  
  356.         // to do: give more priority to closer targets?
  357.         CWeakRef<CAIObject> refSelectedTarget;
  358.         bool bHostileFound = false;
  359.  
  360.         TUnitList::const_iterator it, itEnd = m_Units.end();
  361.         for (it = m_Units.begin(); it != itEnd; ++it)
  362.         {
  363.                 CAIActor* pAIActor = CastToCAIActorSafe(it->m_refUnit.GetAIObject());
  364.                 if (pAIActor)
  365.                 {
  366.                         CAIObject* attentionTarget = static_cast<CAIObject*>(pAIActor->GetAttentionTarget());
  367.                         if (attentionTarget && (attentionTarget->IsEnabled() ||
  368.                                                 (attentionTarget->GetType() == AIOBJECT_VEHICLE) && refSkipTarget != attentionTarget))
  369.                         {
  370.                                 CWeakRef<CAIObject> refAttentionTarget = GetWeakRef(attentionTarget);
  371.                                 bool bLive = attentionTarget->IsAgent();
  372.                                 if (pAIActor->IsHostile(attentionTarget))
  373.                                 {
  374.                                         if (bLive)
  375.                                                 return refAttentionTarget;//give priority to live hostile targets
  376.                                         else if (!bLiveOnly)
  377.                                         {
  378.                                                 bHostileFound = true;
  379.                                                 refSelectedTarget = refAttentionTarget; // then to hostile non live targets
  380.                                                 CCCPOINT(CAIGroup_GetAttentionTarget_A);
  381.                                         }
  382.                                 }
  383.                                 else if (!bHostileFound && !bHostileOnly && (bLive || !bLiveOnly))
  384.                                         refSelectedTarget = refAttentionTarget; // then to non hostile targets
  385.                         }
  386.                 }
  387.         }
  388.         if (m_pLeader && m_pLeader->IsPlayer())
  389.         {
  390.                 CAIPlayer* pPlayer = CastToCAIPlayerSafe(m_pLeader->GetAssociation().GetAIObject());
  391.                 if (pPlayer)
  392.                 {
  393.                         CAIObject* pPlayerAttTarget = static_cast<CAIObject*>(pPlayer->GetAttentionTarget());
  394.                         CWeakRef<CAIObject> refPlayerAttTarget = GetWeakRef(pPlayerAttTarget);
  395.                         if (pPlayerAttTarget && pPlayerAttTarget->IsEnabled() && refPlayerAttTarget != refSkipTarget) // nothing else to check, assuming that player has only live enemy targets
  396.                         {
  397.                                 bool bLive = pPlayerAttTarget->IsAgent();
  398.                                 if (pPlayer->IsHostile(pPlayerAttTarget))
  399.                                 {
  400.                                         if (bLive)
  401.                                                 return refPlayerAttTarget;//give priority to live hostile targets
  402.                                         else if (!bLiveOnly)
  403.                                                 refSelectedTarget = refPlayerAttTarget; // then to hostile non live targets
  404.                                 }
  405.                                 else if (!bHostileFound && !bHostileOnly && (bLive || !bLiveOnly))
  406.                                         refSelectedTarget = refPlayerAttTarget; // then to non hostile targets
  407.  
  408.                                 CCCPOINT(CAIGroup_GetAttentionTarget_B);
  409.                         }
  410.                 }
  411.         }
  412.  
  413.         return refSelectedTarget;
  414. }
  415.  
  416. //====================================================================
  417. // GetTargetCount
  418. //====================================================================
  419. int CAIGroup::GetTargetCount(bool bHostileOnly, bool bLiveOnly) const
  420. {
  421.         CCCPOINT(CAIGroup_GetTargetCount);
  422.         int n = 0;
  423.  
  424.         TUnitList::const_iterator it, itEnd = m_Units.end();
  425.         for (it = m_Units.begin(); it != itEnd; ++it)
  426.         {
  427.                 CAIActor* pAIActor = CastToCAIActorSafe(it->m_refUnit.GetAIObject());
  428.                 if (pAIActor)
  429.                 {
  430.                         CAIObject* attentionTarget = static_cast<CAIObject*>(pAIActor->GetAttentionTarget());
  431.                         if (attentionTarget && attentionTarget->IsEnabled())
  432.                         {
  433.                                 bool bLive = attentionTarget->IsAgent();
  434.                                 bool bHostile = pAIActor->IsHostile(attentionTarget);
  435.                                 if (!(bLiveOnly && !bLive || bHostileOnly && !bHostile))
  436.                                         n++;
  437.                         }
  438.                 }
  439.         }
  440.         if (m_pLeader && m_pLeader->IsPlayer())
  441.         {
  442.                 CAIPlayer* pPlayer = (CAIPlayer*)m_pLeader->GetAssociation().GetAIObject();
  443.                 ;
  444.                 if (pPlayer)
  445.                 {
  446.                         IAIObject* pAttentionTarget = pPlayer->GetAttentionTarget();
  447.                         if (pAttentionTarget && pAttentionTarget->IsEnabled()) // nothing else to check, assuming that player has only live enemy targets
  448.                         {
  449.                                 bool bLive = pAttentionTarget->IsAgent();
  450.                                 bool bHostile = pPlayer->IsHostile(pAttentionTarget);
  451.                                 if (!(bLiveOnly && !bLive || bHostileOnly && !bHostile))
  452.                                         n++;
  453.                         }
  454.                 }
  455.         }
  456.  
  457.         return n;
  458. }
  459.  
  460. //====================================================================
  461. // GetEnemyPosition
  462. //====================================================================
  463. Vec3 CAIGroup::GetEnemyPosition(const CAIObject* pUnit) const
  464. {
  465.         Vec3 enemyPos(0, 0, 0);
  466.         const CAIActor* pUnitAIActor = CastToCAIActorSafe(pUnit);
  467.         if (pUnitAIActor)
  468.         {
  469.                 IAIObject* pAttTarget = pUnitAIActor->GetAttentionTarget();
  470.                 if (pAttTarget)
  471.                 {
  472.                         CCCPOINT(CAIGroup_GetEnemyPosition_A);
  473.  
  474.                         switch (((CAIObject*)pAttTarget)->GetType())
  475.                         {
  476.                         case AIOBJECT_NONE:
  477.                                 break;
  478.                         case AIOBJECT_ACTOR:
  479.                         case AIOBJECT_DUMMY:
  480.                         case AIOBJECT_PLAYER:
  481.                         case AIOBJECT_WAYPOINT: // Actually this should be Beacon
  482.                         default:
  483.                                 return pAttTarget->GetPos();
  484.                         }
  485.                 }
  486.                 else
  487.                         return m_vAverageEnemyPosition;
  488.         }
  489.         else
  490.         {
  491.                 Vec3 averagePos = GetAveragePosition();
  492.  
  493.                 int memory = 0;
  494.                 bool realTarget = false;
  495.                 float distance = 10000.f;
  496.  
  497.                 TUnitList::const_iterator it, itEnd = m_Units.end();
  498.                 for (it = m_Units.begin(); it != itEnd; ++it)
  499.                 {
  500.                         CAIActor* const pAIActor = CastToCAIActorSafe(it->m_refUnit.GetAIObject());
  501.                         if (!pAIActor || !pAIActor->IsEnabled())
  502.                                 continue;
  503.  
  504.                         CAIObject* const pTarget = (CAIObject*) pAIActor->GetAttentionTarget();
  505.                         if (pTarget && !pAIActor->IsHostile(pTarget))
  506.                         {
  507.                                 const SOBJECTSTATE& state = pAIActor->GetState();
  508.  
  509.                                 if (!realTarget)
  510.                                 {
  511.                                         if (state.eTargetType == AITARGET_MEMORY)
  512.                                         {
  513.                                                 enemyPos += pTarget->GetPos();
  514.                                                 ++memory;
  515.                                         }
  516.                                         else
  517.                                         {
  518.                                                 realTarget = true;
  519.                                                 enemyPos = pTarget->GetPos();
  520.                                                 distance = (enemyPos - averagePos).GetLengthSquared();
  521.                                         }
  522.                                 }
  523.                                 else if (state.eTargetType != AITARGET_MEMORY)
  524.                                 {
  525.                                         float thisDistance = (pAIActor->GetPos() - averagePos).GetLengthSquared();
  526.                                         if (distance > thisDistance)
  527.                                         {
  528.                                                 enemyPos = pTarget->GetPos();
  529.                                                 distance = thisDistance;
  530.                                         }
  531.                                 }
  532.                         }
  533.                 }
  534.  
  535.                 if (!realTarget && m_pLeader && m_pLeader->IsPlayer())
  536.                 {
  537.                         CAIPlayer* pPlayer = CastToCAIPlayerSafe(m_pLeader->GetAssociation().GetAIObject());
  538.                         if (pPlayer)
  539.                         {
  540.                                 IAIObject* pTarget = pPlayer->GetAttentionTarget();
  541.                                 if (pTarget && pTarget->IsEnabled()) // nothing else to check, assuming that player has only live enemy targets
  542.                                 {
  543.                                         realTarget = true;
  544.                                         enemyPos = pTarget->GetPos();
  545.                                 }
  546.                         }
  547.                 }
  548.  
  549.                 if (!realTarget && memory)
  550.                         enemyPos /= (float) memory;
  551.         }
  552.  
  553.         CCCPOINT(CAIGroup_GetEnemyPosition_B);
  554.  
  555.         return enemyPos;
  556. }
  557.  
  558. //====================================================================
  559. // GetEnemyAverageDirection
  560. //====================================================================
  561. Vec3 CAIGroup::GetEnemyAverageDirection(bool bLiveTargetsOnly, bool bSmart) const
  562. {
  563.         Vec3 avgDir(0, 0, 0);
  564.         //      TVecTargets FoundTargets;
  565.         //      TVecTargets::iterator itf;
  566.         TSetAIObjects::const_iterator it, itEnd = m_Targets.end();
  567.         int count = 0;
  568.         for (it = m_Targets.begin(); it != itEnd; ++it)
  569.         {
  570.                 const CAIObject* pTarget = it->GetAIObject();
  571.                 if (pTarget)
  572.                 {
  573.                         bool bLiveTarget = pTarget->IsAgent();
  574.                         if ((!bLiveTargetsOnly || bLiveTarget) && !pTarget->GetMoveDir().IsZero())
  575.                         {
  576.                                 // add only not null (significative) directions
  577.                                 avgDir += pTarget->GetMoveDir();
  578.                                 //                      FoundTargets.push_back(pTarget);
  579.                                 count++;
  580.                         }
  581.                 }
  582.  
  583.         }
  584.         if (count)
  585.         {
  586.                 avgDir /= float(count);
  587.                 /*if(bSmart)// clear the average if it's small enough
  588.                    //(means that the direction vectors are spread in many opposite directions)
  589.                    {
  590.  
  591.                    // compute variance
  592.                    float fVariance = 0;
  593.                    for (itf = FoundTargets.begin(); itf != FoundTargets.end(); ++itf)
  594.                    {    CAIObject* pTarget = *itf;
  595.                    fVariance+= (pTarget->GetMoveDir() - avgDir).GetLengthSquared();
  596.                    }
  597.  
  598.                    if(fVariance>0.7)
  599.                    avgDir.Set(0,0,0);
  600.  
  601.                    }*/
  602.                 // either normalize or clear
  603.                 float fAvgSize = avgDir.GetLength();
  604.                 if (fAvgSize > (bSmart ? 0.4f : 0.1f))
  605.                         avgDir /= fAvgSize;
  606.                 else
  607.                         avgDir.Set(0, 0, 0);
  608.         }
  609.         return avgDir;
  610. }
  611.  
  612. //====================================================================
  613. // OnObjectRemoved
  614. //====================================================================
  615. void CAIGroup::OnObjectRemoved(CAIObject* pObject)
  616. {
  617.         if (!pObject)
  618.                 return;
  619.  
  620.         CAIActor* pActor = pObject->CastToCAIActor();
  621.  
  622.         TUnitList::iterator it = std::find(m_Units.begin(), m_Units.end(), pActor);
  623.         if (it != m_Units.end())
  624.                 RemoveMember(pActor);
  625.  
  626.         // (MATT) If UpdateEnemyStats touches targets, this must happen after other cleanup has happened... {2009/03/17}
  627.         TSetAIObjects::iterator ittgt = std::find(m_Targets.begin(), m_Targets.end(), pObject);
  628.         if (ittgt != m_Targets.end())
  629.         {
  630.                 m_bUpdateEnemyStats = true;
  631.         }
  632.  
  633.         for (unsigned i = 0; i < m_reinforcementSpots.size(); )
  634.         {
  635.                 if (m_reinforcementSpots[i].pAI == pObject)
  636.                 {
  637.                         m_reinforcementSpots[i] = m_reinforcementSpots.back();
  638.                         m_reinforcementSpots.pop_back();
  639.                 }
  640.                 else
  641.                         ++i;
  642.         }
  643. }
  644.  
  645. //====================================================================
  646. // GetForemostUnit
  647. //====================================================================
  648. CAIObject* CAIGroup::GetForemostUnit(const Vec3& direction, uint32 unitProp) const
  649. {
  650.         Vec3 vFurthestPos(0, 0, 0);
  651.         float maxLength = 0;
  652.         CAIObject* pForemost = NULL;
  653.  
  654.         Vec3 vAvgPos = GetAveragePosition(AVMODE_PROPERTIES, unitProp);
  655.  
  656.         for (TUnitList::const_iterator it = m_Units.begin(); it != m_Units.end(); ++it)
  657.         {
  658.                 const CUnitImg& unit = *it;
  659.                 CAIObject* pUnit = unit.m_refUnit.GetAIObject();
  660.                 if (pUnit->IsEnabled() && (unit.GetProperties() & unitProp))
  661.                 {
  662.                         CCCPOINT(CAIGroup_ForemostUnit);
  663.  
  664.                         Vec3 vDisplace = pUnit->GetPos() - vAvgPos;
  665.                         float fNorm = vDisplace.GetLength();
  666.                         if (fNorm > 0.001f)//consider an epsilon
  667.                         {
  668.                                 Vec3 vNorm = vDisplace / fNorm;
  669.                                 float cosine = vNorm.Dot(direction);
  670.                                 if (cosine >= 0) // exclude negative cosine (opposite directions)
  671.                                 {
  672.                                         float fProjection = cosine * fNorm;
  673.                                         if (maxLength < fProjection)
  674.                                         {
  675.                                                 maxLength = fProjection;
  676.                                                 pForemost = pUnit;
  677.                                         }
  678.                                 }
  679.                         }
  680.                         else if (!pForemost)
  681.                         {
  682.                                 // the unit is exactly at the average position and no one better has been found yet
  683.                                 pForemost = pUnit;
  684.                         }
  685.                 }
  686.         }
  687.         return (pForemost);
  688. }
  689.  
  690. //====================================================================
  691. // GetForemostEnemyPosition
  692. //====================================================================
  693. Vec3 CAIGroup::GetForemostEnemyPosition(const Vec3& direction, bool bLiveOnly) const
  694. {
  695.         const CAIObject* pForemost = GetForemostEnemy(direction, bLiveOnly);
  696.         return (pForemost ? pForemost->GetPos() : ZERO);
  697. }
  698.  
  699. //====================================================================
  700. // GetForemostEnemy
  701. //====================================================================
  702. const CAIObject* CAIGroup::GetForemostEnemy(const Vec3& direction, bool bLiveOnly) const
  703. {
  704.         Vec3 vFurthestPos(0, 0, 0);
  705.         float maxLength = 0;
  706.         const CAIObject* pForemost = NULL;
  707.         Vec3 vDirNorm = direction.GetNormalizedSafe();
  708.         TSetAIObjects::const_iterator itend = m_Targets.end();
  709.         for (TSetAIObjects::const_iterator it = m_Targets.begin(); it != itend; ++it)
  710.         {
  711.                 const CAIObject* pTarget = it->GetAIObject();
  712.                 if (!bLiveOnly || pTarget->IsAgent())
  713.                 {
  714.                         Vec3 vDisplace = pTarget->GetPos() - m_vAverageEnemyPosition;
  715.                         float fNorm = vDisplace.GetLength();
  716.                         if (fNorm > 0.001f)//consider an epsilon
  717.                         {
  718.                                 Vec3 vNorm = vDisplace / fNorm;
  719.                                 float cosine = vNorm.Dot(vDirNorm);
  720.                                 if (cosine >= 0) // exclude negative cosine (opposite directions)
  721.                                 {
  722.                                         float fProjection = cosine * fNorm;
  723.                                         if (maxLength < fProjection)
  724.                                         {
  725.                                                 maxLength = fProjection;
  726.                                                 pForemost = pTarget;
  727.                                         }
  728.                                 }
  729.                         }
  730.                         else if (!pForemost)
  731.                         {
  732.                                 // the target is exactly at the average position and no one better has been found yet
  733.                                 pForemost = pTarget;
  734.                         }
  735.                 }
  736.         }
  737.  
  738.         CAISystem* pAISystem(GetAISystem());
  739.         if (!pForemost && !bLiveOnly)
  740.                 pForemost = static_cast<CAIObject*>(pAISystem->GetBeacon(m_groupID));
  741.  
  742.         return pForemost;
  743. }
  744.  
  745. //====================================================================
  746. // GetEnemyPositionKnown
  747. //====================================================================
  748. Vec3 CAIGroup::GetEnemyPositionKnown() const
  749. {
  750.         // (MATT) Only used in one place and candidates for its replacement are noted {2009/02/10}
  751.         CCCPOINT(CAIGroup_GetEnemyPositionKnown);
  752.  
  753.         CAISystem* pAISystem(GetAISystem());
  754.         Vec3 enemyPos;
  755.         bool realTarget = false;
  756.         TUnitList::const_iterator it, itEnd = m_Units.end();
  757.         for (it = m_Units.begin(); it != itEnd; ++it)
  758.         {
  759.                 CAIActor* pAIActor = it->m_refUnit.GetAIObject();
  760.                 if (!pAIActor || !pAIActor->IsEnabled())
  761.                         continue;
  762.  
  763.                 CAIObject* const pTarget = (CAIObject*) pAIActor->GetAttentionTarget();
  764.                 if (!pTarget || !pTarget->IsEnabled() || !pTarget->IsAgent())
  765.                         continue;
  766.  
  767.                 if (pAIActor->GetAttentionTargetType() == AITARGET_MEMORY || !pAIActor->IsHostile(pTarget))
  768.                         continue;
  769.  
  770.                 realTarget = true;
  771.                 enemyPos = pTarget->GetPos();
  772.                 break;
  773.         }
  774.  
  775.         if (!realTarget)
  776.         {
  777.                 CCCPOINT(CAIGroup_GetEnemyPositionKnown_A);
  778.  
  779.                 if (m_pLeader && m_pLeader->IsPlayer())
  780.                 {
  781.                         CAIPlayer* pPlayer = CastToCAIPlayerSafe(m_pLeader->GetAssociation().GetAIObject());
  782.                         if (pPlayer)
  783.                         {
  784.                                 IAIObject* pTarget = pPlayer->GetAttentionTarget();
  785.                                 if (pTarget && pTarget->IsEnabled()) // nothing else to check, assuming that player has only live enemy targets
  786.                                 {
  787.                                         realTarget = true;
  788.                                         enemyPos = pTarget->GetPos();
  789.                                 }
  790.                         }
  791.                 }
  792.                 if (!realTarget)
  793.                 {
  794.                         if (pAISystem->GetBeacon(m_groupID))
  795.                                 enemyPos = pAISystem->GetBeacon(m_groupID)->GetPos();
  796.                         else
  797.                                 enemyPos.Set(0, 0, 0);
  798.                 }
  799.         }
  800.         return enemyPos;
  801. }
  802.  
  803. //====================================================================
  804. // Update
  805. //====================================================================
  806. void CAIGroup::Update()
  807. {
  808.         CCCPOINT(CAIGroup_Update);
  809.         FUNCTION_PROFILER(gEnv->pSystem, PROFILE_AI);
  810.  
  811.         CAISystem* pAISystem(GetAISystem());
  812.  
  813.         UpdateReinforcementLogic();
  814. }
  815.  
  816. //====================================================================
  817. // UpdateReinforcementLogic
  818. //====================================================================
  819. // (MATT) This code looks rather complex - does it really help? {2009/02/12}
  820. void CAIGroup::UpdateReinforcementLogic()
  821. {
  822.         FUNCTION_PROFILER(gEnv->pSystem, PROFILE_AI);
  823.  
  824.         if (/*m_reinforcementState == REINF_ALERTED_COMBAT_PENDING ||*/
  825.           m_reinforcementState == REINF_DONE_PENDING)
  826.                 return;
  827.  
  828.         // Get reinforcement points for this group if not acquired yet.
  829.         if (!m_reinforcementSpotsAcquired)
  830.         {
  831.                 m_reinforcementSpots.clear();
  832.  
  833.                 m_reinforcementSpotsAllAlerted = 0;
  834.                 m_reinforcementSpotsCombat = 0;
  835.                 m_reinforcementSpotsBodyCount = 0;
  836.  
  837.                 for (AutoAIObjectIter it(gAIEnv.pAIObjectManager->GetFirstAIObject(OBJFILTER_TYPE, AIANCHOR_REINFORCEMENT_SPOT)); it->GetObject(); it->Next())
  838.                 {
  839.                         CAIObject* pAI = static_cast<CAIObject*>(it->GetObject());
  840.                         if (pAI->GetGroupId() == m_groupID && pAI->GetEntity())
  841.                         {
  842.                                 // Look up the extra properties.
  843.                                 IScriptTable* pTable = pAI->GetEntity()->GetScriptTable();
  844.                                 if (pTable)
  845.                                 {
  846.                                         CCCPOINT(CAIGroup_UpdateReinforcementLogic_A);
  847.  
  848.                                         SmartScriptTable props;
  849.                                         if (pTable->GetValue("Properties", props))
  850.                                         {
  851.                                                 m_reinforcementSpots.resize(m_reinforcementSpots.size() + 1);
  852.  
  853.                                                 int whenAllAlerted = 0;
  854.                                                 int whenInCombat = 0;
  855.                                                 int groupBodyCount = 0;
  856.                                                 float avoidWhenTargetInRadius = 0.0f;
  857.                                                 int type = 0;
  858.                                                 props->GetValue("bWhenAllAlerted", whenAllAlerted);
  859.                                                 props->GetValue("bWhenInCombat", whenInCombat);
  860.                                                 props->GetValue("iGroupBodyCount", groupBodyCount);
  861.                                                 props->GetValue("eiReinforcementType", type);
  862.                                                 props->GetValue("AvoidWhenTargetInRadius", avoidWhenTargetInRadius);
  863.  
  864.                                                 m_reinforcementSpots.back().whenAllAlerted = whenAllAlerted > 0;
  865.                                                 m_reinforcementSpots.back().whenInCombat = whenInCombat > 0;
  866.                                                 m_reinforcementSpots.back().groupBodyCount = groupBodyCount;
  867.                                                 m_reinforcementSpots.back().avoidWhenTargetInRadius = avoidWhenTargetInRadius;
  868.                                                 m_reinforcementSpots.back().type = type;
  869.                                                 m_reinforcementSpots.back().pAI = pAI;
  870.  
  871.                                                 if (m_reinforcementSpots.back().whenAllAlerted)
  872.                                                         m_reinforcementSpotsAllAlerted++;
  873.                                                 if (m_reinforcementSpots.back().whenInCombat)
  874.                                                         m_reinforcementSpotsCombat++;
  875.                                                 if (m_reinforcementSpots.back().groupBodyCount > 0)
  876.                                                         m_reinforcementSpotsBodyCount++;
  877.  
  878.                                         }
  879.                                 }
  880.                         }
  881.                 }
  882.  
  883.                 m_reinforcementSpotsAcquired = true;
  884.         }
  885.  
  886.         // Check if reinforcements should be called.
  887.         if (!m_reinforcementSpots.empty() && m_reinforcementState != REINF_DONE)
  888.         {
  889.                 CCCPOINT(CAIGroup_UpdateReinforcementLogic_B);
  890.  
  891.                 int totalCount = 0;
  892.                 int enabledCount = 0;
  893.                 int alertedCount = 0;
  894.                 int combatCount = 0;
  895.                 int liveTargetCount = 0;
  896.                 for (TUnitList::const_iterator it = m_Units.begin(), end = m_Units.end(); it != end; ++it)
  897.                 {
  898.                         CAIActor* pAIActor = it->m_refUnit.GetAIObject();
  899.                         if (!pAIActor) continue;
  900.  
  901.                         totalCount++;
  902.  
  903.                         if (!pAIActor->IsEnabled()) continue;
  904.                         if (pAIActor->GetProxy()->IsCurrentBehaviorExclusive()) continue;
  905.  
  906.                         if (CPuppet* pPuppet = pAIActor->CastToCPuppet())
  907.                         {
  908.                                 if (pPuppet->GetAlertness() >= 1)
  909.                                         alertedCount++;
  910.                                 if (pPuppet->GetAlertness() >= 2)
  911.                                         combatCount++;
  912.                         }
  913.  
  914.                         if (pAIActor->GetAttentionTargetType() == AITARGET_VISUAL &&
  915.                             pAIActor->GetAttentionTargetThreat() == AITHREAT_AGGRESSIVE)
  916.                         {
  917.                                 liveTargetCount++;
  918.                         }
  919.  
  920.                         enabledCount++;
  921.                 }
  922.  
  923.                 bool matchWhenAllAlerted = false;
  924.                 bool matchWhenInCombat = false;
  925.                 bool matchWhenGroupSizeLess = false;
  926.  
  927.                 bool tryToCall = false;
  928.  
  929.                 if (m_reinforcementState == REINF_NONE)
  930.                 {
  931.                         if (m_reinforcementSpotsAllAlerted)
  932.                         {
  933.                                 if ((enabledCount <= 2 && alertedCount > 0) ||
  934.                                     (enabledCount > 2 && alertedCount > 1))
  935.                                 {
  936.                                         matchWhenAllAlerted = true;
  937.                                         matchWhenInCombat = false;
  938.                                         matchWhenGroupSizeLess = false;
  939.                                         tryToCall = true;
  940.                                 }
  941.                         }
  942.  
  943.                         if (m_reinforcementSpotsCombat)
  944.                         {
  945.                                 if ((enabledCount <= 2 && liveTargetCount > 0 && combatCount > 0) ||
  946.                                     (enabledCount > 2 && liveTargetCount > 1 && combatCount > 1))
  947.                                 {
  948.                                         matchWhenAllAlerted = false;
  949.                                         matchWhenInCombat = true;
  950.                                         matchWhenGroupSizeLess = false;
  951.                                         tryToCall = true;
  952.                                 }
  953.                         }
  954.                 }
  955.                 /*
  956.                     if (m_reinforcementState == REINF_ALERTED_COMBAT)
  957.                     {
  958.                       if (m_reinforcementSpotsBodyCount && m_countDead > 0)
  959.                       {
  960.                         for (unsigned i = 0, n = m_reinforcementSpots.size(); i < n; ++i)
  961.                         {
  962.                           if (m_countDead >= m_reinforcementSpots[i].groupBodyCount)
  963.                           {
  964.                             matchWhenAllAlerted = false;
  965.                             matchWhenInCombat = false;
  966.                             matchWhenGroupSizeLess = true;
  967.                             tryToCall = true;
  968.                             break;
  969.                           }
  970.                         }
  971.                       }
  972.                     }
  973.                  */
  974.                 if (tryToCall)
  975.                 {
  976.                         CCCPOINT(CAIGroup_UpdateReinforcementLogic_C);
  977.  
  978.                         float nearestDist = FLT_MAX;
  979.                         SAIReinforcementSpot* nearestSpot = 0;
  980.                         CUnitImg* pNearestCallerImg = 0;
  981.  
  982.                         Vec3 playerPos(0, 0, 0), playerViewDir(0, 0, 0);
  983.                         CAIPlayer* pPlayer = CastToCAIPlayerSafe(GetAISystem()->GetPlayer());
  984.                         if (pPlayer)
  985.                         {
  986.                                 playerPos = pPlayer->GetPos();
  987.                                 playerViewDir = pPlayer->GetViewDir();
  988.                         }
  989.  
  990.                         size_t reinfSpotCount = m_reinforcementSpots.size();
  991.  
  992.                         for (size_t i = 0; i < reinfSpotCount; ++i)
  993.                         {
  994.                                 const SAIReinforcementSpot& spot = m_reinforcementSpots[i];
  995.                                 if (!spot.pAI->IsEnabled())
  996.                                         continue;
  997.  
  998.                                 if (matchWhenAllAlerted && !spot.whenAllAlerted) continue;
  999.                                 if (matchWhenInCombat && !spot.whenInCombat) continue;
  1000.                                 if (matchWhenGroupSizeLess && m_countDead >= spot.groupBodyCount) continue;
  1001.  
  1002.                                 const Vec3& reinfSpot = spot.pAI->GetPos();
  1003.                                 const float reinfRadiusSqr = sqr(spot.pAI->GetRadius());
  1004.                                 const float avoidWhenTargetInRadiusSqr = sqr(spot.avoidWhenTargetInRadius);
  1005.  
  1006.                                 for (TUnitList::iterator it = m_Units.begin(), end = m_Units.end(); it != end; ++it)
  1007.                                 {
  1008.                                         CAIActor* const pAIActor = CastToCPuppetSafe(it->m_refUnit.GetAIObject());
  1009.                                         if (!pAIActor) continue;
  1010.                                         if (!pAIActor->IsEnabled()) continue;
  1011.                                         if ((GetAISystem()->GetFrameStartTime() - it->m_lastReinforcementTime).GetSeconds() < 3.f) continue;
  1012.                                         IAIActorProxy* pProxy = pAIActor->GetProxy();
  1013.                                         if (!pProxy || pProxy->IsCurrentBehaviorExclusive()) continue;
  1014.  
  1015.                                         if (CPuppet* const pPuppet = pAIActor->CastToCPuppet())
  1016.                                         {
  1017.                                                 if (matchWhenAllAlerted && pPuppet->GetAlertness() < 1) continue;
  1018.                                                 if (matchWhenInCombat && pPuppet->GetAlertness() < 2) continue;
  1019.                                         }
  1020.  
  1021.                                         IAIObject* pAttTarget = pAIActor->GetAttentionTarget();
  1022.                                         EAITargetType eAttTargetType = pAIActor->GetAttentionTargetType();
  1023.                                         EAITargetThreat eAttTargetThreat = pAIActor->GetAttentionTargetThreat();
  1024.  
  1025.                                         // Skip reinforcement spots that are too close the attention target.
  1026.                                         if (pAttTarget)
  1027.                                         {
  1028.                                                 if ((eAttTargetType == AITARGET_VISUAL || eAttTargetType == AITARGET_MEMORY) &&
  1029.                                                     eAttTargetThreat == AITHREAT_AGGRESSIVE &&
  1030.                                                     Distance::Point_PointSq(reinfSpot, pAttTarget->GetPos()) < avoidWhenTargetInRadiusSqr)
  1031.                                                 {
  1032.                                                         continue;
  1033.                                                 }
  1034.                                         }
  1035.  
  1036.                                         const Vec3& vPos = pAIActor->GetPos();
  1037.                                         float distSqr = Distance::Point_PointSq(vPos, reinfSpot);
  1038.  
  1039.                                         CCCPOINT(CAIGroup_UpdateReinforcementLogic_D);
  1040.  
  1041.                                         if (distSqr < reinfRadiusSqr)
  1042.                                         {
  1043.                                                 float dist = sqrtf(distSqr);
  1044.  
  1045.                                                 if (!pAttTarget || pProxy->GetLinkedVehicleEntityId())
  1046.                                                 {
  1047.                                                         dist += 100.0f;
  1048.                                                 }
  1049.                                                 else
  1050.                                                 {
  1051.                                                         const float preferredCallDist = 25.0f;
  1052.                                                         float bestDist = fabsf(Distance::Point_Point(vPos, pAttTarget->GetPos()) - preferredCallDist);
  1053.  
  1054.                                                         if (eAttTargetType == AITARGET_VISUAL && eAttTargetThreat == AITHREAT_AGGRESSIVE)
  1055.                                                                 bestDist *= 0.5f;
  1056.                                                         else if (eAttTargetThreat == AITHREAT_THREATENING)
  1057.                                                                 bestDist *= 0.75f;
  1058.  
  1059.                                                         dist += bestDist;
  1060.                                                 }
  1061.  
  1062.                                                 // Prefer puppet visible to the player.
  1063.                                                 Vec3 dirPlayerToPuppet = vPos - playerPos;
  1064.                                                 dirPlayerToPuppet.NormalizeSafe();
  1065.                                                 float dot = playerViewDir.Dot(dirPlayerToPuppet);
  1066.                                                 dist += (1 - sqr((dot + 1) / 2)) * 25.0f;
  1067.  
  1068.                                                 if (dist < nearestDist)
  1069.                                                 {
  1070.                                                         nearestDist = dist;
  1071.                                                         nearestSpot = &m_reinforcementSpots[i];
  1072.                                                         //                                                      nearestCaller = pPuppet;
  1073.                                                         pNearestCallerImg = &(*it);
  1074.                                                 }
  1075.                                         }
  1076.                                 }
  1077.                         }
  1078.  
  1079.                         if (pNearestCallerImg && nearestSpot)
  1080.                         {
  1081.                                 // Change state
  1082.                                 if (m_reinforcementState == REINF_NONE)
  1083.                                         /*                                      m_reinforcementState = REINF_ALERTED_COMBAT_PENDING;
  1084.                                                 else if (m_reinforcementState == REINF_ALERTED_COMBAT)*/
  1085.                                         m_reinforcementState = REINF_DONE_PENDING;
  1086.  
  1087.                                 // Tell the agent to call reinforcements.
  1088.                                 CAIActor* const pUnit = CastToCAIActorSafe(pNearestCallerImg->m_refUnit.GetAIObject());
  1089.                                 AISignalExtraData* pData = new AISignalExtraData;
  1090.                                 pData->nID = nearestSpot->pAI->GetEntityID();
  1091.                                 pData->iValue = nearestSpot->type;
  1092.                                 pUnit->SetSignal(1, "OnCallReinforcements", pUnit->GetEntity(), pData);
  1093.                                 pNearestCallerImg->m_lastReinforcementTime = GetAISystem()->GetFrameStartTime();
  1094.  
  1095. #ifdef CRYAISYSTEM_DEBUG
  1096.                                 m_DEBUG_reinforcementCalls.push_back(SAIRefinforcementCallDebug(pUnit->GetPos() + Vec3(0, 0, 0.3f), nearestSpot->pAI->GetPos() + Vec3(0, 0, 0.3f), 7.0f, nearestSpot->pAI->GetName()));
  1097. #endif
  1098.                                 m_refReinfPendingUnit = StaticCast<CPuppet>(pNearestCallerImg->m_refUnit);
  1099.                                 // Remove the spot (when confirmed)
  1100.                                 m_pendingDecSpotsAllAlerted = nearestSpot->whenAllAlerted;
  1101.                                 m_pendingDecSpotsCombat = nearestSpot->whenInCombat;
  1102.                                 m_pendingDecSpotsBodyCount = nearestSpot->groupBodyCount > 0;
  1103.  
  1104.                                 CCCPOINT(CAIGroup_UpdateReinforcementLogic_E);
  1105.                         }
  1106.                 }
  1107.         }
  1108.  
  1109. #ifdef CRYAISYSTEM_DEBUG
  1110.         for (unsigned i = 0; i < m_DEBUG_reinforcementCalls.size(); )
  1111.         {
  1112.                 m_DEBUG_reinforcementCalls[i].t -= gEnv->pTimer->GetFrameTime();
  1113.                 if (m_DEBUG_reinforcementCalls[i].t < 0.0f)
  1114.                 {
  1115.                         m_DEBUG_reinforcementCalls[i] = m_DEBUG_reinforcementCalls.back();
  1116.                         m_DEBUG_reinforcementCalls.pop_back();
  1117.                 }
  1118.                 else
  1119.                         ++i;
  1120.         }
  1121. #endif
  1122. }
  1123.  
  1124. //====================================================================
  1125. // UpdateGroupCountStatus
  1126. //====================================================================
  1127. void CAIGroup::UpdateGroupCountStatus()
  1128. {
  1129.         CAISystem* pAISystem(GetAISystem());
  1130.         // Count number of active and non active members.
  1131.         int count = 0;
  1132.         int countEnabled = 0;
  1133.         for (AIObjects::iterator it = pAISystem->m_mapGroups.find(m_groupID); it != pAISystem->m_mapGroups.end() && it->first == m_groupID; )
  1134.         {
  1135.                 CAIObject* pObject = it->second.GetAIObject();
  1136.  
  1137.                 // (MATT) These are weak refs so objects may have been removed {2009/03/25}
  1138.                 if (!pObject)
  1139.                 {
  1140.                         pAISystem->m_mapGroups.erase(it++);
  1141.                         continue;
  1142.                 }
  1143.  
  1144.                 int type = pObject->GetType();
  1145.                 if (type == AIOBJECT_ACTOR)
  1146.                 {
  1147.                         if (pObject->IsEnabled())
  1148.                                 countEnabled++;
  1149.                         count++;
  1150.                 }
  1151.                 else if (type == AIOBJECT_VEHICLE)
  1152.                 {
  1153.                         CAIVehicle* pVehicle = pObject->CastToCAIVehicle();
  1154.                         if (pVehicle->IsEnabled() && pVehicle->IsDriverInside())
  1155.                                 countEnabled++;
  1156.                         count++;
  1157.                 }
  1158.  
  1159.                 ++it;
  1160.         }
  1161.  
  1162.         // Store the current state
  1163.         m_count = count;
  1164.         m_countEnabled = countEnabled;
  1165.         // Keep track on the maximum
  1166.         m_countMax = max(m_countMax, count);
  1167.         m_countEnabledMax = max(m_countEnabledMax, countEnabled);
  1168.  
  1169.         // add smart objects state "GroupHalved" to alive group members
  1170.         // (MATT) Rather specific :/ Does anyone use it?  {2009/03/25}
  1171.         if (m_countEnabled == m_countEnabledMax / 2)
  1172.         {
  1173.                 AIObjects::iterator it, itEnd = pAISystem->m_mapGroups.end();
  1174.                 for (it = pAISystem->m_mapGroups.lower_bound(m_groupID); it != itEnd && it->first == m_groupID; ++it)
  1175.                 {
  1176.                         // Objects will now already be validated or removed
  1177.                         CAIObject* pObject = it->second.GetAIObject();
  1178.                         if (pObject->IsEnabled() && pObject->GetType() != AIOBJECT_LEADER)
  1179.                         {
  1180.                                 if (IEntity* pEntity = pObject->GetEntity())
  1181.                                         gAIEnv.pSmartObjectManager->AddSmartObjectState(pEntity, "GroupHalved");
  1182.                         }
  1183.                 }
  1184.         }
  1185. }
  1186.  
  1187. //====================================================================
  1188. // GetGroupCount
  1189. //====================================================================
  1190. int CAIGroup::GetGroupCount(int flags)
  1191. {
  1192.         if (flags == 0 || flags == IAISystem::GROUP_ALL)
  1193.                 return m_count;
  1194.         else if (flags == IAISystem::GROUP_ENABLED)
  1195.                 return m_countEnabled;
  1196.         else if (flags == IAISystem::GROUP_MAX)
  1197.                 return m_countMax;
  1198.         else if (flags == (IAISystem::GROUP_ENABLED | IAISystem::GROUP_MAX))
  1199.                 return m_countEnabledMax;
  1200.         return 0;
  1201. }
  1202.  
  1203. //====================================================================
  1204. // Reset
  1205. //====================================================================
  1206. void CAIGroup::Reset()
  1207. {
  1208.         CCCPOINT(CAIGroup_Reset);
  1209.  
  1210.         m_count = 0;
  1211.         m_countMax = 0;
  1212.         m_countEnabled = 0;
  1213.         m_countEnabledMax = 0;
  1214.         m_countDead = 0;
  1215.         m_countCheckedDead = 0;
  1216.         m_bUpdateEnemyStats = true;
  1217.  
  1218.         for (TUnitList::iterator itrUnit(m_Units.begin()); itrUnit != m_Units.end(); ++itrUnit)
  1219.                 itrUnit->Reset();
  1220.  
  1221.         stl::free_container(m_groupScopes);
  1222.  
  1223.         stl::free_container(m_reinforcementSpots);
  1224.         m_reinforcementSpotsAcquired = false;
  1225.         m_reinforcementState = REINF_NONE;
  1226.         m_refReinfPendingUnit.Reset();
  1227.  
  1228. #ifdef CRYAISYSTEM_DEBUG
  1229.         m_DEBUG_reinforcementCalls.clear();
  1230. #endif
  1231. }
  1232.  
  1233. //====================================================================
  1234. // Serialize
  1235. //====================================================================
  1236. void CAIGroup::Serialize(TSerialize ser)
  1237. {
  1238.         CCCPOINT(CAIGroup_Serialize);
  1239.  
  1240.         // TODO: serialize and create tactical evals
  1241.         char Name[256];
  1242.         cry_sprintf(Name, "AIGroup-%d", m_groupID);
  1243.  
  1244.         ser.BeginGroup(Name);
  1245.  
  1246.         ser.Value("AIgroup_GroupID", m_groupID);
  1247.  
  1248.         m_bUpdateEnemyStats = true;
  1249.  
  1250.         ser.Value("m_count", m_count);
  1251.         ser.Value("m_countMax", m_countMax);
  1252.         ser.Value("m_countEnabled", m_countEnabled);
  1253.         ser.Value("m_countEnabledMax", m_countEnabledMax);
  1254.         ser.Value("m_countDead", m_countDead);
  1255.         ser.Value("m_countCheckedDead", m_countCheckedDead);
  1256.  
  1257.         //      TSetAIObjects   m_Targets;
  1258.         ser.Value("m_vEnemyPositionKnown", m_vEnemyPositionKnown);
  1259.         ser.Value("m_vAverageEnemyPosition", m_vAverageEnemyPosition);
  1260.         ser.Value("m_vAverageLiveEnemyPosition", m_vAverageLiveEnemyPosition);
  1261.  
  1262.         //see below for m_pLeader Serialization
  1263.         {
  1264.                 if (ser.BeginOptionalGroup("m_Units", true))
  1265.                 {
  1266.                         if (ser.IsWriting())
  1267.                         {
  1268.                                 uint32 count = m_Units.size();
  1269.                                 ser.Value("Size", count);
  1270.                                 for (TUnitList::iterator iter = m_Units.begin(); iter != m_Units.end(); ++iter)
  1271.                                 {
  1272.                                         ser.BeginGroup("i");
  1273.                                         CUnitImg& value = *iter;
  1274.                                         ser.Value("v", value);
  1275.                                         ser.EndGroup();
  1276.                                 }
  1277.                         }
  1278.                         else
  1279.                         {
  1280.                                 m_Units.clear();
  1281.                                 uint32 count = 0;
  1282.                                 ser.Value("Size", count);
  1283.                                 while (count--)
  1284.                                 {
  1285.                                         ser.BeginGroup("i");
  1286.                                         m_Units.push_back(CUnitImg());
  1287.                                         ser.Value("v", m_Units.back());
  1288.                                         ser.EndGroup();
  1289.                                 }
  1290.                         }
  1291.                         ser.EndGroup();
  1292.                 }
  1293.         }
  1294.  
  1295.         ser.Value("m_groupScopes", m_groupScopes);
  1296.  
  1297.         if (ser.IsReading())
  1298.         {
  1299.                 // Clear reinforcement spots.
  1300.                 m_reinforcementSpotsAcquired = false;
  1301.                 m_reinforcementSpots.clear();
  1302.         }
  1303.  
  1304.         SerializeWeakRefVector<const CAIObject>(ser, "m_Targets", m_Targets);
  1305.  
  1306.         ser.EnumValue("m_reinforcementState", m_reinforcementState, REINF_NONE, LAST_REINF);
  1307.  
  1308.         ser.Value("m_pendingDecSpotsAllAlerted", m_pendingDecSpotsAllAlerted);
  1309.         ser.Value("m_pendingDecSpotsCombat", m_pendingDecSpotsCombat);
  1310.         ser.Value("m_pendingDecSpotsBodyCount", m_pendingDecSpotsBodyCount);
  1311.         m_refReinfPendingUnit.Serialize(ser, "m_refReinfPendingUnit");
  1312.  
  1313.         ser.EndGroup(); // AIGroup
  1314. }
  1315.  
  1316. //====================================================================
  1317. // DebugDraw
  1318. //====================================================================
  1319. void CAIGroup::DebugDraw()
  1320. {
  1321.         // Debug draw reinforcement logic.
  1322.         if (gAIEnv.CVars.DebugDrawReinforcements == m_groupID)
  1323.         {
  1324.  
  1325.                 int totalCount = 0;
  1326.                 int enabledCount = 0;
  1327.                 int alertedCount = 0;
  1328.                 int combatCount = 0;
  1329.                 int liveTargetCount = 0;
  1330.                 for (TUnitList::const_iterator it = m_Units.begin(), end = m_Units.end(); it != end; ++it)
  1331.                 {
  1332.                         CAIActor* pAIActor = it->m_refUnit.GetAIObject();
  1333.                         if (!pAIActor) continue;
  1334.                         totalCount++;
  1335.  
  1336.                         if (!pAIActor->IsEnabled()) continue;
  1337.                         if (pAIActor->GetProxy()->IsCurrentBehaviorExclusive()) continue;
  1338.  
  1339.                         if (CPuppet* pPuppet = pAIActor->CastToCPuppet())
  1340.                         {
  1341.                                 if (pPuppet->GetAlertness() >= 1)
  1342.                                         alertedCount++;
  1343.                                 if (pPuppet->GetAlertness() >= 2)
  1344.                                         combatCount++;
  1345.                         }
  1346.  
  1347.                         if (pAIActor->GetAttentionTargetType() == AITARGET_VISUAL &&
  1348.                             pAIActor->GetAttentionTargetThreat() == AITHREAT_AGGRESSIVE)
  1349.                         {
  1350.                                 liveTargetCount++;
  1351.                         }
  1352.  
  1353.                         enabledCount++;
  1354.                 }
  1355.  
  1356.                 CDebugDrawContext dc;
  1357.  
  1358.                 for (unsigned i = 0, n = m_reinforcementSpots.size(); i < n; ++i)
  1359.                 {
  1360.                         if (m_reinforcementSpots[i].pAI->IsEnabled())
  1361.                         {
  1362.                                 string text;
  1363.                                 char msg[64];
  1364.  
  1365.                                 if (m_reinforcementState == REINF_NONE)
  1366.                                 {
  1367.                                         if (m_reinforcementSpots[i].whenAllAlerted)
  1368.                                         {
  1369.                                                 cry_sprintf(msg, "ALERTED: Alerted >= Enabled | %d >= %d", alertedCount, enabledCount);
  1370.                                                 text += msg;
  1371.                                                 if (alertedCount >= enabledCount)
  1372.                                                         text += " Active!\n";
  1373.                                                 else
  1374.                                                         text += "\n";
  1375.                                         }
  1376.  
  1377.                                         if (m_reinforcementSpots[i].whenInCombat)
  1378.                                         {
  1379.                                                 if (enabledCount > 1)
  1380.                                                         cry_sprintf(msg, "COMBAT: InCombat > 0 && LiveTarget > 1 | %d > 0 && %d > 1", combatCount, liveTargetCount);
  1381.                                                 else
  1382.                                                         cry_sprintf(msg, "COMBAT: InCombat > 0 && LiveTarget > 0 | %d > 0 && %d > 0", combatCount, liveTargetCount);
  1383.                                                 text += msg;
  1384.  
  1385.                                                 if (combatCount > 0 && ((enabledCount > 1 && liveTargetCount > 1) || (enabledCount == 1 && liveTargetCount > 0)))
  1386.                                                         text += " Active!\n";
  1387.                                                 else
  1388.                                                         text += "\n";
  1389.                                         }
  1390.                                 }
  1391.  
  1392.                                 if (m_reinforcementState == REINF_NONE /*|| m_reinforcementState == REINF_ALERTED_COMBAT*/)
  1393.                                 {
  1394.                                         if (m_reinforcementSpots[i].groupBodyCount > 0)
  1395.                                         {
  1396.                                                 cry_sprintf(msg, "SIZE: Bodies < Count | %d < %d",
  1397.                                                             m_reinforcementSpots[i].groupBodyCount, m_countDead);
  1398.                                                 text += msg;
  1399.  
  1400.                                                 if (m_countDead >= m_reinforcementSpots[i].groupBodyCount)
  1401.                                                         text += " >>>\n";
  1402.                                                 else
  1403.                                                         text += "\n";
  1404.                                         }
  1405.                                 }
  1406.                                 dc->Draw3dLabel(m_reinforcementSpots[i].pAI->GetPos() + Vec3(0, 0, 1), 1.5f, "%s", text.c_str());
  1407.                         }
  1408.                         else
  1409.                         {
  1410.                                 dc->Draw3dLabel(m_reinforcementSpots[i].pAI->GetPos() + Vec3(0, 0, 1), 1.0f, "Disabled");
  1411.                         }
  1412.  
  1413.                         ColorB color, colorTrans;
  1414.                         int c = m_reinforcementSpots[i].type % 3;
  1415.                         if (c == 0)
  1416.                                 color.set(255, 64, 64, 255);
  1417.                         else if (c == 1)
  1418.                                 color.set(64, 255, 64, 255);
  1419.                         else if (c == 2)
  1420.                                 color.set(64, 64, 255, 255);
  1421.                         colorTrans = color;
  1422.                         colorTrans.a = 64;
  1423.  
  1424.                         if (!m_reinforcementSpots[i].pAI->IsEnabled())
  1425.                         {
  1426.                                 color.a /= 4;
  1427.                                 colorTrans.a /= 4;
  1428.                         }
  1429.  
  1430.                         dc->DrawCylinder(m_reinforcementSpots[i].pAI->GetPos() + Vec3(0, 0, 0.5f), Vec3(0, 0, 1), 0.2f, 1.0f, color);
  1431.                         dc->DrawRangeCircle(m_reinforcementSpots[i].pAI->GetPos(), m_reinforcementSpots[i].pAI->GetRadius(), 1.0f, colorTrans, color, true);
  1432.  
  1433.                         if (m_reinforcementSpots[i].pAI->IsEnabled())
  1434.                         {
  1435.                                 for (TUnitList::const_iterator it = m_Units.begin(), end = m_Units.end(); it != end; ++it)
  1436.                                 {
  1437.                                         CPuppet* pPuppet = CastToCPuppetSafe(it->m_refUnit.GetAIObject());
  1438.                                         if (!pPuppet) continue;
  1439.                                         totalCount++;
  1440.                                         if (!pPuppet->IsEnabled()) continue;
  1441.                                         if (pPuppet->GetProxy()->IsCurrentBehaviorExclusive()) continue;
  1442.  
  1443.                                         if (Distance::Point_PointSq(pPuppet->GetPos(), m_reinforcementSpots[i].pAI->GetPos()) < sqr(m_reinforcementSpots[i].pAI->GetRadius()))
  1444.                                                 dc->DrawLine(pPuppet->GetPos(), color + Vec3(0, 0, 0.5f), m_reinforcementSpots[i].pAI->GetPos() + Vec3(0, 0, 0.5f), color);
  1445.                                 }
  1446.                         }
  1447.                 }
  1448.  
  1449. #ifdef CRYAISYSTEM_DEBUG
  1450.                 for (unsigned i = 0, n = m_DEBUG_reinforcementCalls.size(); i < n; ++i)
  1451.                 {
  1452.                         const Vec3& pos = m_DEBUG_reinforcementCalls[i].from;
  1453.                         Vec3 dir = m_DEBUG_reinforcementCalls[i].to - m_DEBUG_reinforcementCalls[i].from;
  1454.                         dc->DrawArrow(pos, dir, 0.5f, ColorB(255, 255, 255));
  1455.  
  1456.                         float len = dir.NormalizeSafe();
  1457.                         dir *= min(2.0f, len);
  1458.  
  1459.                         dc->Draw3dLabel(pos + dir, 1.0f, "%s", m_DEBUG_reinforcementCalls[i].performer.c_str());
  1460.                 }
  1461. #endif
  1462.         }
  1463. }
  1464.  
  1465. //====================================================================
  1466. // NotifyReinfDone
  1467. //====================================================================
  1468. void CAIGroup::NotifyReinfDone(const IAIObject* obj, bool isDone)
  1469. {
  1470.         CAIObject* pReinfPendingUnit = m_refReinfPendingUnit.GetAIObject();
  1471.         if (!pReinfPendingUnit)
  1472.                 return;
  1473.  
  1474.         if (pReinfPendingUnit != obj)
  1475.         {
  1476.                 AIWarning("CAIGroup::NotifyReinfDone - pending unit missMatch (internal %s ; passed %s)", pReinfPendingUnit->GetName(), obj->GetName());
  1477.                 AIAssert(0);
  1478.                 return;
  1479.         }
  1480.         if (/*m_reinforcementState != REINF_ALERTED_COMBAT_PENDING &&*/
  1481.           m_reinforcementState != REINF_DONE_PENDING)
  1482.         {
  1483.                 AIWarning("CAIGroup::NotifyReinfDone - not pending state (Puppet %s ; state %d)", obj->GetName(), m_reinforcementState);
  1484.                 AIAssert(0);
  1485.                 return;
  1486.         }
  1487.         if (isDone)
  1488.         {
  1489.                 // Change state
  1490.                 /*if (m_reinforcementState == REINF_ALERTED_COMBAT_PENDING)
  1491.                    m_reinforcementState = REINF_ALERTED_COMBAT;
  1492.                    else */if (m_reinforcementState == REINF_DONE_PENDING)
  1493.                         m_reinforcementState = REINF_DONE;
  1494.  
  1495.                 // Remove the spot
  1496.                 if (m_pendingDecSpotsAllAlerted)
  1497.                         m_reinforcementSpotsAllAlerted--;
  1498.                 if (m_pendingDecSpotsCombat)
  1499.                         m_reinforcementSpotsCombat--;
  1500.                 if (m_pendingDecSpotsBodyCount)
  1501.                         m_reinforcementSpotsBodyCount--;
  1502.         }
  1503.         else
  1504.         {
  1505.                 // Change state
  1506.                 //if (m_reinforcementState == REINF_ALERTED_COMBAT_PENDING)
  1507.                 m_reinforcementState = REINF_NONE;
  1508.                 //else if (m_reinforcementState == REINF_DONE_PENDING)
  1509.                 //      m_reinforcementState = REINF_ALERTED_COMBAT;
  1510.         }
  1511.         m_refReinfPendingUnit.Reset();
  1512. }
  1513.  
  1514. bool CAIGroup::EnterGroupScope(const CAIActor* pMember, const GroupScopeID scopeID, const uint32 allowedConcurrentUsers)
  1515. {
  1516.         TUnitList::iterator theUnit = std::find(m_Units.begin(), m_Units.end(), pMember);
  1517.         IF_UNLIKELY (theUnit == m_Units.end())
  1518.                 return false;
  1519.  
  1520.         IF_UNLIKELY (GetAmountOfActorsInScope(scopeID) >= allowedConcurrentUsers)
  1521.         {
  1522.                 return false;
  1523.         }
  1524.  
  1525.         const tAIObjectID memberId = pMember->GetAIObjectID();
  1526.         IF_UNLIKELY (m_groupScopes.find(memberId) != m_groupScopes.end())
  1527.         {
  1528.                 return false;
  1529.         }
  1530.  
  1531.         m_groupScopes[scopeID].insert(memberId);
  1532.         return true;
  1533. }
  1534.  
  1535. void CAIGroup::LeaveGroupScope(const CAIActor* pMember, const GroupScopeID scopeID)
  1536. {
  1537.         GroupScopes::iterator scopeIt = m_groupScopes.find(scopeID);
  1538.         if (scopeIt == m_groupScopes.end())
  1539.         {
  1540.                 return;
  1541.         }
  1542.  
  1543.         const tAIObjectID memberId = pMember->GetAIObjectID();
  1544.         MembersInScope& membersInScope = scopeIt->second;
  1545.         MembersInScope::iterator memberInScopeIt = membersInScope.find(memberId);
  1546.         if (memberInScopeIt == membersInScope.end())
  1547.         {
  1548.                 return;
  1549.         }
  1550.  
  1551.         membersInScope.erase(memberInScopeIt);
  1552.         if (membersInScope.empty())
  1553.         {
  1554.                 m_groupScopes.erase(scopeIt);
  1555.         }
  1556. }
  1557.  
  1558. void CAIGroup::LeaveAllGroupScopesForActor(const CAIActor* pMember)
  1559. {
  1560.         const tAIObjectID memberId = pMember->GetAIObjectID();
  1561.  
  1562.         GroupScopes::iterator scopeIt = m_groupScopes.begin();
  1563.         while (scopeIt != m_groupScopes.end())
  1564.         {
  1565.                 MembersInScope& membersInScope = scopeIt->second;
  1566.                 MembersInScope::iterator memberInScopeIt = membersInScope.find(memberId);
  1567.                 if (memberInScopeIt != membersInScope.end())
  1568.                 {
  1569.                         membersInScope.erase(memberInScopeIt);
  1570.                         if (membersInScope.empty())
  1571.                         {
  1572.                                 m_groupScopes.erase(scopeIt++); // Delete current entry and move on to the next.
  1573.                         }
  1574.                         else
  1575.                         {
  1576.                                 ++scopeIt;
  1577.                         }
  1578.                 }
  1579.                 else
  1580.                 {
  1581.                         ++scopeIt;
  1582.                 }
  1583.         }
  1584. }
  1585.  
  1586. uint32 CAIGroup::GetAmountOfActorsInScope(const GroupScopeID scopeID) const
  1587. {
  1588.         const GroupScopes::const_iterator scopeIt = m_groupScopes.find(scopeID);
  1589.         if (scopeIt == m_groupScopes.end())
  1590.         {
  1591.                 // No-one has entered the scope, so it doesn't exist.
  1592.                 return 0;
  1593.         }
  1594.  
  1595.         const MembersInScope& membersInScope = scopeIt->second;
  1596.         return membersInScope.size();
  1597. }
  1598.  
  1599. GroupScopeID CAIGroup::GetGroupScopeId(const char* scopeName)
  1600. {
  1601.         IF_UNLIKELY (scopeName == NULL)
  1602.         {
  1603.                 assert(false);
  1604.                 return (GroupScopeID)0;
  1605.         }
  1606.         return (GroupScopeID)(CCrc32::ComputeLowercase(scopeName));
  1607. }
  1608.  
downloadAIGroup.cpp Source code - Download CRYENGINE Source code
Related Source Codes/Software:
postal - 2017-06-11
reactide - Reactide is the first dedicated IDE for React web ... 2017-06-11
rkt - rkt is a pod-native container engine for Linux. It... 2017-06-11
uWebSockets - Tiny WebSockets https://for... 2017-06-11
realworld - TodoMVC for the RealWorld - Exemplary fullstack Me... 2017-06-11
CRYENGINE - CRYENGINE is a powerful real-time game development... 2017-06-11
goreplay - GoReplay is an open-source tool for capturing and ... 2017-06-10
pyenv - Simple Python version management 2017-06-10
redux-saga - An alternative side effect model for Redux apps ... 2017-06-10
angular-starter - 2017-06-10

 Back to top