BVB Source Codes

CRYENGINE Show LeaderAction.cpp Source code

Return Download CRYENGINE: download LeaderAction.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:   LeaderAction.cpp
  6.  
  7.    Description: Class Implementation for CLeaderAction (and inherited)
  8.  
  9.    -------------------------------------------------------------------------
  10.    History:
  11.    - 15:11:2004   17:46 : Created by Luciano Morpurgo
  12.    - 2:6:2005   15:23 : Kirill Bulatsev - serialization support added, related refactoring/cleanup
  13.  
  14.  
  15.  *********************************************************************/
  16.  
  17. #include "StdAfx.h"
  18. #include "LeaderAction.h"
  19. #include "AILog.h"
  20. #include "GoalOp.h"
  21. #include "Puppet.h"
  22. #include "Leader.h"
  23. #include "AIPlayer.h"
  24. #include "CAISystem.h"
  25. #include <set>
  26. #include <algorithm>
  27. #include <utility>
  28. #include <CryEntitySystem/IEntitySystem.h>
  29. #include <CrySystem/ISystem.h>
  30. #include <CrySystem/ITimer.h>
  31. #include <CrySystem/IConsole.h>
  32. #include <CryNetwork/ISerialize.h>
  33. #include "AICollision.h"
  34. #include "HideSpot.h"
  35.  
  36. const float CLeaderAction_Attack::m_CSearchDistance = 30.f;
  37.  
  38. const float CLeaderAction_Search::m_CSearchDistance = 15.f;
  39. const uint32 CLeaderAction_Search::m_CCoverUnitProperties = UPR_COMBAT_GROUND;
  40. const float CLeaderAction_Attack_SwitchPositions::m_fDefaultMinDistance = 6;
  41.  
  42. CLeaderAction::CLeaderAction()
  43.         : m_pLeader(nullptr)
  44.         , m_eActionType(LA_NONE)
  45.         , m_eActionSubType(LAS_DEFAULT)
  46.         , m_Priority(0)
  47.         , m_unitProperties(UPR_ALL)
  48.         , m_currentNavType(IAISystem::NAV_UNSET)
  49.         , m_NavProperties()
  50. {
  51. }
  52.  
  53. CLeaderAction::CLeaderAction(CLeader* pLeader)
  54.         : m_pLeader(pLeader)
  55.         , m_eActionType(LA_NONE)
  56.         , m_eActionSubType(LAS_DEFAULT)
  57.         , m_Priority(0)
  58.         , m_unitProperties(UPR_ALL)
  59.         , m_currentNavType(IAISystem::NAV_UNSET)
  60.         , m_NavProperties()
  61. {
  62. }
  63.  
  64. CLeaderAction::~CLeaderAction()
  65. {
  66.         TUnitList::iterator itEnd = GetUnitsList().end();
  67.         for (TUnitList::iterator unitItr = GetUnitsList().begin(); unitItr != itEnd; ++unitItr)
  68.         {
  69.                 CUnitImg& curUnit = (*unitItr);
  70.                 curUnit.ClearPlanning(m_Priority);
  71.                 curUnit.ClearFlags();
  72.         }
  73. }
  74.  
  75. TUnitList& CLeaderAction::GetUnitsList() const
  76. {
  77.         return m_pLeader->GetAIGroup()->GetUnits();
  78. }
  79.  
  80. //////////////////////////////////////////////////////////////////////////
  81. bool CLeaderAction::IsUnitTooFar(const CUnitImg& tUnit, const Vec3& vPos) const
  82. {
  83.         // TODO: check if it was blocked by something or was leading the player
  84.         // through the map.
  85.  
  86.         CAIActor* pUnitAIActor = tUnit.m_refUnit.GetAIObject();
  87.         assert(pUnitAIActor);
  88.  
  89.         if (!pUnitAIActor->IsEnabled())
  90.                 return false;
  91.  
  92.         const float fMaxDist = 15.0f;
  93.         if ((pUnitAIActor->GetPos() - vPos).GetLengthSquared() > (fMaxDist * fMaxDist))
  94.                 return true;
  95.  
  96.         CCCPOINT(CLeaderAction_IsUnitTooFar);
  97.  
  98.         return false;
  99. }
  100.  
  101. void CLeaderAction::ClearUnitFlags()
  102. {
  103.         TUnitList::iterator itEnd = GetUnitsList().end();
  104.         for (TUnitList::iterator unitItr = GetUnitsList().begin(); unitItr != itEnd; ++unitItr)
  105.         {
  106.                 CCCPOINT(CLeaderAction_ClearUnitFlags);
  107.  
  108.                 CUnitImg& curUnit = (*unitItr);
  109.                 curUnit.ClearFlags();
  110.                 curUnit.m_Group = 0;
  111.         }
  112. }
  113.  
  114. bool CLeaderAction::IsUnitAvailable(const CUnitImg& unit) const
  115. {
  116.         CCCPOINT(CLeaderAction_IsUnitAvailable);
  117.  
  118.         return (unit.GetProperties() & m_unitProperties) && unit.m_refUnit.GetAIObject()->IsEnabled();
  119. }
  120.  
  121. void CLeaderAction::DeadUnitNotify(CAIActor* pUnit)
  122. {
  123.         // by default for all Leader actions, the dead unit's remaining actions are deleted
  124.         // and their blocked actions are unlocked (for each Unit Action's destructor)
  125.         TUnitList::iterator itUnit = m_pLeader->GetAIGroup()->GetUnit(pUnit);
  126.         if (itUnit != m_pLeader->GetAIGroup()->GetUnits().end())
  127.                 itUnit->ClearPlanning();
  128. }
  129.  
  130. void CLeaderAction::BusyUnitNotify(CUnitImg& BusyUnit)
  131. {
  132. }
  133.  
  134. int CLeaderAction::GetNumLiveUnits()  const
  135. {
  136.         // since dead unit were removed from this list just return its size
  137.         return GetUnitsList().size();
  138.  
  139. }
  140.  
  141. CUnitImg* CLeaderAction::GetFormationOwnerImg() const
  142. {
  143.         // Return pointer to the unit image of the group formation owner.
  144.         TUnitList::iterator itEnd = GetUnitsList().end();
  145.         for (TUnitList::iterator unitItr = GetUnitsList().begin(); unitItr != itEnd; ++unitItr)
  146.         {
  147.                 CUnitImg& unit = *unitItr;
  148.                 if (m_pLeader->GetFormationOwner() == unit.m_refUnit)
  149.                 {
  150.                         CCCPOINT(CLeaderAction_GetFormationOwnerImg)
  151.                         return &unit;
  152.                 }
  153.         }
  154.         return 0;
  155. }
  156.  
  157. void CLeaderAction::CheckNavType(CAIActor* pMember, bool bSignal)
  158. {
  159.         int building;
  160.         IAISystem::ENavigationType navType = gAIEnv.pNavigation->CheckNavigationType(pMember->GetPos(), building, m_NavProperties);
  161.         if (navType != m_currentNavType && bSignal)
  162.         {
  163.                 IAISignalExtraData* pData = GetAISystem()->CreateSignalExtraData();
  164.                 pData->iValue = navType;
  165.                 GetAISystem()->SendSignal(SIGNALFILTER_SENDER, 1, "OnNavTypeChanged", pMember, pData);
  166.  
  167.                 CCCPOINT(CLeaderAction_CheckNavType);
  168.         }
  169.         m_currentNavType = navType;
  170. }
  171.  
  172. void CLeaderAction::SetTeamNavProperties()
  173. {
  174.         m_NavProperties = 0;
  175.         CWeakRef<CAIObject> refFormationOwner = m_pLeader->GetFormationOwner();
  176.         TUnitList::iterator itEnd = GetUnitsList().end();
  177.         for (TUnitList::iterator it = GetUnitsList().begin(); it != itEnd; ++it)
  178.         {
  179.                 CUnitImg& unit = *it;
  180.                 CAIObject* pUnit = unit.m_refUnit.GetAIObject();
  181.                 CAIActor* pAIActor = pUnit->CastToCAIActor();
  182.                 if (pAIActor && (unit.GetProperties() & m_unitProperties) && pUnit->IsEnabled() && unit.m_refUnit != refFormationOwner)
  183.                         m_NavProperties |= pAIActor->GetMovementAbility().pathfindingProperties.navCapMask;
  184.  
  185.                 CCCPOINT(CLeaderAction_SetTeamNavProperties);
  186.         }
  187. }
  188.  
  189. void CLeaderAction::UpdateBeacon() const
  190. {
  191.         if (!m_pLeader->GetAIGroup()->GetLiveEnemyAveragePosition().IsZero())
  192.                 GetAISystem()->UpdateBeacon(m_pLeader->GetGroupId(), m_pLeader->GetAIGroup()->GetLiveEnemyAveragePosition(), m_pLeader);
  193.         else if (!m_pLeader->GetAIGroup()->GetEnemyAveragePosition().IsZero())
  194.                 GetAISystem()->UpdateBeacon(m_pLeader->GetGroupId(), m_pLeader->GetAIGroup()->GetEnemyAveragePosition(), m_pLeader);
  195.         Vec3 vEnemyDir = m_pLeader->GetAIGroup()->GetEnemyAverageDirection(true, false);
  196.         if (!vEnemyDir.IsZero())
  197.         {
  198.                 IAIObject* pBeacon = GetAISystem()->GetBeacon(m_pLeader->GetGroupId());
  199.                 if (pBeacon)
  200.                 {
  201.                         pBeacon->SetEntityDir(vEnemyDir);
  202.                         pBeacon->SetMoveDir(vEnemyDir);
  203.                 }
  204.                 else
  205.                 {
  206.                         AIError("Unable to get beacon for group id %d", m_pLeader->GetGroupId());
  207.                 }
  208.  
  209.                 CCCPOINT(CLeaderAction_UpdateBeacon);
  210.         }
  211. }
  212.  
  213. void CLeaderAction::CheckLeaderDistance() const
  214. {
  215.         // Check if some unit is too back
  216.         CAIObject* pAILeader = m_pLeader->GetAssociation().GetAIObject();
  217.         if (pAILeader)
  218.         {
  219.                 TUnitList::iterator itEnd = GetUnitsList().end();
  220.                 for (TUnitList::iterator unitItr = GetUnitsList().begin(); unitItr != itEnd; ++unitItr)
  221.                 {
  222.                         CAIActor* pUnitActor = CastToCAIActorSafe((*unitItr).m_refUnit.GetAIObject());
  223.                         if (pUnitActor && pUnitActor->IsEnabled())
  224.                         {
  225.                                 CCCPOINT(CLeaderAction_CheckLeaderDistance);
  226.  
  227.                                 static const float maxdist2 = 18 * 18;
  228.                                 float dist2 = Distance::Point_PointSq(pUnitActor->GetPos(), pAILeader->GetPos());
  229.                                 if (dist2 > maxdist2 && !unitItr->IsFar())
  230.                                 {
  231.                                         pUnitActor->SetSignal(1, "OnLeaderTooFar", (IEntity*)(pAILeader->GetAssociation().GetAIObject()), 0, gAIEnv.SignalCRCs.m_nOnLeaderTooFar);
  232.                                         unitItr->SetFar();
  233.                                 }
  234.                                 else
  235.                                         unitItr->ClearFar();
  236.                         }
  237.                 }
  238.         }
  239. }
  240. //-----------------------------------------------------------
  241. //----  SEARCH
  242. //-----------------------------------------------------------
  243.  
  244. CLeaderAction_Search::CLeaderAction_Search(CLeader* pLeader, const LeaderActionParams& params)
  245.         : CLeaderAction(pLeader)
  246.         , m_timeRunning(0.0f)
  247. {
  248.  
  249.         m_eActionType = LA_SEARCH;
  250.         m_iSearchSpotAIObjectType = params.iValue ? params.iValue : AIANCHOR_COMBAT_HIDESPOT;
  251.         m_bUseHideSpots = (m_iSearchSpotAIObjectType & AI_USE_HIDESPOTS) != 0;
  252.         m_iSearchSpotAIObjectType &= ~AI_USE_HIDESPOTS;
  253.  
  254.         m_unitProperties = params.unitProperties;
  255.         m_fSearchDistance = params.fSize > 0 ? params.fSize : m_CSearchDistance;
  256.  
  257.         // TO DO : use customized m_fSearchDistance (now there's a 15 hardcoded in GetEnclosing()
  258.  
  259.         Vec3 initPos = params.vPoint;
  260.  
  261.         if (params.subType == LAS_SEARCH_COVER)
  262.         {
  263.                 int numFiringUnits = m_pLeader->GetAIGroup()->GetUnitCount(m_CCoverUnitProperties);
  264.                 m_iCoverUnitsLeft = numFiringUnits * 2 / 5;
  265.                 if (m_iCoverUnitsLeft == 0 && numFiringUnits > 0)
  266.                         m_iCoverUnitsLeft = 1;
  267.         }
  268.         else
  269.                 m_iCoverUnitsLeft = 0;
  270.  
  271.         TUnitList::iterator itEnd = GetUnitsList().end();
  272.         for (TUnitList::iterator unitItr = GetUnitsList().begin(); unitItr != itEnd; ++unitItr)
  273.                 unitItr->ClearHiding();
  274.  
  275.         m_vEnemyPos = ZERO;
  276.         m_bInitialized = false;
  277.         PopulateSearchSpotList(initPos);
  278.  
  279. }
  280.  
  281. void CLeaderAction_Search::PopulateSearchSpotList(Vec3& initPos)
  282. {
  283.         float maxdist2 = m_fSearchDistance * m_fSearchDistance;
  284.         Vec3 avgPos = m_pLeader->GetAIGroup()->GetAveragePosition(IAIGroup::AVMODE_PROPERTIES, m_unitProperties);
  285.         if (initPos.IsZero())
  286.                 initPos = m_pLeader->GetMarkedPosition();
  287.         if (initPos.IsZero())
  288.                 initPos = avgPos;
  289.  
  290.         Vec3 currentEnemyPos(m_pLeader->GetAIGroup()->GetEnemyAveragePosition());
  291.  
  292.         if (!currentEnemyPos.IsZero())
  293.                 m_vEnemyPos = currentEnemyPos;
  294.         else
  295.                 m_vEnemyPos = initPos;
  296.  
  297.         if (m_vEnemyPos.IsZero())
  298.         {
  299.                 IAIObject* pBeacon = GetAISystem()->GetBeacon(m_pLeader->GetGroupId());
  300.                 if (pBeacon)
  301.                         m_vEnemyPos = pBeacon->GetPos();
  302.                 if (m_vEnemyPos.IsZero())
  303.                         return;
  304.         }
  305.  
  306.         CCCPOINT(CLeaderAction_PopulateSearchSpotList);
  307.  
  308.         bool bCleared = false;
  309.         if (m_iSearchSpotAIObjectType > 0)
  310.         {
  311.                 for (AutoAIObjectIter it(gAIEnv.pAIObjectManager->GetFirstAIObject(OBJFILTER_TYPE, m_iSearchSpotAIObjectType)); it->GetObject(); it->Next())
  312.                 {
  313.                         IAIObject* pObjectIt = it->GetObject();
  314.                         const Vec3& objPos = pObjectIt->GetPos();
  315.                         const Vec3& objDir = pObjectIt->GetViewDir();
  316.                         if (!pObjectIt->IsEnabled()) // || pPipeUser->IsDevalued(pObjectIt))
  317.                                 continue;
  318.                         float dist2 = Distance::Point_PointSq(m_vEnemyPos, objPos);
  319.                         if (dist2 < maxdist2)
  320.                         {
  321.                                 if (!bCleared)
  322.                                 {
  323.                                         // clear the list only if some new spots are actually found around new init position
  324.                                         m_HideSpots.clear();
  325.                                         bCleared = true;
  326.                                 }
  327.                                 m_HideSpots.insert(std::make_pair(dist2, SSearchPoint(objPos, objDir)));
  328.                         }
  329.                 }
  330.         }
  331.  
  332.         TUnitList::iterator itEnd = GetUnitsList().end();
  333.         for (TUnitList::iterator it = GetUnitsList().begin(); it != itEnd; ++it)
  334.         {
  335.                 CUnitImg& unit = *it;
  336.                 unit.m_TagPoint = ZERO;
  337.                 CAIActor* pAIActor = CastToCAIActorSafe(unit.m_refUnit.GetAIObject());
  338.                 if (pAIActor)
  339.                 {
  340.                         CAIObject* pTarget = (CAIObject*)pAIActor->GetAttentionTarget();
  341.                         if (pTarget && pTarget->GetType() == AIOBJECT_DUMMY &&
  342.                             (pTarget->GetSubType() == IAIObject::STP_MEMORY || pTarget->GetSubType() == IAIObject::STP_SOUND))
  343.                         {
  344.                                 bool bAlreadyChecked = false;
  345.                                 Vec3 memoryPos(pTarget->GetPos());
  346.                                 // check if some other guy is not already checking a nearby point
  347.                                 TPointMap::iterator it1 = m_HideSpots.begin(), itend1 = m_HideSpots.end();
  348.                                 for (; it1 != itend1; ++it1)
  349.                                 {
  350.  
  351.                                         if (Distance::Point_Point2DSq(memoryPos, it1->second.pos) < 1)
  352.                                         {
  353.                                                 bAlreadyChecked = true;
  354.                                                 break;
  355.                                         }
  356.                                 }
  357.                                 if (!bAlreadyChecked)
  358.                                 {
  359.                                         float dist2 = Distance::Point_PointSq(memoryPos, m_vEnemyPos);
  360.                                         if (!bCleared)
  361.                                         {
  362.                                                 // clear the list only if some new spots are actually found around new init position
  363.                                                 m_HideSpots.clear();
  364.                                                 bCleared = true;
  365.                                         }
  366.                                         m_HideSpots.insert(std::make_pair(dist2, SSearchPoint(memoryPos, pTarget->GetViewDir())));
  367.                                 }
  368.                         }
  369.                 }
  370.         }
  371.  
  372.         if (m_bUseHideSpots)
  373.         {
  374.                 TUnitList::iterator itu = GetUnitsList().begin();
  375.                 if (itu != itEnd)
  376.                 {
  377.                         CUnitImg& unit = *itu;
  378.                         const CAIActor* pActor = unit.m_refUnit.GetAIObject();
  379.  
  380.                         MultimapRangeHideSpots hidespots;
  381.                         MapConstNodesDistance traversedNodes;
  382.                         GetAISystem()->GetHideSpotsInRange(hidespots, traversedNodes, m_vEnemyPos, m_fSearchDistance,
  383.                                                            pActor->m_movementAbility.pathfindingProperties.navCapMask, pActor->GetParameters().m_fPassRadius, false);
  384.  
  385.                         MultimapRangeHideSpots::iterator it = hidespots.begin(), ithend = hidespots.end();
  386.                         for (; it != ithend; ++it)
  387.                         {
  388.                                 float distance = it->first;
  389.                                 const SHideSpot& hs = it->second;
  390.                                 Vec3 pos(hs.info.pos);
  391.                                 if (hs.info.type == SHideSpotInfo::eHST_TRIANGULAR && hs.pObstacle)
  392.                                 {
  393.                                         Vec3 dir = (pos - m_vEnemyPos).GetNormalizedSafe();
  394.                                         pos += dir * (hs.pObstacle->fApproxRadius + 0.5f + 2 * pActor->m_movementAbility.pathRadius);
  395.                                 }
  396.                                 if (!bCleared)
  397.                                 {
  398.                                         // clear the list only if some new spots are actually found around new init position
  399.                                         m_HideSpots.clear();
  400.                                         bCleared = true;
  401.                                 }
  402.                                 m_HideSpots.insert(std::make_pair(distance * distance, SSearchPoint(pos, -hs.info.dir, true)));
  403.                         }
  404.  
  405.                 }
  406.         }
  407.  
  408.         if (!m_vEnemyPos.IsZero())
  409.         {
  410.                 // add at least one point
  411.                 Vec3 dir(m_vEnemyPos - avgPos);
  412.                 m_HideSpots.insert(std::make_pair(dir.GetLengthSquared(), SSearchPoint(m_vEnemyPos, dir.GetNormalizedSafe())));
  413.  
  414.         }
  415.  
  416.         // DEBUG
  417.         if (gAIEnv.CVars.DebugDraw == 1)
  418.         {
  419.                 TPointMap::iterator it = m_HideSpots.begin(), ithend = m_HideSpots.end();
  420.                 for (; it != ithend; ++it)
  421.                 {
  422.                         GetAISystem()->AddDebugSphere(it->second.pos + Vec3(0, 0, 1), 0.3f, 255, 0, 255, 8);
  423.                         GetAISystem()->AddDebugLine(it->second.pos + Vec3(0, 0, 1), it->second.pos + Vec3(0, 0, -3), 255, 0, 255, 8);
  424.                 }
  425.                 GetAISystem()->AddDebugSphere(m_vEnemyPos + Vec3(0, 0, 2), 0.5f, 255, 128, 255, 8);
  426.                 GetAISystem()->AddDebugLine(m_vEnemyPos + Vec3(0, 0, 2), m_vEnemyPos + Vec3(0, 0, -3), 255, 128, 255, 8);
  427.         }
  428. }
  429.  
  430. CLeaderAction_Search::~CLeaderAction_Search()
  431. {
  432. }
  433.  
  434. bool CLeaderAction_Search::ProcessSignal(const AISIGNAL& signal)
  435. {
  436.         IEntity* pEntity = gEnv->pEntitySystem->GetEntity(signal.senderID);
  437.  
  438.         if (signal.Compare(gAIEnv.SignalCRCs.m_nOnUnitMoving))
  439.         {
  440.                 CAIActor* pUnit = CastToCAIActorSafe(pEntity->GetAI());
  441.                 if (pUnit)
  442.                 {
  443.                         TUnitList::iterator itUnit = m_pLeader->GetAIGroup()->GetUnit(pUnit);
  444.                         if (itUnit != GetUnitsList().end())
  445.                         {
  446.                                 Vec3 hidepos(itUnit->m_TagPoint);
  447.                                 TPointMap::iterator it = m_HideSpots.begin(), itend = m_HideSpots.end();
  448.                                 for (; it != itend; ++it)
  449.                                         if (it->second.pos == hidepos)
  450.                                         {
  451.                                                 m_HideSpots.erase(it);
  452.                                                 itUnit->SetMoving();
  453.                                                 break;
  454.                                         }
  455.                         }
  456.  
  457.                 }
  458.                 return true;
  459.         }
  460.         else if (signal.Compare(gAIEnv.SignalCRCs.m_nOnUnitStop))
  461.         {
  462.                 // unit can't reach an assigned hidespot
  463.                 CAIActor* pUnit = CastToCAIActorSafe(pEntity->GetAI());
  464.                 if (pUnit)
  465.                 {
  466.                         TUnitList::iterator itUnit = m_pLeader->GetAIGroup()->GetUnit(pUnit);
  467.                         if (itUnit != GetUnitsList().end())
  468.                         {
  469.                                 Vec3 hidepos(itUnit->m_TagPoint);
  470.                                 TPointMap::iterator it = m_HideSpots.begin(), itend = m_HideSpots.end();
  471.                                 for (; it != itend; ++it)
  472.                                         if (it->second.pos == hidepos)
  473.                                         {
  474.                                                 m_HideSpots.erase(it);// assume that no other unit can reach it, just remove it
  475.                                                 break;
  476.                                         }
  477.                                 itUnit->ClearPlanning();
  478.                         }
  479.  
  480.                 }
  481.                 return true;
  482.         }
  483.         else if (signal.Compare(gAIEnv.SignalCRCs.m_nOnUnitDamaged) || signal.Compare(gAIEnv.SignalCRCs.m_nAIORD_SEARCH))
  484.         {
  485.                 CAIActor* pUnit = CastToCAIActorSafe(pEntity->GetAI());
  486.                 if (pUnit)
  487.                 {
  488.                         TUnitList::iterator itUnit = m_pLeader->GetAIGroup()->GetUnit(pUnit);
  489.                         if (itUnit != GetUnitsList().end())
  490.                         {
  491.                                 Vec3 hidepos(itUnit->m_TagPoint);
  492.                                 TPointMap::iterator it = m_HideSpots.begin(), itend = m_HideSpots.end();
  493.                                 for (; it != itend; ++it)
  494.                                         if (it->second.pos == hidepos)
  495.                                         {
  496.                                                 it->second.bReserved = false;
  497.                                                 break;
  498.                                         }
  499.                                 //create new spot
  500.                                 if (signal.pEData)
  501.                                 {
  502.                                         m_pLeader->ClearAllPlannings();
  503.                                         PopulateSearchSpotList(signal.pEData->point);
  504.                                 }
  505.                         }
  506.  
  507.                 }
  508.                 return true;
  509.         }
  510.         return false;
  511. }
  512.  
  513. CLeaderAction::eActionUpdateResult CLeaderAction_Search::Update()
  514. {
  515.         FRAME_PROFILER("CLeaderAction_Attack::CLeaderAction_Search", GetISystem(), PROFILE_AI);
  516.  
  517.         if (m_HideSpots.empty())
  518.         {
  519.                 bool bAllunitFinished = true;
  520.                 TUnitList::iterator itEnd = GetUnitsList().end();
  521.                 for (TUnitList::iterator unitItr = GetUnitsList().begin(); unitItr != itEnd; ++unitItr)
  522.                 {
  523.                         CUnitImg& curUnit = (*unitItr);
  524.                         if (!curUnit.IsPlanFinished())
  525.                         {
  526.                                 bAllunitFinished = false;
  527.                                 break;
  528.                         }
  529.                 }
  530.                 if (bAllunitFinished)
  531.                         return ACTION_DONE;
  532.         }
  533.  
  534.         m_timeRunning = GetAISystem()->GetFrameStartTime();
  535.  
  536.         bool busy = false;
  537.  
  538.         TUnitList::iterator it, itEnd = GetUnitsList().end();
  539.         for (it = GetUnitsList().begin(); it != itEnd; ++it)
  540.         {
  541.                 CUnitImg& unit = *it;
  542.                 if (unit.m_refUnit.GetAIObject()->IsEnabled() && (unit.IsPlanFinished() || !m_bInitialized))
  543.                 {
  544.                         // find cover fire units first
  545.                         if (m_iCoverUnitsLeft > 0 && (unit.GetProperties() & m_CCoverUnitProperties))
  546.                         {
  547.                                 AISignalExtraData data;
  548.                                 data.point = m_vEnemyPos;
  549.                                 data.point2 = m_pLeader->GetAIGroup()->GetAveragePosition(IAIGroup::AVMODE_PROPERTIES, m_unitProperties);
  550.                                 CUnitAction* pAction = new CUnitAction(UA_SIGNAL, true, "ORDER_COVER_SEARCH", data);
  551.                                 unit.m_Plan.push_back(pAction);
  552.                                 m_iCoverUnitsLeft--;
  553.                                 busy = true;
  554.  
  555.                                 CCCPOINT(CLeaderAction_Search_Update_A);
  556.                         }
  557.                         else // search units
  558.                         {
  559.                                 Vec3 unitPos(unit.m_refUnit.GetAIObject()->GetPos());
  560.                                 TPointMap::iterator oit = m_HideSpots.begin(), oend = m_HideSpots.end();
  561.                                 Vec3 obstaclePos(ZERO);
  562.                                 TPointMap::iterator itFound = oend;
  563.  
  564.                                 for (; oit != oend; ++oit)
  565.                                 {
  566.                                         SSearchPoint& hp = oit->second;
  567.                                         if (!hp.bReserved && unit.m_TagPoint != hp.pos)
  568.                                         {
  569.                                                 itFound = oit; // get the first obstacles (closer to enemy position)
  570.                                                 break;
  571.                                         }
  572.                                 }
  573.  
  574.                                 if (itFound != oend)
  575.                                 {
  576.                                         SSearchPoint& hp = itFound->second;
  577.                                         CUnitAction* action = new CUnitAction(UA_SEARCH, true, hp.pos, hp.dir);
  578.                                         action->m_Tag = hp.bHideSpot ? 1 : 0;
  579.                                         unit.m_Plan.push_back(action);
  580.                                         unit.m_TagPoint = hp.pos;
  581.                                         unit.ExecuteTask();
  582.                                         busy = true;
  583.                                         itFound->second.bReserved = true;
  584.  
  585.                                         CCCPOINT(CLeaderAction_Search_Update_B);
  586.                                 }
  587.                         }
  588.                 }
  589.                 else
  590.                         busy = true;
  591.         }
  592.  
  593.         m_bInitialized = true;
  594.  
  595.         return (busy ? ACTION_RUNNING : ACTION_DONE);
  596. }
  597.  
  598. //-----------------------------------------------------------
  599. //----  ATTACK
  600. //-----------------------------------------------------------
  601.  
  602. CLeaderAction_Attack::CLeaderAction_Attack(CLeader* pLeader)
  603.         : CLeaderAction(pLeader)
  604.         , m_bInitialized(false)
  605.         , m_bStealth(false)
  606.         , m_bApproachWithNoObstacle(false)
  607.         , m_bNoTarget(false)
  608.         , m_timeLimit(40.0f)
  609.         , m_vDefensePoint(ZERO)
  610.         , m_vEnemyPos(ZERO)
  611. {
  612.         m_eActionType = LA_ATTACK;
  613.         m_eActionSubType = LAS_DEFAULT;
  614.  
  615.         TUnitList::iterator itEnd = GetUnitsList().end();
  616.         for (TUnitList::iterator unitItr = GetUnitsList().begin(); unitItr != itEnd; ++unitItr)
  617.                 unitItr->ClearHiding();
  618.  
  619. }
  620.  
  621. CLeaderAction_Attack::CLeaderAction_Attack()
  622.         : CLeaderAction()
  623.         , m_bInitialized(false)
  624.         , m_bStealth(false)
  625.         , m_bApproachWithNoObstacle(false)
  626.         , m_bNoTarget(false)
  627.         , m_timeRunning()
  628.         , m_timeLimit(0)
  629.         , m_vDefensePoint(ZERO)
  630.         , m_vEnemyPos(ZERO)
  631. {
  632. }
  633.  
  634. CLeaderAction_Attack::~CLeaderAction_Attack()
  635. {
  636.         GetAISystem()->SendSignal(SIGNALFILTER_GROUPONLY, 1, "OnFireDisabled", m_pLeader);
  637. }
  638.  
  639. bool CLeaderAction_Attack::ProcessSignal(const AISIGNAL& signal)
  640. {
  641.         return false;
  642. }
  643.  
  644. //
  645. //----------------------------------------------------------------------------------------------------
  646. #define LEADERACTION_DEFAULT_DISTANCE_TO_TARGET 6.0f
  647.  
  648. CLeaderAction_Attack_SwitchPositions::CLeaderAction_Attack_SwitchPositions()
  649.         : m_fDistanceToTarget(LEADERACTION_DEFAULT_DISTANCE_TO_TARGET)
  650.         , m_fMinDistanceToTarget(0.0f)
  651.         , m_bVisibilityChecked(false)
  652.         , m_bPointsAssigned(false)
  653.         , m_bAvoidDanger(false)
  654.         , m_fMinDistanceToNextPoint(0.0f)
  655.         , m_vUpdatePointTarget(ZERO)
  656.         , m_fFormationSize(0.0f)
  657.         , m_fFormationScale(0.0f)
  658.         , m_pLiveTarget(nullptr)
  659. {
  660. }
  661.  
  662. CLeaderAction_Attack_SwitchPositions::CLeaderAction_Attack_SwitchPositions(CLeader* pLeader, const LeaderActionParams& params)
  663.         : m_fDistanceToTarget(LEADERACTION_DEFAULT_DISTANCE_TO_TARGET)
  664.         , m_bVisibilityChecked(false)
  665.         , m_bPointsAssigned(false)
  666.         , m_bAvoidDanger(false)
  667.         , m_fFormationSize(0.0f)
  668.         , m_fFormationScale(0.0f)
  669.         , m_pLiveTarget(NULL)
  670. {
  671.         CCCPOINT(CLeaderAction_Attack_SwitchPositions_CLA_A_SP);
  672.  
  673.         m_pLeader = pLeader;
  674.         m_eActionType = LA_ATTACK;
  675.         m_eActionSubType = LAS_ATTACK_SWITCH_POSITIONS;
  676.         m_bInitialized = false;
  677.         m_timeLimit = params.fDuration;
  678.         m_timeRunning = GetAISystem()->GetFrameStartTime();
  679.         m_sFormationType = params.name;
  680.         m_unitProperties = params.unitProperties;
  681.         // TO DO: make it variable and tweakable from script
  682.         m_fMinDistanceToNextPoint = m_fDefaultMinDistance;
  683.         m_PointProperties.reserve(50);
  684.         InitNavTypeData();
  685.         m_vUpdatePointTarget = ZERO;
  686.         m_fDistanceToTarget = 6;
  687.         m_fMinDistanceToTarget = 3;// below this distance, position will be discarded
  688. }
  689.  
  690. void CLeaderAction_Attack_SwitchPositions::UpdateBeaconWithTarget(const CAIObject* pTarget) const
  691. {
  692.         if (pTarget)
  693.                 GetAISystem()->UpdateBeacon(m_pLeader->GetGroupId(), pTarget->GetPos(), m_pLeader);
  694.         else
  695.                 CLeaderAction::UpdateBeacon();
  696. }
  697.  
  698. //
  699. //----------------------------------------------------------------------------------------------------
  700. void CLeaderAction_Attack_SwitchPositions::InitNavTypeData()
  701. {
  702.         m_TargetData.clear();
  703.         TUnitList::iterator itEnd = GetUnitsList().end();
  704.         for (TUnitList::iterator it = GetUnitsList().begin(); it != itEnd; ++it)
  705.         {
  706.                 CUnitImg& unit = *it;
  707.                 CAIActor* pAIActor = CastToCAIActorSafe(unit.m_refUnit.GetAIObject());
  708.                 if (pAIActor)
  709.                         m_TargetData.insert(std::make_pair(unit.m_refUnit, STargetData()));
  710.  
  711.                 CCCPOINT(CLeaderAction_Attack_SwitchPositions_INTD);
  712.         }
  713. }
  714.  
  715. void CLeaderAction_Attack_SwitchPositions::OnObjectRemoved(CAIObject* pObject)
  716. {
  717.         // (MATT) Caused entries in m_SpecialActions to be erase and values (not keys) in m_TargetData to go NULL {2009/03/13}
  718. }
  719. //
  720. //----------------------------------------------------------------------------------------------------
  721. void CLeaderAction_Attack_SwitchPositions::CheckNavType(CUnitImg& unit)
  722. {
  723.         // (MATT) Ensure this is a valid pipe user {2009/03/13}
  724.         CAIActor* const pMember = CastToCAIActorSafe(unit.m_refUnit.GetAIObject());
  725.         if (!pMember)
  726.                 return;
  727.  
  728.         // (MATT) Get attention target, if any, and find entry for this unit. Note: ref must have been valid to get this far {2009/03/13}
  729.         CAIObject* pTarget = (CAIObject*)pMember->GetAttentionTarget();
  730.         TMapTargetData::iterator it = m_TargetData.find(unit.m_refUnit);
  731.  
  732.         if (it == m_TargetData.end())
  733.                 return;
  734.  
  735.         CCCPOINT(CLeaderAction_Attack_SwitchPositions_CheckNavType);
  736.  
  737.         STargetData& tData = it->second;
  738.         tData.refTarget = GetWeakRefSafe(pTarget);
  739.  
  740.         int building;
  741.         IAISystem::ENavigationType navType = gAIEnv.pNavigation->CheckNavigationType(pMember->GetPos(), building, m_NavProperties);
  742.         if (pTarget && pTarget->GetAssociation().IsValid())
  743.                 //kind of cheat, but it's just to let the AI know in which navigation type the enemy went
  744.                 if (pTarget->GetSubType() == CAIObject::STP_MEMORY)// || pTarget->GetSubType()==CAIObject::STP_SOUND)
  745.                         pTarget = pTarget->GetAssociation().GetAIObject();
  746.  
  747.         IAISystem::ENavigationType targetNavType = (pTarget ? gAIEnv.pNavigation->CheckNavigationType(pTarget->GetPos(), building, m_NavProperties) :
  748.                                                     IAISystem::NAV_UNSET);
  749.  
  750.         if (navType == IAISystem::NAV_TRIANGULAR || navType == IAISystem::NAV_WAYPOINT_HUMAN)
  751.         {
  752.                 if (navType != tData.navType && (tData.navType == IAISystem::NAV_TRIANGULAR || tData.navType == IAISystem::NAV_WAYPOINT_HUMAN))
  753.                 {
  754.                         CCCPOINT(CLeaderAction_Attack_SwitchPositions_CheckNavType_A);
  755.  
  756.                         IAISignalExtraData* pData = GetAISystem()->CreateSignalExtraData();
  757.                         pData->iValue = navType;
  758.                         pData->iValue2 = targetNavType;
  759.                         GetAISystem()->SendSignal(SIGNALFILTER_SENDER, 1, "OnNavTypeChanged", pMember, pData);
  760.                 }
  761.                 tData.navType = navType;
  762.         }
  763.  
  764.         if (targetNavType == IAISystem::NAV_TRIANGULAR || targetNavType == IAISystem::NAV_WAYPOINT_HUMAN)
  765.         {
  766.  
  767.                 if (targetNavType != tData.targetNavType && tData.refTarget.IsValid() && (tData.targetNavType == IAISystem::NAV_TRIANGULAR || tData.targetNavType == IAISystem::NAV_WAYPOINT_HUMAN))
  768.                 {
  769.                         CCCPOINT(CLeaderAction_Attack_SwitchPositions_CheckNavType_B);
  770.  
  771.                         IAISignalExtraData* pData = GetAISystem()->CreateSignalExtraData();
  772.                         pData->iValue = navType;
  773.                         pData->iValue2 = targetNavType;
  774.                         GetAISystem()->SendSignal(SIGNALFILTER_SENDER, 1, "OnTargetNavTypeChanged", pMember, pData);
  775.                 }
  776.                 tData.targetNavType = targetNavType;
  777.         }
  778.  
  779.         CCCPOINT(CLeaderAction_Attack_SwitchPositions_CheckNavType_C);
  780. }
  781.  
  782. //
  783. //----------------------------------------------------------------------------------------------------
  784. CLeaderAction_Attack_SwitchPositions::STargetData* CLeaderAction_Attack_SwitchPositions::GetTargetData(CUnitImg& unit)
  785. {
  786.         TMapTargetData::iterator it = m_TargetData.find(unit.m_refUnit);
  787.         if (it != m_TargetData.end())
  788.                 return &(it->second);
  789.         return NULL;
  790. }
  791.  
  792. //
  793. //----------------------------------------------------------------------------------------------------
  794. CLeaderAction_Attack_SwitchPositions::~CLeaderAction_Attack_SwitchPositions()
  795. {
  796.         m_pLeader->ReleaseFormation();
  797. }
  798.  
  799. //
  800. //----------------------------------------------------------------------------------------------------
  801. void CLeaderAction_Attack_SwitchPositions::AddUnitNotify(CAIActor* pUnit)
  802. {
  803.         if (pUnit)
  804.         {
  805.                 CAIObject* pTarget = (CAIObject*)pUnit->GetAttentionTarget();
  806.  
  807.                 UpdatePointList(pTarget);
  808.  
  809.                 TUnitList::iterator itUnit = m_pLeader->GetAIGroup()->GetUnit(pUnit);
  810.                 if (itUnit != GetUnitsList().end())
  811.                 {
  812.                         itUnit->ClearFollowing();
  813.                         itUnit->m_TagPoint = ZERO;
  814.                         itUnit->SetMoving();
  815.                 }
  816.         }
  817. }
  818.  
  819. //
  820. //----------------------------------------------------------------------------------------------------
  821. void CLeaderAction_Attack_SwitchPositions::UpdatePointList(CAIObject* pTarget)
  822. {
  823.         IEntity* pTargetEntity = NULL;
  824.         if (!pTarget)
  825.                 pTarget = (CAIObject*)m_pLeader->GetAIGroup()->GetAttentionTarget(true, true).GetAIObject();
  826.         if (pTarget)
  827.                 pTargetEntity = pTarget->GetEntity();
  828.         if (!pTargetEntity)
  829.                 return;
  830.  
  831.         // (MATT) We might check for dead references here in m_PointProperties, but logic appears to be simply:
  832.         // "if owner removed, owner is set to NULL" which can be easily done in-place {2009/02/13}
  833.  
  834.         IEntity* pDummyEntity = NULL;
  835.         if (!m_vUpdatePointTarget.IsEquivalent(pTarget->GetPos()))
  836.         {
  837.                 m_vUpdatePointTarget = pTarget->GetPos();
  838.                 // target has moved, update additional shoot spot list
  839.                 QueryEventMap queryEvents;
  840.                 gAIEnv.pSmartObjectManager->TriggerEvent("CheckTargetNear", pTargetEntity, pDummyEntity, &queryEvents);
  841.  
  842.                 CAIObject* pFormationOwner = m_pLeader->GetFormationOwner().GetAIObject();
  843.                 int size = m_PointProperties.size();
  844.  
  845.                 const QueryEventMap::const_iterator itEnd = queryEvents.end();
  846.  
  847.                 // (MATT) We might check for dead references here in m_PointProperties, but logic in OnObjectRemoved was simply:
  848.                 // "if owner removed, owner is set to NULL", which can be easily done in-place.
  849.                 // The code below doesn't actually seem interested in whether the owner is valid or not.
  850.                 // It just removes elements if the query is no longer relevant. {2009/02/13}
  851.                 TPointPropertiesList::iterator itp = m_PointProperties.begin(), itpEnd = m_PointProperties.end();
  852.                 itp += size;
  853.                 QueryEventMap::iterator itFound = queryEvents.end();
  854.                 for (; itp != itpEnd; )
  855.                 {
  856.                         CCCPOINT(CLeaderAction_Attack_SwitchPositions_UpdatePointList);
  857.  
  858.                         bool bFound = false;
  859.                         for (QueryEventMap::iterator itq = queryEvents.begin(); itq != itEnd; ++itq)
  860.                         {
  861.                                 Vec3 pos;
  862.                                 const CQueryEvent* pQueryEvent = &itq->second;
  863.                                 if (pQueryEvent->pRule->pObjectHelper)
  864.                                         pos = pQueryEvent->pObject->GetHelperPos(pQueryEvent->pRule->pObjectHelper);
  865.                                 else
  866.                                         pos = pQueryEvent->pObject->GetPos();
  867.  
  868.                                 if (itp->point == pos)
  869.                                 {
  870.                                         bFound = true;
  871.                                         itFound = itq;
  872.                                         break;
  873.                                 }
  874.                         }
  875.                         if (bFound)
  876.                         {
  877.                                 queryEvents.erase(itFound);
  878.                                 ++itp;
  879.                                 CCCPOINT(CLeaderAction_Attack_SwitchPositions_UpdatePointList_A);
  880.                         }
  881.                         else
  882.                         {
  883.                                 m_PointProperties.erase(itp++);
  884.                                 CCCPOINT(CLeaderAction_Attack_SwitchPositions_UpdatePointList_B);
  885.                         }
  886.                 }
  887.  
  888.                 // only not found points in queryEvents now
  889.                 for (QueryEventMap::const_iterator it = queryEvents.begin(); it != itEnd; ++it)
  890.                 {
  891.                         const CQueryEvent* pQueryEvent = &it->second;
  892.  
  893.                         Vec3 pos;
  894.                         if (pQueryEvent->pRule->pObjectHelper)
  895.                                 pos = pQueryEvent->pObject->GetHelperPos(pQueryEvent->pRule->pObjectHelper);
  896.                         else
  897.                                 pos = pQueryEvent->pObject->GetPos();
  898.  
  899.                         m_PointProperties.push_back(SPointProperties(pos));
  900.                 }
  901.  
  902.         }
  903.  
  904. }
  905. //
  906. //----------------------------------------------------------------------------------------------------
  907. bool CLeaderAction_Attack_SwitchPositions::ProcessSignal(const AISIGNAL& signal)
  908. {
  909.         CCCPOINT(CLeaderAction_Attack_SwitchPositions_ProcessSignal);
  910.  
  911.         IEntity* pSenderEntity = gEnv->pEntitySystem->GetEntity(signal.senderID);
  912.  
  913.         if (signal.Compare(gAIEnv.SignalCRCs.m_nOnFormationPointReached))
  914.         {
  915.                 CCCPOINT(CLeaderAction_Attack_SwitchPositions_ProcessSignal_A);
  916.                 CAIObject* pUnit;
  917.                 if (pSenderEntity && (pUnit = (CAIObject*)(pSenderEntity->GetAI())))
  918.                 {
  919.                         CAIActor* pAIActor = pUnit->CastToCAIActor();
  920.                         TUnitList::iterator itUnit = m_pLeader->GetAIGroup()->GetUnit(pAIActor);
  921.                         if (itUnit != GetUnitsList().end())
  922.                                 itUnit->SetFollowing();
  923.                 }
  924.                 return true;
  925.         }
  926.         else if (signal.Compare(gAIEnv.SignalCRCs.m_nAIORD_ATTACK))
  927.         {
  928.                 if (signal.pEData && static_cast<ELeaderActionSubType>(signal.pEData->iValue) == m_eActionSubType)
  929.                 {
  930.                         // unit is requesting this tactic which is active already,
  931.                         // just give him instructions to go
  932.                         CAIObject* pUnit;
  933.                         if (pSenderEntity && (pUnit = (CAIObject*)(pSenderEntity->GetAI())))
  934.                         {
  935.                                 CAIActor* pAIActor = pUnit->CastToCAIActor();
  936.                                 if (pAIActor)
  937.                                 {
  938.                                         CAIObject* pTarget = (CAIObject*)pAIActor->GetAttentionTarget();
  939.  
  940.                                         UpdatePointList(pTarget);
  941.  
  942.                                         TUnitList::iterator itUnit = m_pLeader->GetAIGroup()->GetUnit(pAIActor);
  943.                                         if (itUnit != GetUnitsList().end())
  944.                                         {
  945.                                                 CCCPOINT(CLeaderAction_Attack_SwitchPositions_ProcessSignal_B);
  946.  
  947.                                                 itUnit->ClearFollowing();
  948.                                                 itUnit->m_TagPoint = ZERO;
  949.                                                 itUnit->SetMoving();
  950.                                         }
  951.                                 }
  952.                         }
  953.                         return true;
  954.                 }
  955.         }
  956.         else if (signal.Compare(gAIEnv.SignalCRCs.m_nOnRequestUpdate))
  957.         {
  958.                 CAIObject* pUnit;
  959.                 if (pSenderEntity && (pUnit = (CAIObject*)(pSenderEntity->GetAI())))
  960.                 {
  961.                         CAIActor* pAIActor = pUnit->CastToCAIActor();
  962.                         if (pAIActor)
  963.                         {
  964.                                 CAIObject* pTarget = (CAIObject*)pAIActor->GetAttentionTarget();
  965.  
  966.                                 UpdatePointList(pTarget);
  967.  
  968.                                 TUnitList::iterator itUnit = m_pLeader->GetAIGroup()->GetUnit(pAIActor);
  969.                                 if (itUnit != GetUnitsList().end())
  970.                                 {
  971.                                         CCCPOINT(CLeaderAction_Attack_SwitchPositions_ProcessSignal_C);
  972.  
  973.                                         itUnit->ClearFollowing();
  974.                                         itUnit->m_TagPoint = ZERO;
  975.                                         itUnit->SetMoving();
  976.  
  977.                                         if (signal.pEData)
  978.                                         {
  979.                                                 GetBaseSearchPosition(*itUnit, pTarget, signal.pEData->iValue, signal.pEData->fValue);
  980.                                                 if (signal.pEData->iValue2 > 0)
  981.                                                         itUnit->m_fDistance2 = (float)signal.pEData->iValue2;
  982.  
  983.                                         }
  984.                                 }
  985.                         }
  986.                 }
  987.                 return true;
  988.         }
  989.         else if (signal.Compare(gAIEnv.SignalCRCs.m_nOnRequestUpdateAlternative))
  990.         {
  991.                 CAIObject* pUnit;
  992.                 if (pSenderEntity && (pUnit = (CAIObject*)(pSenderEntity->GetAI())))
  993.                 {
  994.                         CAIActor* pAIActor = pUnit->CastToCAIActor();
  995.                         if (pAIActor)
  996.                         {
  997.                                 CAIObject* pTarget = (CAIObject*)pAIActor->GetAttentionTarget();
  998.  
  999.                                 UpdatePointList(pTarget);
  1000.  
  1001.                                 TUnitList::iterator itUnit = m_pLeader->GetAIGroup()->GetUnit(pAIActor);
  1002.                                 if (itUnit != GetUnitsList().end())
  1003.                                 {
  1004.                                         CCCPOINT(CLeaderAction_Attack_SwitchPositions_ProcessSignal_D);
  1005.  
  1006.                                         itUnit->ClearFollowing();
  1007.                                         itUnit->m_TagPoint = ZERO;
  1008.                                         itUnit->SetMoving();
  1009.  
  1010.                                         if (signal.pEData)
  1011.                                         {
  1012.                                                 m_ActorForbiddenSpotManager.AddSpot(GetWeakRef(pAIActor), signal.pEData->point);
  1013.                                                 GetBaseSearchPosition(*itUnit, pTarget, signal.pEData->iValue, signal.pEData->fValue);
  1014.                                         }
  1015.                                 }
  1016.                         }
  1017.                 }
  1018.                 return true;
  1019.         }
  1020.         else if (signal.Compare(gAIEnv.SignalCRCs.m_nOnClearSpotList))
  1021.         {
  1022.                 CAIObject* pUnit;
  1023.                 if (pSenderEntity && (pUnit = (CAIObject*)(pSenderEntity->GetAI())))
  1024.                 {
  1025.                         CAIActor* pActor = pUnit->CastToCAIActor();
  1026.                         if (pActor)
  1027.                         {
  1028.                                 CCCPOINT(CLeaderAction_Attack_SwitchPositions_ProcessSignal_E);
  1029.                                 m_ActorForbiddenSpotManager.RemoveAllSpots(GetWeakRef(pActor));
  1030.                         }
  1031.                 }
  1032.                 return true;
  1033.         }
  1034.         else if (signal.Compare(gAIEnv.SignalCRCs.m_nOnRequestUpdateTowards))
  1035.         {
  1036.                 CAIObject* pUnit;
  1037.                 if (pSenderEntity && (pUnit = (CAIObject*)(pSenderEntity->GetAI())))
  1038.                 {
  1039.                         CPipeUser* pPiper = pUnit->CastToCPipeUser();
  1040.                         if (pPiper)
  1041.                         {
  1042.                                 CAIObject* pTarget = (CAIObject*)pPiper->GetAttentionTarget();
  1043.  
  1044.                                 UpdatePointList(pTarget);
  1045.  
  1046.                                 TUnitList::iterator itUnit = m_pLeader->GetAIGroup()->GetUnit(pPiper);
  1047.                                 if (itUnit != GetUnitsList().end())
  1048.                                 {
  1049.                                         CCCPOINT(CLeaderAction_Attack_SwitchPositions_ProcessSignal_F);
  1050.  
  1051.                                         itUnit->ClearFollowing();
  1052.                                         itUnit->SetMoving();
  1053.                                         if (signal.pEData)
  1054.                                         {
  1055.                                                 if (signal.pEData->iValue) // unit is asking for a particular direction
  1056.                                                         itUnit->m_Group = signal.pEData->iValue;
  1057.                                         }
  1058.                                 }
  1059.                         }
  1060.                 }
  1061.                 return true;
  1062.         }
  1063.         else if (signal.Compare(gAIEnv.SignalCRCs.m_nOnCheckDeadTarget))
  1064.         {
  1065.                 CAIObject* pUnit;
  1066.                 if (pSenderEntity && (pUnit = (CAIObject*)(pSenderEntity->GetAI())))
  1067.                 {
  1068.                         CPipeUser* pPiper = pUnit->CastToCPipeUser();
  1069.                         if (pPiper)
  1070.                         {
  1071.                                 CAIObject* pTarget = NULL;
  1072.                                 if (signal.pEData)
  1073.                                 {
  1074.                                         IEntity* pTargetEntity = gEnv->pEntitySystem->GetEntity((EntityId)signal.pEData->nID.n);
  1075.                                         if (pTargetEntity)
  1076.                                                 pTarget = (CAIObject*) pTargetEntity->GetAI();
  1077.                                 }
  1078.                                 CWeakRef<CAIObject> refTarget = GetWeakRef(pTarget);
  1079.                                 CWeakRef<CAIObject> refGroupTarget = m_pLeader->GetAIGroup()->GetAttentionTarget(true, true, refTarget);
  1080.                                 CWeakRef<CAIActor> refInvestigator;
  1081.                                 if (!refGroupTarget.IsValid() && pTarget && pTarget->GetType() == AIOBJECT_PLAYER)
  1082.                                 {
  1083.                                         // last touch, no more live targets and the last one was the player, go to investigate him
  1084.                                         float mindist2 = 1000000000.f;
  1085.                                         Vec3 targetPos(pTarget->GetPos());
  1086.                                         TUnitList::iterator itUEnd = GetUnitsList().end();
  1087.                                         for (TUnitList::iterator itUnit = GetUnitsList().begin(); itUnit != itUEnd; ++itUnit)
  1088.                                         {
  1089.                                                 CAIActor* pAIActor = itUnit->m_refUnit.GetAIObject();
  1090.                                                 if (pAIActor)
  1091.                                                 {
  1092.                                                         float dist2 = Distance::Point_PointSq(targetPos, pAIActor->GetPos());
  1093.                                                         if (dist2 <= mindist2)
  1094.                                                         {
  1095.                                                                 refInvestigator = itUnit->m_refUnit;
  1096.                                                                 mindist2 = dist2;
  1097.                                                         }
  1098.                                                 }
  1099.                                         }
  1100.  
  1101.                                 }
  1102.  
  1103.                                 CCCPOINT(CLeaderAction_Attack_SwitchPositions_ProcessSignal_G);
  1104.  
  1105.                                 CAIActor* const pInvestigator = refInvestigator.GetAIObject();
  1106.                                 if (pTarget && refInvestigator.IsValid())
  1107.                                 {
  1108.                                         CCCPOINT(CLeaderAction_Attack_SwitchPositions_ProcessSignal_OCDT);
  1109.  
  1110.                                         IAISignalExtraData* pData = GetAISystem()->CreateSignalExtraData();
  1111.                                         pData->nID = pTarget->GetEntityID();
  1112.                                         pInvestigator->SetSignal(0, "OnCheckDeadBody", pInvestigator->GetEntity(), pData, gAIEnv.SignalCRCs.m_nOnCheckDeadBody);
  1113.                                 }
  1114.                                 else
  1115.                                         pPiper->SetSignal(0, "OnNoGroupTarget", 0, 0, gAIEnv.SignalCRCs.m_nOnNoGroupTarget);
  1116.                         }
  1117.                 }
  1118.                 return true;
  1119.         }
  1120.         else if (signal.Compare(gAIEnv.SignalCRCs.m_nAddDangerPoint))
  1121.         {
  1122.                 IAISignalExtraData* pData = signal.pEData;
  1123.                 if (pData)
  1124.                 {
  1125.                         Vec3 dpoint = pData->point;
  1126.                         float radius = pData->fValue;
  1127.                         bool bFound = false;
  1128.                         TDangerPointList::iterator it = m_DangerPoints.begin(), itEnd = m_DangerPoints.end();
  1129.                         for (; it != itEnd; ++it)
  1130.                                 if (it->point == dpoint)
  1131.                                 {
  1132.                                         m_DangerPoints.erase(it);
  1133.                                         bFound = true;
  1134.                                         break;
  1135.                                 }
  1136.  
  1137.                         m_DangerPoints.push_back(SDangerPoint(float(pData->iValue), pData->fValue, dpoint));
  1138.  
  1139.                         if (!bFound)
  1140.                         {
  1141.                                 TUnitList::iterator itUEnd = GetUnitsList().end();
  1142.                                 for (TUnitList::iterator itUnit = GetUnitsList().begin(); itUnit != itUEnd; ++itUnit)
  1143.                                 {
  1144.                                         CAIActor* pUnit = itUnit->m_refUnit.GetAIObject();
  1145.                                         if (pUnit && Distance::Point_PointSq(dpoint, pUnit->GetPos()) <= radius * radius)
  1146.                                         {
  1147.                                                 itUnit->ClearFollowing();
  1148.                                                 itUnit->ClearMoving();
  1149.                                                 CCCPOINT(CLeaderAction_Attack_SwitchPositions_ProcessSignal_H);
  1150.                                         }
  1151.                                 }
  1152.                         }
  1153.                         m_bPointsAssigned = false;   // reassign all points
  1154.                         m_bAvoidDanger = true;
  1155.                 }
  1156.                 return true;
  1157.         }
  1158.         else if (!strcmp(signal.strText, "SetDistanceToTarget"))
  1159.         {
  1160.                 if (signal.pEData && pSenderEntity)
  1161.                 {
  1162.                         const CAIActor* pAIActor = CastToCAIActorSafe(pSenderEntity->GetAI());
  1163.                         TUnitList::iterator itUnit = m_pLeader->GetAIGroup()->GetUnit(pAIActor);
  1164.                         if (itUnit != GetUnitsList().end())
  1165.                         {
  1166.                                 CCCPOINT(CLeaderAction_Attack_SwitchPositions_ProcessSignal_I);
  1167.                                 itUnit->m_fDistance = signal.pEData->fValue;
  1168.                         }
  1169.                 }
  1170.                 return true;
  1171.         }
  1172.         else if (!strcmp(signal.strText, "OnExecutingSpecialAction"))
  1173.         {
  1174.                 const CAIActor* pAIActor = CastToCAIActorSafe(pSenderEntity->GetAI());
  1175.                 TSpecialActionMap::iterator its = m_SpecialActions.begin(), itsEnd = m_SpecialActions.end();
  1176.                 for (; its != itsEnd; ++its)
  1177.                 {
  1178.                         SSpecialAction& action = its->second;
  1179.                         if (action.refOwner == pAIActor && action.status == AS_WAITING_CONFIRM)
  1180.                                 action.status = AS_ON;
  1181.                 }
  1182.  
  1183.                 return true;
  1184.         }
  1185.         else if (!strcmp(signal.strText, "OnSpecialActionDone"))
  1186.         {
  1187.                 const CAIActor* pAIActor = CastToCAIActorSafe(pSenderEntity->GetAI());
  1188.                 TSpecialActionMap::iterator its = m_SpecialActions.begin(), itsEnd = m_SpecialActions.end();
  1189.                 for (; its != itsEnd; ++its)
  1190.                 {
  1191.                         SSpecialAction& action = its->second;
  1192.                         if (action.refOwner == pAIActor)
  1193.                                 action.status = AS_OFF;
  1194.                 }
  1195.  
  1196.                 TUnitList::iterator itUnit = m_pLeader->GetAIGroup()->GetUnit(pAIActor);
  1197.                 if (itUnit != GetUnitsList().end())
  1198.                 {
  1199.                         CCCPOINT(CLeaderAction_Attack_SwitchPositions_ProcessSignal_J);
  1200.  
  1201.                         itUnit->ClearSpecial();
  1202.                         // will request a new position later
  1203.                         itUnit->ClearFollowing();
  1204.                         itUnit->m_TagPoint = ZERO;
  1205.                         itUnit->SetMoving();
  1206.                 }
  1207.  
  1208.                 return true;
  1209.         }
  1210.         else if (!strcmp(signal.strText, "SetMinDistanceToTarget"))
  1211.         {
  1212.                 if (signal.pEData)
  1213.                 {
  1214.                         CCCPOINT(CLeaderAction_Attack_SwitchPositions_ProcessSignal_K);
  1215.                         m_fMinDistanceToTarget = signal.pEData->fValue;
  1216.                 }
  1217.                 return true;
  1218.         }
  1219.         return false;
  1220. }
  1221.  
  1222. void CLeaderAction_Attack_SwitchPositions::AssignNewShootSpot(CAIObject* pUnit, int index)
  1223. {
  1224.         CAIObject* pFormationOwner = m_pLeader->GetFormationOwner().GetAIObject();
  1225.         CFormation* pFormation = pFormationOwner ? pFormationOwner->m_pFormation : NULL;
  1226.         int fsize = pFormation ? pFormation->GetSize() : 0;
  1227.         TPointPropertiesList::iterator it = m_PointProperties.begin(), itEnd = m_PointProperties.end();
  1228.  
  1229.         CWeakRef<CAIObject> refUnit = GetWeakRef(pUnit);
  1230.         int i = 0;
  1231.         for (; it != itEnd; ++it)
  1232.                 if (i++ >= fsize && it->refOwner == refUnit)
  1233.                 {
  1234.                         CCCPOINT(CLeaderAction_Attack_SwitchPositions_ANSS);
  1235.  
  1236.                         it->refOwner.Reset();
  1237.                         break;
  1238.                 }
  1239.  
  1240.         m_PointProperties[index].refOwner = refUnit;
  1241. }
  1242.  
  1243. //
  1244. //----------------------------------------------------------------------------------------------------
  1245. bool CLeaderAction_Attack_SwitchPositions::IsVehicle(const CAIActor* pTarget, IEntity** ppVehicleEntity) const
  1246. {
  1247.         if (!ppVehicleEntity)
  1248.                 return false;
  1249.  
  1250.         // assuming not null pTarget
  1251.         IEntity* pEntity = pTarget->GetEntity();
  1252.  
  1253.         if (pTarget->GetType() == AIOBJECT_VEHICLE)
  1254.         {
  1255.                 *ppVehicleEntity = pEntity;
  1256.                 return true;
  1257.         }
  1258.  
  1259.         if (pEntity)
  1260.         {
  1261.                 while (pEntity->GetParent())
  1262.                         pEntity = pEntity->GetParent();
  1263.  
  1264.                 IAIObject* pAI = pEntity->GetAI();
  1265.                 if (pAI && (static_cast<CAIObject*>(pAI)->GetType() == AIOBJECT_VEHICLE))
  1266.                 {
  1267.                         *ppVehicleEntity = pEntity;
  1268.                         return true;
  1269.                 }
  1270.         }
  1271.  
  1272.         return false;
  1273. }
  1274.  
  1275. //
  1276. //----------------------------------------------------------------------------------------------------
  1277. bool CLeaderAction_Attack_SwitchPositions::IsSpecialActionConsidered(const CAIActor* pUnit, const CAIActor* pUnitLiveTarget) const
  1278. {
  1279.         CWeakRef<const CAIActor> refUnitLiveTarget = GetWeakRef(pUnitLiveTarget);
  1280.         TSpecialActionMap::const_iterator its = m_SpecialActions.find(refUnitLiveTarget), itEnd = m_SpecialActions.end();
  1281.         if (its != itEnd)
  1282.         {
  1283.                 CCCPOINT(CLeaderAction_Attack_SwitchPositions_ISAC);
  1284.  
  1285.                 // if it's a vehicle, more units can have a special action with it
  1286.                 if (IsVehicle(pUnitLiveTarget))
  1287.                 {
  1288.                         while (its != itEnd && its->first == refUnitLiveTarget)
  1289.                         {
  1290.                                 if (its->second.refOwner == pUnit)
  1291.                                         return true;
  1292.                                 ++its;
  1293.                         }
  1294.                 }
  1295.                 else
  1296.                         return true;
  1297.         }
  1298.         return false;
  1299. }
  1300.  
  1301. //
  1302. //----------------------------------------------------------------------------------------------------
  1303. void CLeaderAction_Attack_SwitchPositions::UpdateSpecialActions()
  1304. {
  1305.         CTimeValue Time = GetAISystem()->GetFrameStartTime();
  1306.         TUnitList::iterator it = GetUnitsList().begin(), itEnd = GetUnitsList().end();
  1307.         int size = m_pLeader->GetAIGroup()->GetGroupCount(IAISystem::GROUP_ENABLED);
  1308.         size = max(1, size / 2); // max half of the group can have special action
  1309.         // update special action list with new live targets
  1310.         for (; it != itEnd; ++it)
  1311.         {
  1312.                 // (MATT)  Whilst updating units list, is this the best place to remove entries with invalid refs? {2009/03/13}
  1313.                 CAIActor* pAIActor = it->m_refUnit.GetAIObject();
  1314.                 if (pAIActor && pAIActor->IsEnabled())
  1315.                 {
  1316.                         IAIObject* pUnitTarget = pAIActor->GetAttentionTarget();
  1317.                         const CAIActor* pUnitLiveTarget = CastToCAIActorSafe(pUnitTarget);
  1318.                         if (pUnitLiveTarget && pUnitLiveTarget->IsHostile(pAIActor) && !IsSpecialActionConsidered(pAIActor, pUnitLiveTarget))
  1319.                                 m_SpecialActions.insert(std::make_pair(GetWeakRef(pUnitLiveTarget), SSpecialAction(it->m_refUnit)));
  1320.  
  1321.                         CCCPOINT(CLeaderAction_Attack_SwitchPositions_UpdateSpecialActions_A);
  1322.                 }
  1323.         }
  1324.  
  1325.         TSpecialActionMap::iterator its = m_SpecialActions.begin(), itsEnd = m_SpecialActions.end();
  1326.         for (; size > 0 && its != itsEnd; )
  1327.         {
  1328.                 // (MATT)  Whilst updating the special actions map, remove entries with invalid refs {2009/03/13}
  1329.                 const CAIActor* pTarget = its->first.GetAIObject();
  1330.                 if (!pTarget)
  1331.                 {
  1332.                         m_SpecialActions.erase(its++);
  1333.                         CCCPOINT(CLeaderAction_Attack_SwitchPositions_UpdateSpecialActions_B);
  1334.                         continue;
  1335.                 }
  1336.  
  1337.                 SSpecialAction& action = its->second;
  1338.                 if (action.status == AS_OFF && (Time - action.lastTime).GetSeconds() > 2)
  1339.                 {
  1340.                         float maxscore = -1000000;
  1341.                         TUnitList::iterator itUnitSelected = itEnd;
  1342.                         for (it = GetUnitsList().begin(); it != itEnd; ++it)
  1343.                         {
  1344.                                 CAIActor* pUnit = CastToCAIActorSafe(it->m_refUnit.GetAIObject());
  1345.                                 if (pUnit && pUnit->IsEnabled())
  1346.                                 {
  1347.                                         IAIObject* pUnitTarget = pUnit->GetAttentionTarget();
  1348.                                         if (pUnitTarget && pUnitTarget == (IAIObject*)pTarget)
  1349.                                         {
  1350.                                                 float score = -Distance::Point_PointSq(pTarget->GetPos(), pUnit->GetPos());
  1351.                                                 if (action.refOwner != pUnit)
  1352.                                                         score += 49; // like it was 7m closer
  1353.                                                 if (score > maxscore)
  1354.                                                 {
  1355.                                                         maxscore = score;
  1356.                                                         itUnitSelected = it;
  1357.                                                 }
  1358.                                         }
  1359.                                 }
  1360.                         }
  1361.                         if (itUnitSelected != itEnd)
  1362.                         {
  1363.                                 action.status = AS_WAITING_CONFIRM;
  1364.                                 action.lastTime = Time;
  1365.                                 action.refOwner = itUnitSelected->m_refUnit;
  1366.  
  1367.                                 CAIActor* pUnit = itUnitSelected->m_refUnit.GetAIObject();
  1368.                                 pUnit->SetSignal(1, "OnSpecialAction", pUnit->GetEntity(), NULL, gAIEnv.SignalCRCs.m_nOnSpecialAction);
  1369.                                 itUnitSelected->SetSpecial();
  1370.                                 size--;
  1371.  
  1372.                                 CCCPOINT(CLeaderAction_Attack_SwitchPositions_UpdateSpecialActions_C);
  1373.                         }
  1374.                 }
  1375.  
  1376.                 switch (action.status)
  1377.                 {
  1378.                 case AS_ON:
  1379.                         action.lastTime = Time;
  1380.                         break;
  1381.                 case AS_WAITING_CONFIRM:
  1382.                         if ((Time - action.lastTime).GetSeconds() > 3)
  1383.                         {
  1384.                                 // if unit doesn't confirm doing the special action,clear it
  1385.                                 action.status = AS_OFF;
  1386.                                 TUnitList::iterator itUnit = m_pLeader->GetAIGroup()->GetUnit(action.refOwner.GetAIObject());
  1387.                                 if (itUnit != GetUnitsList().end())
  1388.                                         itUnit->ClearSpecial();
  1389.                         }
  1390.                         break;
  1391.                 default:
  1392.                         break;
  1393.                 }
  1394.  
  1395.                 CCCPOINT(CLeaderAction_Attack_SwitchPositions_UpdateSpecialActions_D);
  1396.  
  1397.                 ++its;
  1398.         }
  1399. }
  1400.  
  1401. //
  1402. //----------------------------------------------------------------------------------------------------
  1403. CLeaderAction::eActionUpdateResult CLeaderAction_Attack_SwitchPositions::Update()
  1404. {
  1405.         m_pLiveTarget = m_pLeader->GetAIGroup()->GetAttentionTarget(true, true).GetAIObject();
  1406.  
  1407.         CTimeValue frameTime = GetAISystem()->GetFrameStartTime();
  1408.         if (m_pLiveTarget)
  1409.                 m_timeRunning = frameTime;
  1410.         else if ((frameTime - m_timeRunning).GetSeconds() > m_timeLimit)
  1411.                 return ACTION_DONE;
  1412.  
  1413.         CAIObject* pBeacon = (CAIObject*)GetAISystem()->GetBeacon(m_pLeader->GetGroupId());
  1414.         if (!pBeacon)
  1415.                 UpdateBeacon();
  1416.         if (!pBeacon)
  1417.                 return ACTION_FAILED;
  1418.  
  1419.         CCCPOINT(CLeaderAction_Attack_SwitchPositions_Update);
  1420.  
  1421.         m_bVisibilityChecked = false;
  1422.  
  1423.         bool bFormationUpdated = false;
  1424.  
  1425.         TUnitList::iterator itEnd = GetUnitsList().end();
  1426.         if (!m_bInitialized)
  1427.         {
  1428.                 if (!m_pLiveTarget)
  1429.                         return ACTION_FAILED;
  1430.                 if (!m_pLeader->LeaderCreateFormation(m_sFormationType, ZERO, false, m_unitProperties, pBeacon))
  1431.                         return ACTION_FAILED;
  1432.                 CFormation* pFormation = pBeacon->m_pFormation;
  1433.                 assert(pFormation);
  1434.                 pFormation->SetOrientationType(CFormation::OT_VIEW);
  1435.                 pFormation->ForceReachablePoints(true);
  1436.                 pFormation->GetNewFormationPoint(GetWeakRef(m_pLiveTarget->CastToCAIActor()), 0);
  1437.  
  1438.                 m_fFormationScale = 1;
  1439.                 m_fFormationSize = pFormation->GetMaxWidth();
  1440.                 m_lastScaleUpdateTime.SetSeconds(0.f);
  1441.                 UpdateFormationScale(pFormation);
  1442.  
  1443.                 pFormation->SetUpdate(true);
  1444.                 pFormation->Update();
  1445.                 pFormation->SetUpdate(false);
  1446.  
  1447.                 bFormationUpdated = true;
  1448.  
  1449.                 m_vEnemyPos = pBeacon->GetPos();
  1450.                 if (m_vEnemyPos.IsZero())
  1451.                         return ACTION_FAILED;
  1452.  
  1453.                 int size = pFormation->GetSize();
  1454.                 m_PointProperties.resize(size);
  1455.                 m_bInitialized = true;
  1456.                 m_bPointsAssigned = false;
  1457.                 m_bAvoidDanger = false;
  1458.  
  1459.                 ClearUnitFlags();
  1460.  
  1461.                 UpdatePointList();
  1462.         }
  1463.  
  1464.         for (TUnitList::iterator unitItr = GetUnitsList().begin(); unitItr != itEnd; ++unitItr)
  1465.         {
  1466.                 CUnitImg& curUnit = (*unitItr);
  1467.                 CheckNavType(curUnit);
  1468.  
  1469.                 if (m_bPointsAssigned && !curUnit.IsMoving())
  1470.                 {
  1471.                         CAIActor* pUnit = curUnit.m_refUnit.GetAIObject();
  1472.  
  1473.                         CAIActor* pUnitObstructing = NULL;
  1474.  
  1475.                         // check Behind status - the unit is behind some other unit in the grioup
  1476.                         Vec3 pos = pUnit->GetPos();
  1477.                         CAIActor* pAIActor = pUnit->CastToCAIActor();
  1478.                         IAIObject* pTarget = pAIActor->GetAttentionTarget();
  1479.                         Vec3 targetPos = (pTarget && pTarget->GetEntity() ? pTarget->GetPos() : m_vEnemyPos);
  1480.                         Vec3 dirToEnemy = (targetPos - pos);
  1481.                         Vec3 proj;
  1482.  
  1483.                         for (TUnitList::iterator otherItr = GetUnitsList().begin(); otherItr != itEnd; ++otherItr)
  1484.                         {
  1485.                                 CUnitImg& otherUnit = (*otherItr);
  1486.                                 if (otherUnit != curUnit && !otherUnit.IsMoving())
  1487.                                 {
  1488.                                         Vec3 otherPos = otherUnit.m_refUnit.GetAIObject()->GetPos();
  1489.                                         Vec3 dirToUnit = (otherPos - pos).GetNormalizedSafe();
  1490.                                         if (dirToUnit.Dot(dirToEnemy) > 0.f)
  1491.                                                 if (fabs(pos.z - otherPos.z) < otherUnit.GetHeight() * 1.1f)
  1492.                                                         if (Distance::Point_Line2D(otherPos, pos, targetPos, proj) < otherUnit.GetWidth() / 2)
  1493.                                                         {
  1494.                                                                 float distanceToEnemy = Distance::Point_PointSq(targetPos, pos);
  1495.                                                                 float unitToEnemy = Distance::Point_PointSq(otherPos, targetPos);
  1496.                                                                 if (unitToEnemy > 2 * 2)
  1497.                                                                 {
  1498.                                                                         CCCPOINT(CLeaderAction_Attack_SwitchPositions_Update_A);
  1499.  
  1500.                                                                         pUnitObstructing = otherUnit.m_refUnit.GetAIObject();
  1501.                                                                         break;
  1502.                                                                 }
  1503.                                                         }
  1504.                                 }
  1505.                         }
  1506.  
  1507.                         if (curUnit.IsBehind() && !pUnitObstructing)
  1508.                         {
  1509.                                 pUnit->SetSignal(1, "OnNotBehind", pUnit->GetEntity());
  1510.                                 curUnit.ClearBehind();
  1511.                         }
  1512.                         else if (!curUnit.IsBehind() && pUnitObstructing)
  1513.                         {
  1514.                                 IAISignalExtraData* pData = NULL;
  1515.                                 IEntity* pOtherEntity = pUnitObstructing->GetEntity();
  1516.                                 if (pOtherEntity)
  1517.                                 {
  1518.                                         pData = GetAISystem()->CreateSignalExtraData();
  1519.                                         pData->nID = pOtherEntity->GetId();
  1520.                                 }
  1521.                                 pUnit->SetSignal(1, "OnBehind", pUnit->GetEntity(), pData);
  1522.                                 curUnit.SetBehind();
  1523.                         }
  1524.                 }
  1525.         }
  1526.  
  1527.         if (!m_bPointsAssigned)
  1528.         {
  1529.                 CFormation* pFormation = pBeacon->m_pFormation;
  1530.                 int s = pFormation->GetSize();
  1531.                 for (int i = 1; i < s; i++)
  1532.                         pFormation->FreeFormationPoint(i);
  1533.  
  1534.                 ClearUnitFlags();
  1535.  
  1536.                 for (TUnitList::iterator unitItr = GetUnitsList().begin(); unitItr != itEnd; ++unitItr)
  1537.                 {
  1538.                         CUnitImg& curUnit = (*unitItr);
  1539.                         curUnit.m_FormationPointIndex = -1;
  1540.  
  1541.                         STargetData* pUnitTData = GetTargetData(curUnit);
  1542.                         bool bAssignPoint = !(pUnitTData &&
  1543.                                               (pUnitTData->refTarget.IsValid() && (pUnitTData->targetNavType == IAISystem::NAV_WAYPOINT_HUMAN)));
  1544.  
  1545.                         CAIObject* pUnit = curUnit.m_refUnit.GetAIObject();
  1546.                         CPipeUser* pPiper = pUnit->CastToCPipeUser();
  1547.                         int iPointIndex = bAssignPoint ? GetFormationPointWithTarget(curUnit) : -1;
  1548.                         if (pPiper)
  1549.                         {
  1550.                                 CAIObject* pTarget = (CAIObject*)pPiper->GetAttentionTarget();
  1551.                                 if (!pTarget)
  1552.                                         pTarget = pBeacon;
  1553.                                 GetBaseSearchPosition(curUnit, pTarget, AI_MOVE_BACKWARD);
  1554.                                 if (iPointIndex > 0)
  1555.                                 {
  1556.                                         if (iPointIndex < s)
  1557.                                         {
  1558.  
  1559.                                                 m_pLeader->AssignFormationPointIndex(curUnit, iPointIndex);
  1560.                                                 pPiper->SetSignal(1, "OnAttackSwitchPosition");
  1561.                                                 curUnit.ClearFollowing();
  1562.                                         }
  1563.                                         else
  1564.                                         {
  1565.                                                 CAIActor* pAIActor = pUnit->CastToCAIActor();
  1566.                                                 IAISignalExtraData* pData = GetAISystem()->CreateSignalExtraData();
  1567.                                                 if (pData)
  1568.                                                 {
  1569.                                                         pData->point = m_PointProperties[iPointIndex].point;
  1570.                                                         AssignNewShootSpot(pUnit, iPointIndex);
  1571.                                                         CPipeUser* pPipeUser = pUnit->CastToCPipeUser();
  1572.                                                         pPipeUser->SetRefPointPos(pData->point);
  1573.                                                         pPipeUser->SetSignal(1, "OnAttackShootSpot", pUnit->GetEntity(), pData);
  1574.                                                         curUnit.ClearFollowing();
  1575.                                                 }
  1576.                                         }
  1577.                                 }
  1578.                                 else if (m_bAvoidDanger)
  1579.                                 {
  1580.                                         // to do: find a point outside all dangers and send 'em there
  1581.                                         Vec3 worstPoint(ZERO);
  1582.                                         Vec3 unitPos(pUnit->GetPos());
  1583.                                         float mindist = 1000000.f;
  1584.                                         TDangerPointList::iterator it = m_DangerPoints.begin(), itEndDP = m_DangerPoints.end();
  1585.                                         for (; it != itEndDP; ++it)
  1586.                                         {
  1587.                                                 float d = Distance::Point_Point2DSq(unitPos, it->point);
  1588.                                                 if (d < mindist)
  1589.                                                 {
  1590.                                                         mindist = d;
  1591.                                                         worstPoint = it->point;
  1592.                                                 }
  1593.                                         }
  1594.                                         pPiper->SetRefPointPos(worstPoint);
  1595.  
  1596.                                         pPiper->SetSignal(1, "OnAvoidDanger", NULL, NULL, gAIEnv.SignalCRCs.m_nOnAvoidDanger);
  1597.                                 }
  1598.                         }
  1599.                         m_pLeader->AssignFormationPointIndex(curUnit, iPointIndex);
  1600.                         curUnit.ClearFollowing();
  1601.                         curUnit.ClearSpecial(); // just to avoid sending the OnAttackSwitchPosition/ShootSpot signal now
  1602.                 }
  1603.                 m_bAvoidDanger = false;
  1604.                 m_bPointsAssigned = true;
  1605.  
  1606.                 return ACTION_RUNNING;
  1607.         }
  1608.  
  1609.         CFormation* pFormation = pBeacon->m_pFormation;
  1610.         if (pFormation)
  1611.         {
  1612.                 int size = pFormation->GetSize();
  1613.                 for (int i = 0; i < size; i++)
  1614.                         m_PointProperties[i].bTargetVisible = false;
  1615.         }
  1616.         else
  1617.                 return ACTION_FAILED;
  1618.  
  1619.         if (UpdateFormationScale(pFormation))
  1620.         {
  1621.                 bFormationUpdated = true;
  1622.                 pFormation->SetUpdate(true);
  1623.                 pFormation->Update();
  1624.                 pFormation->SetUpdate(false);
  1625.                 m_vEnemyPos = pBeacon->GetPos();
  1626.                 for (TUnitList::iterator unitItr = GetUnitsList().begin(); unitItr != itEnd; ++unitItr)
  1627.                         unitItr->SetMoving(); // force all units to move to (new) formation points when target and formation move
  1628.         }
  1629.  
  1630.         // move the formation if enemy avg position has moved
  1631.         if (!bFormationUpdated && Distance::Point_Point2DSq(pBeacon->GetPos(), m_vEnemyPos) > 4 * 4)
  1632.         {
  1633.                 pFormation->SetUpdate(true);
  1634.                 pFormation->Update();
  1635.                 pFormation->SetUpdate(false);
  1636.                 m_vEnemyPos = pBeacon->GetPos();
  1637.                 for (TUnitList::iterator unitItr = GetUnitsList().begin(); unitItr != itEnd; ++unitItr)
  1638.                         unitItr->SetMoving(); // force all units to move to (new) formation points when target and formation move
  1639.         }
  1640.  
  1641.         UpdateSpecialActions();
  1642.  
  1643.         if (m_DangerPoints.empty())
  1644.         {
  1645.                 for (TUnitList::iterator unitItr = GetUnitsList().begin(); unitItr != itEnd; ++unitItr)
  1646.                 {
  1647.                         CUnitImg& curUnit = (*unitItr);
  1648.                         CAIObject* pUnit = curUnit.m_refUnit.GetAIObject();
  1649.                         CPuppet* pPuppet = pUnit->CastToCPuppet();
  1650.                         if (pUnit->IsEnabled() && pPuppet)
  1651.                         {
  1652.                                 IAIObject* pTarget = pPuppet->GetAttentionTarget();
  1653.                                 if (pTarget)
  1654.                                 {
  1655.                                         const CAIActor* pTargetActor = pTarget->CastToCAIActor();
  1656.  
  1657.                                         IEntity* pVehicleEntity = NULL;
  1658.                                         if (pTargetActor && IsVehicle(pTargetActor, &pVehicleEntity))
  1659.                                         {
  1660.                                                 // use refpoint for vehicles
  1661.                                                 AABB aabb;
  1662.                                                 pVehicleEntity->GetLocalBounds(aabb);
  1663.                                                 float x = (aabb.max.x - aabb.min.x) / 2;
  1664.                                                 float y = (aabb.max.y - aabb.min.y) / 2;
  1665.                                                 float radius = sqrtf(x * x + y * y) + 1.f;
  1666.                                                 Vec3 center(pVehicleEntity->GetWorldPos());
  1667.                                                 center.z += 1.f;
  1668.                                                 Vec3 dir(center - pUnit->GetPos());
  1669.                                                 dir.z = 0;
  1670.                                                 dir.NormalizeSafe();
  1671.                                                 Vec3 hitdir(dir * radius);
  1672.                                                 Vec3 pos(center - hitdir);
  1673.                                                 IAIActorProxy* pProxy = pPuppet->GetProxy();
  1674.                                                 IPhysicalEntity* pPhysics = pProxy ? pProxy->GetPhysics() : NULL;
  1675.  
  1676.                                                 ray_hit hit;
  1677.                                                 int rayresult = 0;
  1678.                                                 IPhysicalWorld* pWorld = gAIEnv.pWorld;
  1679.                                                 if (pWorld)
  1680.                                                 {
  1681.                                                         rayresult = pWorld->RayWorldIntersection(
  1682.                                                           pos, hitdir, COVER_OBJECT_TYPES,
  1683.                                                           AI_VISION_RAY_CAST_FLAG_BLOCKED_BY_SOLID_COVER,
  1684.                                                           &hit, 1, pPhysics);
  1685.                                                         if (rayresult)
  1686.                                                                 pos = hit.pt - dir;
  1687.                                                 }
  1688.                                                 pPuppet->SetRefPointPos(pos);
  1689.                                                 continue;
  1690.                                         }
  1691.                                 }
  1692.                                 if (!curUnit.IsSpecial() && (curUnit.IsMoving() || curUnit.IsFollowing() && (!pTarget || !pTarget->IsAgent())))
  1693.                                 {
  1694.                                         curUnit.ClearMoving();
  1695.                                         // change position, can't see any live target and I'm not moving
  1696.                                         int iPointIndex = GetFormationPointWithTarget(curUnit);
  1697.                                         if (iPointIndex > 0 && iPointIndex != m_pLeader->GetFormationPointIndex(pUnit))
  1698.                                         {
  1699.                                                 if (iPointIndex < pFormation->GetSize())
  1700.                                                 {
  1701.                                                         m_pLeader->AssignFormationPointIndex(curUnit, iPointIndex);
  1702.                                                         CAIActor* pAIActor = pUnit->CastToCAIActor();
  1703.                                                         pAIActor->SetSignal(1, "OnAttackSwitchPosition");
  1704.                                                 }
  1705.                                                 else
  1706.                                                 {
  1707.                                                         CAIActor* pAIActor = pUnit->CastToCAIActor();
  1708.                                                         IAISignalExtraData* pData = GetAISystem()->CreateSignalExtraData();
  1709.                                                         if (pData)
  1710.                                                         {
  1711.                                                                 pData->point = m_PointProperties[iPointIndex].point;
  1712.                                                                 AssignNewShootSpot(pUnit, iPointIndex);
  1713.                                                                 CPipeUser* pPiper = pUnit->CastToCPipeUser();
  1714.                                                                 pPiper->SetRefPointPos(pData->point);
  1715.                                                                 pPiper->SetSignal(1, "OnAttackShootSpot", pUnit->GetEntity(), pData);
  1716.                                                                 curUnit.ClearFollowing();
  1717.                                                         }
  1718.                                                 }
  1719.                                         }
  1720.                                 }
  1721.                         }
  1722.                 }
  1723.         }
  1724.         // update danger points
  1725.         CTimeValue frameDTime = GetAISystem()->GetFrameDeltaTime();
  1726.         TDangerPointList::iterator itp = m_DangerPoints.begin();
  1727.         while (itp != m_DangerPoints.end())
  1728.         {
  1729.                 itp->time -= frameDTime.GetSeconds();
  1730.                 if (itp->time <= 0)
  1731.                         itp = m_DangerPoints.erase(itp);
  1732.                 else
  1733.                         ++itp;
  1734.         }
  1735.  
  1736.         m_fMinDistanceToNextPoint = m_fDefaultMinDistance;
  1737.  
  1738.         return ACTION_RUNNING;
  1739. }
  1740.  
  1741. bool CLeaderAction_Attack_SwitchPositions::UpdateFormationScale(CFormation* pFormation)
  1742. {
  1743.         // scale the formation depending on enemy occupied area
  1744.         float t = (GetAISystem()->GetFrameStartTime() - m_lastScaleUpdateTime).GetSeconds();
  1745.         bool ret = false;
  1746.         if (t > 2.f)
  1747.         {
  1748.                 m_lastScaleUpdateTime = GetAISystem()->GetFrameStartTime();
  1749.  
  1750.                 Vec3 pos1(m_pLeader->GetAIGroup()->GetForemostEnemyPosition(Vec3Constants<float>::fVec3_OneX));
  1751.                 Vec3 pos2(m_pLeader->GetAIGroup()->GetForemostEnemyPosition(Vec3Constants<float>::fVec3_OneY));
  1752.                 Vec3 pos3(m_pLeader->GetAIGroup()->GetForemostEnemyPosition(-Vec3Constants<float>::fVec3_OneX));
  1753.                 Vec3 pos4(m_pLeader->GetAIGroup()->GetForemostEnemyPosition(-Vec3Constants<float>::fVec3_OneY));
  1754.                 float s = Distance::Point_Point(pos1, pos2);
  1755.                 float s1 = Distance::Point_Point(pos3, pos4);
  1756.                 if (s < s1)
  1757.                         s = s1;
  1758.                 float s2 = Distance::Point_Point(pos2, pos4);
  1759.                 if (s < s2)
  1760.                         s = s2;
  1761.  
  1762.                 if (s > m_fFormationSize)
  1763.                         s = m_fFormationSize;
  1764.  
  1765.                 float scale = (m_fFormationSize + s) / m_fFormationSize;
  1766.                 float scaleRatio = scale / m_fFormationScale;
  1767.                 if (scaleRatio < 0.8f || scaleRatio > 1.2f)
  1768.                 {
  1769.                         m_fFormationScale = scale;
  1770.                         pFormation->SetScale(scale);
  1771.                         ret = true;
  1772.                 }
  1773.  
  1774.                 // compute distance to target
  1775.                 int si = pFormation->GetSize();
  1776.                 float mindist2 = 100000;
  1777.                 bool bfound = false;
  1778.                 Vec3 point;
  1779.                 for (int i = 0; i < si; i++)
  1780.                 {
  1781.                         if (pFormation->GetPointOffset(i, point))
  1782.                         {
  1783.                                 float dist2 = point.GetLengthSquared();
  1784.                                 if (dist2 < mindist2)
  1785.                                 {
  1786.                                         mindist2 = dist2;
  1787.                                         bfound = true;
  1788.                                 }
  1789.                         }
  1790.                 }
  1791.                 if (bfound)
  1792.                         m_fDistanceToTarget = sqrtf(mindist2);
  1793.         }
  1794.  
  1795.         return ret;
  1796. }
  1797.  
  1798. int CLeaderAction_Attack_SwitchPositions::GetFormationPointWithTarget(CUnitImg& unit)
  1799. {
  1800.         CCCPOINT(CLeaderAction_Attack_SwitchPositions_GFPWT);
  1801.  
  1802.         CAIObject* pBeacon = (CAIObject*)GetAISystem()->GetBeacon(m_pLeader->GetGroupId());
  1803.  
  1804.         CAIActor* pUnit = unit.m_refUnit.GetAIObject();
  1805.         if (!pUnit)
  1806.                 return -1;
  1807.  
  1808.         int index = -1;
  1809.         Vec3 groundDir(0, 0, -6);
  1810.         int myCurrentPointIndex = unit.m_FormationPointIndex;
  1811.         if (pBeacon)
  1812.         {
  1813.                 // TO DO: get the formation from the leader directly (beacon will not own the formation after refactoring)
  1814.                 CFormation* pFormation = pBeacon->m_pFormation;
  1815.                 if (pFormation)
  1816.                 {
  1817.                         CCCPOINT(CLeaderAction_Attack_SwitchPositions_GFPWT_GotBeacon);
  1818.  
  1819.                         const SAIBodyInfo& bodyInfo = pUnit->GetBodyInfo();
  1820.                         IEntity* pUnitEntity = pUnit->GetEntity();
  1821.                         float zDisp = (pUnitEntity ? bodyInfo.vEyePos.z - pUnitEntity->GetWorldPos().z : 1.2f);
  1822.  
  1823.                         int formationSize = pFormation->GetSize();
  1824.  
  1825.                         // total size includes all points, including shoot spots (m_PointProperties.size()) only if there's no live target
  1826.                         // otherwise, only formation points (first <formationSize> points in the m_PointProperties list
  1827.                         int size = (m_pLiveTarget ? formationSize : m_PointProperties.size());
  1828.  
  1829.                         ray_hit hit;
  1830.  
  1831.                         CAIObject* pTarget = (CAIObject*)pUnit->GetAttentionTarget();
  1832.                         if (!pTarget)
  1833.                                 pTarget = pBeacon;
  1834.  
  1835.                         IAIActorProxy* pProxy = pTarget->GetProxy();
  1836.                         IPhysicalEntity* pTargetPhysics = pProxy ? pProxy->GetPhysics() : NULL;
  1837.  
  1838.                         if (!pTargetPhysics)
  1839.                         {
  1840.                                 IAIObject* pAssociation = pTarget->GetAssociation().GetAIObject();
  1841.                                 if (pAssociation && pTarget->GetSubType() == IAIObject::STP_MEMORY)
  1842.                                 {
  1843.                                         if ((pProxy = pAssociation->GetProxy()))
  1844.                                                 pTargetPhysics = pProxy->GetPhysics();
  1845.                                 }
  1846.                         }
  1847.  
  1848.                         Vec3 beaconpos = pTarget->GetPos();
  1849.  
  1850.                         if (unit.m_TagPoint.IsZero())
  1851.                                 GetBaseSearchPosition(unit, pTarget, unit.m_Group);
  1852.                         Vec3 unitpos = unit.m_TagPoint;
  1853.  
  1854.                         float mindist = 100000000.f;
  1855.                         float fMinDistanceToNextPoint = unit.m_fDistance2 > 0 ? unit.m_fDistance2 : m_fMinDistanceToNextPoint;
  1856.                         for (int i = 1; i < size; i++)//exclude owner's point
  1857.                         {
  1858.                                 Vec3 pos;
  1859.                                 if (i < formationSize)
  1860.                                 {
  1861.                                         CAIObject* pPointOwner = pFormation->GetPointOwner(i);
  1862.                                         if (pPointOwner == pUnit)
  1863.                                                 myCurrentPointIndex = i;
  1864.                                         if (pPointOwner)
  1865.                                                 continue;
  1866.                                         CAIObject* pFormationPoint = pFormation->GetFormationPoint(i);
  1867.                                         if (pFormationPoint)
  1868.                                         {
  1869.                                                 pos = pFormationPoint->GetPos();
  1870.                                         }
  1871.                                         else
  1872.                                                 continue;
  1873.                                 }
  1874.                                 else
  1875.                                         pos = m_PointProperties[i].point;
  1876.  
  1877.                                 if (Distance::Point_Point2DSq(pos, beaconpos) < m_fMinDistanceToTarget * m_fMinDistanceToTarget)
  1878.                                         continue;
  1879.  
  1880.                                 if (!m_ActorForbiddenSpotManager.IsForbiddenSpot(unit.m_refUnit, pos))
  1881.                                 {
  1882.                                         CCCPOINT(CLeaderAction_Attack_SwitchPositions_GFPWT_A);
  1883.                                         {
  1884.                                                 // rough visibility check with raytrace
  1885.  
  1886.                                                 // check if the current point is not in a danger region
  1887.                                                 bool bDanger = false;
  1888.                                                 TDangerPointList::iterator itp = m_DangerPoints.begin(), itpEnd = m_DangerPoints.end();
  1889.                                                 for (; itp != itpEnd; ++itp)
  1890.                                                 {
  1891.                                                         float r = itp->radius;
  1892.                                                         r *= r;
  1893.                                                         if (Distance::Point_Point2DSq(itp->point, pos) <= r)
  1894.                                                         {
  1895.                                                                 bDanger = true;
  1896.                                                                 break;
  1897.                                                         }
  1898.                                                         else if ((pos - unitpos).GetNormalizedSafe().Dot((itp->point - unitpos).GetNormalizedSafe()) > 0.1f)
  1899.                                                         {
  1900.                                                                 bDanger = true;
  1901.                                                                 break;
  1902.                                                         }
  1903.                                                 }
  1904.  
  1905.                                                 if (bDanger)
  1906.                                                         continue;
  1907.  
  1908.                                                 // tweak the right Z position for formation point - the same Z as the requestor being at the formation point
  1909.                                                 int rayresult2 = 0;
  1910.                                                 if (!m_bVisibilityChecked && !unit.IsFar())
  1911.                                                 {
  1912.                                                         if (i < formationSize)
  1913.                                                         {
  1914.                                                                 rayresult2 = gAIEnv.pWorld->RayWorldIntersection(
  1915.                                                                   pos, groundDir, COVER_OBJECT_TYPES,
  1916.                                                                   AI_VISION_RAY_CAST_FLAG_BLOCKED_BY_SOLID_COVER,
  1917.                                                                   &hit, 1, pTargetPhysics);
  1918.                                                                 if (rayresult2)
  1919.                                                                         pos.z = hit.pt.z;
  1920.                                                         }
  1921.                                                         Vec3 rayPos(pos.x, pos.y, pos.z + zDisp);
  1922.                                                         rayresult2 = gAIEnv.pWorld->RayWorldIntersection(
  1923.                                                           rayPos, pTarget->GetPos() - rayPos, COVER_OBJECT_TYPES | ent_living,
  1924.                                                           AI_VISION_RAY_CAST_FLAG_BLOCKED_BY_SOLID_COVER,
  1925.                                                           &hit, 1, pTargetPhysics);
  1926.                                                 }
  1927.                                                 // TO DO: optimization with m_bVisibilityChecked and m_Targetvisiblep[]
  1928.                                                 // works perfectly only if there's one enemy
  1929.                                                 if (!rayresult2 || m_PointProperties[i].bTargetVisible)
  1930.                                                 {
  1931.                                                         float dist = 0;
  1932.  
  1933.                                                         if (unit.m_fDistance > 0)
  1934.                                                                 dist = 2 * fabs(unit.m_fDistance - Distance::Point_Point2D(beaconpos, pos));
  1935.                                                         float d1 = Distance::Point_Point2D(pUnit->GetPos(), pos) - fMinDistanceToNextPoint;
  1936.                                                         if (d1 < 0)
  1937.                                                                 dist -= d1;
  1938.                                                         else
  1939.                                                                 dist += d1;
  1940.  
  1941.                                                         if (!unit.m_TagPoint.IsZero())
  1942.                                                                 dist += Distance::Point_Point2D(unit.m_TagPoint, pos);
  1943.  
  1944.                                                         if (unit.m_Group == AI_BACKOFF_FROM_TARGET)
  1945.                                                         {
  1946.                                                                 //try to stay in front of target
  1947.                                                                 Vec3 targetDir(pos - beaconpos);
  1948.                                                                 targetDir.NormalizeSafe();
  1949.                                                                 float dot = targetDir.Dot(pTarget->GetViewDir());
  1950.                                                                 if (dot < 0.3f)
  1951.                                                                         dist += (1 - dot) * m_fFormationSize;
  1952.                                                         }
  1953.  
  1954.                                                         if (dist < mindist)
  1955.                                                         {
  1956.                                                                 mindist = dist;
  1957.                                                                 m_PointProperties[i].bTargetVisible = true;
  1958.                                                                 index = i;
  1959.                                                         }
  1960.                                                 }
  1961.  
  1962.                                                 CCCPOINT(CLeaderAction_Attack_SwitchPositions_GFPWT_B);
  1963.                                         }
  1964.                                 }
  1965.                         }
  1966.                         m_bVisibilityChecked = true;
  1967.                 }
  1968.         }
  1969.  
  1970.         unit.m_Group = 0;
  1971.         unit.m_fDistance2 = 0;
  1972.         unit.ClearFar();
  1973.  
  1974.         unit.m_TagPoint = ZERO;
  1975.  
  1976.         if (index < 0 && myCurrentPointIndex > 0)
  1977.                 return myCurrentPointIndex;
  1978.  
  1979.         return index;
  1980. }
  1981.  
  1982. //
  1983. //----------------------------------------------------------------------------------------------------
  1984. Vec3 CLeaderAction_Attack_SwitchPositions::GetBaseDirection(CAIObject* pTarget, bool bUseTargetMoveDir)
  1985. {
  1986.         CCCPOINT(CLeaderAction_Attack_SwitchPositions_GetBaseDirection);
  1987.  
  1988.         Vec3 vY;
  1989.         if (bUseTargetMoveDir)
  1990.         {
  1991.                 vY = pTarget->GetMoveDir();
  1992.                 vY.z = 0; // 2D only
  1993.                 vY.NormalizeSafe(pTarget->GetEntityDir());
  1994.         }
  1995.         else
  1996.         {
  1997.                 vY = pTarget->GetViewDir();
  1998.                 if (fabs(vY.z) > 0.95f)
  1999.                         vY = pTarget->GetEntityDir();
  2000.                 vY.z = 0; // 2D only
  2001.                 vY.NormalizeSafe();
  2002.         }
  2003.         return vY;
  2004. }
  2005. //
  2006. //----------------------------------------------------------------------------------------------------
  2007. void CLeaderAction_Attack_SwitchPositions::GetBaseSearchPosition(CUnitImg& unit, CAIObject* pTarget, int method, float distance)
  2008. {
  2009.         Vec3 unitpos = unit.m_refUnit.GetAIObject()->GetPos();
  2010.         if (!pTarget)
  2011.         {
  2012.                 pTarget = (CAIObject*)m_pLeader->GetAIGroup()->GetAttentionTarget().GetAIObject();
  2013.                 if (!pTarget)
  2014.                 {
  2015.                         pTarget = (CAIObject*)GetAISystem()->GetBeacon(m_pLeader->GetGroupId());
  2016.                         if (!pTarget)
  2017.                         {
  2018.                                 unit.m_TagPoint = unitpos;
  2019.                                 return;
  2020.                         }
  2021.                 }
  2022.         }
  2023.  
  2024.         Vec3 beaconpos = pTarget->GetPos();
  2025.  
  2026.         if (method < 0)
  2027.         {
  2028.                 method = -method;
  2029.                 unit.SetFar();
  2030.         }
  2031.         else
  2032.                 unit.ClearFar();
  2033.  
  2034.         bool bUseTargetMoveDir = (method & AI_USE_TARGET_MOVEMENT) != 0;
  2035.         method &= ~AI_USE_TARGET_MOVEMENT;
  2036.  
  2037.         if (method != AI_BACKOFF_FROM_TARGET)
  2038.         {
  2039.                 if (distance <= 0)
  2040.                         distance = 2 * m_fMinDistanceToNextPoint;
  2041.                 else
  2042.                         distance += m_fMinDistanceToNextPoint;
  2043.         }
  2044.  
  2045.         unit.m_Group = method;
  2046.  
  2047.         switch (method)
  2048.         {
  2049.         case AI_BACKOFF_FROM_TARGET:
  2050.                 {
  2051.                         unit.m_fDistance = distance;
  2052.                         Vec3 vY(unitpos - beaconpos);
  2053.                         vY.NormalizeSafe();
  2054.                         unitpos = beaconpos + vY * distance;
  2055.                 }
  2056.                 break;
  2057.         case AI_MOVE_BACKWARD: // move back to the target
  2058.                 {
  2059.                         Vec3 vY(GetBaseDirection(pTarget, bUseTargetMoveDir));
  2060.                         unitpos = beaconpos + vY * distance;
  2061.                 }
  2062.                 break;
  2063.         case AI_MOVE_LEFT: // move left to the target
  2064.                 {
  2065.                         Vec3 vY(GetBaseDirection(pTarget, bUseTargetMoveDir));
  2066.                         Vec3 vX = vY % Vec3(0, 0, 1);
  2067.                         unitpos = beaconpos - vX * distance;
  2068.                 }
  2069.                 break;
  2070.         case AI_MOVE_RIGHT: // move left to the target
  2071.                 {
  2072.                         Vec3 vY(GetBaseDirection(pTarget, bUseTargetMoveDir));
  2073.                         Vec3 vX = vY % Vec3(0, 0, 1);
  2074.                         unitpos = beaconpos + vX * distance;
  2075.                 }
  2076.                 break;
  2077.         case AI_MOVE_RIGHT + AI_MOVE_BACKWARD: // move left to the target
  2078.                 {
  2079.                         Vec3 vY(GetBaseDirection(pTarget, bUseTargetMoveDir));
  2080.                         Vec3 vX = vY % Vec3(0, 0, 1);
  2081.                         unitpos = beaconpos + (vX + vY).GetNormalizedSafe() * distance;
  2082.                 }
  2083.                 break;
  2084.         case AI_MOVE_LEFT + AI_MOVE_BACKWARD: // move left to the target
  2085.                 {
  2086.                         Vec3 vY(GetBaseDirection(pTarget, bUseTargetMoveDir));
  2087.                         Vec3 vX = vY % Vec3(0, 0, 1);
  2088.                         unitpos = beaconpos + (-vY - vX).GetNormalizedSafe() * distance;
  2089.                 }
  2090.                 break;
  2091.         default:
  2092.                 break;
  2093.         }
  2094.         unit.m_TagPoint = unitpos;
  2095.  
  2096.         CCCPOINT(CLeaderAction_Attack_SwitchPositions_GetBasesSearchPosition);
  2097. }
  2098.  
  2099. //-------------------------------------------------------------------------------------
  2100. // SERIALIZATION FUNCTIONS
  2101. //-------------------------------------------------------------------------------------
  2102.  
  2103. //
  2104. //----------------------------------------------------------------------------------------------------
  2105. void CLeaderAction::Serialize(TSerialize ser)
  2106. {
  2107.         ser.EnumValue("m_ActionType", m_eActionType, LA_NONE, LA_LAST);
  2108.         ser.EnumValue("m_eActionSubType", m_eActionSubType, LAS_DEFAULT, LAS_LAST);
  2109.         ser.Value("m_Priority", m_Priority);
  2110.         ser.Value("m_unitProperties", m_unitProperties);
  2111.         ser.EnumValue("m_currentNavType", m_currentNavType, IAISystem::NAV_UNSET, IAISystem::NAV_MAX_VALUE);
  2112.         ser.Value("m_NavProperties", m_NavProperties);
  2113. }
  2114. //
  2115. //----------------------------------------------------------------------------------------------------
  2116. void CLeaderAction_Attack::Serialize(TSerialize ser)
  2117. {
  2118.         CLeaderAction::Serialize(ser);
  2119.         ser.Value("m_bInitialized", m_bInitialized);
  2120.         ser.Value("m_bNoTarget", m_bNoTarget);
  2121.         ser.Value("m_timeRunning", m_timeRunning);
  2122.         ser.Value("m_timeLimit", m_timeLimit);
  2123.         ser.Value("m_bApproachWithNoObstacle", m_bApproachWithNoObstacle);
  2124.         ser.Value("m_vDefensePoint", m_vDefensePoint);
  2125.         ser.Value("m_vEnemyPos", m_vEnemyPos);
  2126.  
  2127. }
  2128.  
  2129. //
  2130. //----------------------------------------------------------------------------------------------------
  2131. void CLeaderAction_Search::Serialize(TSerialize ser)
  2132. {
  2133.         CLeaderAction::Serialize(ser);
  2134.         ser.Value("m_timeRunning", m_timeRunning);
  2135.         ser.Value("m_iCoverUnitsLeft", m_iCoverUnitsLeft);
  2136.         ser.Value("m_vEnemyPos", m_vEnemyPos);
  2137.         ser.Value("m_fSearchDistance", m_fSearchDistance);
  2138.         ser.Value("m_bInitialized", m_bInitialized);
  2139.         ser.Value("m_bUseHideSpots", m_bUseHideSpots);
  2140.         ser.Value("m_iSearchSpotAIObjectType", m_iSearchSpotAIObjectType);
  2141.  
  2142.         ser.BeginGroup("HideSpots");
  2143.         if (ser.IsReading())
  2144.                 m_HideSpots.clear();
  2145.         TPointMap::iterator it = m_HideSpots.begin();
  2146.         char name[16];
  2147.         int count = m_HideSpots.size();
  2148.         SSearchPoint hp;
  2149.         float dist2;
  2150.         ser.Value("count", count);
  2151.         for (int i = 0; i < count; ++i)
  2152.         {
  2153.                 if (ser.IsWriting())
  2154.                 {
  2155.                         dist2 = it->first;
  2156.                         hp.pos = it->second.pos;
  2157.                         hp.dir = it->second.dir;
  2158.                         hp.bReserved = it->second.bReserved;
  2159.                         ++it;
  2160.                 }
  2161.                 cry_sprintf(name, "HideSpot%d", i);
  2162.                 ser.BeginGroup(name);
  2163.                 ser.Value("distance2", dist2);
  2164.                 hp.Serialize(ser);
  2165.                 ser.EndGroup();
  2166.                 if (ser.IsReading())
  2167.                         m_HideSpots.insert(std::make_pair(dist2, hp));
  2168.         }
  2169.         ser.EndGroup();
  2170. }
  2171.  
  2172. //
  2173. //----------------------------------------------------------------------------------------------------
  2174. void CLeaderAction_Attack_SwitchPositions::Serialize(TSerialize ser)
  2175. {
  2176.         CLeaderAction_Attack::Serialize(ser);
  2177.         ser.Value("m_PointProperties", m_PointProperties);
  2178.         ser.Value("m_sFormationType", m_sFormationType);
  2179.         ser.Value("m_bVisibilityChecked", m_bVisibilityChecked);
  2180.         ser.Value("m_fMinDistanceToNextPoint", m_fMinDistanceToNextPoint);
  2181.         ser.Value("m_bPointsAssigned", m_bPointsAssigned);
  2182.         ser.Value("m_DangerPoints", m_DangerPoints);
  2183.         ser.Value("m_bAvoidDanger", m_bAvoidDanger);
  2184.         ser.Value("m_vUpdatePointTarget", m_vUpdatePointTarget);
  2185.         ser.Value("m_fFormationSize", m_fFormationSize);
  2186.         ser.Value("m_fFormationScale", m_fFormationScale);
  2187.         ser.Value("m_fDistanceToTarget", m_fDistanceToTarget);
  2188.         ser.Value("m_fMinDistanceToTarget", m_fMinDistanceToTarget);
  2189.         ser.Value("m_lastScaleUpdateTime", m_lastScaleUpdateTime);
  2190.  
  2191.         ser.BeginGroup("TargetData");
  2192.         {
  2193.                 int size = m_TargetData.size();
  2194.                 ser.Value("size", size);
  2195.                 TMapTargetData::iterator it = m_TargetData.begin();
  2196.                 if (ser.IsReading())
  2197.                         m_TargetData.clear();
  2198.  
  2199.                 STargetData targetData;
  2200.                 CWeakRef<CAIActor> refUnitActor;
  2201.                 char name[32];
  2202.  
  2203.                 for (int i = 0; i < size; i++)
  2204.                 {
  2205.                         cry_sprintf(name, "target_%d", i);
  2206.                         ser.BeginGroup(name);
  2207.                         {
  2208.                                 if (ser.IsWriting())
  2209.                                 {
  2210.                                         refUnitActor = it->first;
  2211.                                         targetData = it->second;
  2212.                                         ++it;
  2213.                                 }
  2214.                                 refUnitActor.Serialize(ser, "refUnitActor");
  2215.                                 targetData.Serialize(ser);
  2216.                                 if (ser.IsReading())
  2217.                                         m_TargetData.insert(std::make_pair(refUnitActor, targetData));
  2218.                         }
  2219.                         ser.EndGroup();
  2220.  
  2221.                 }
  2222.                 ser.EndGroup();
  2223.         }
  2224.  
  2225.         ser.BeginGroup("SpecialActions");
  2226.         {
  2227.                 int size = m_SpecialActions.size();
  2228.                 ser.Value("size", size);
  2229.                 TSpecialActionMap::iterator it = m_SpecialActions.begin();
  2230.                 if (ser.IsReading())
  2231.                         m_SpecialActions.clear();
  2232.  
  2233.                 SSpecialAction specialAction;
  2234.                 CWeakRef<const CAIActor> refTargetActor;
  2235.                 char name[32];
  2236.  
  2237.                 for (int i = 0; i < size; i++)
  2238.                 {
  2239.                         cry_sprintf(name, "target_%d", i);
  2240.                         ser.BeginGroup(name);
  2241.                         {
  2242.                                 if (ser.IsWriting())
  2243.                                 {
  2244.                                         refTargetActor = it->first;
  2245.                                         specialAction = it->second;
  2246.                                         ++it;
  2247.                                 }
  2248.                                 refTargetActor.Serialize(ser, "refTargetActor");
  2249.                                 specialAction.Serialize(ser);
  2250.                                 if (ser.IsReading())
  2251.                                         m_SpecialActions.insert(std::make_pair(refTargetActor, specialAction));
  2252.                         }
  2253.                         ser.EndGroup();
  2254.  
  2255.                 }
  2256.                 ser.EndGroup();
  2257.         }
  2258.  
  2259.         m_ActorForbiddenSpotManager.Serialize(ser);
  2260. }
  2261.  
downloadLeaderAction.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