BVB Source Codes

CRYENGINE Show Formation.cpp Source code

Return Download CRYENGINE: download Formation.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:   Formation.cpp
  6.    $Id$
  7.    Description:
  8.  
  9.    -------------------------------------------------------------------------
  10.    History:
  11.  
  12.  *********************************************************************/
  13. #include "StdAfx.h"
  14. #include "Formation.h"
  15. #include "PipeUser.h"
  16.  
  17. #include <CryEntitySystem/IEntity.h>
  18. #include "AIObject.h"
  19. #include "CAISystem.h"
  20. #include <CryMath/Cry_Math.h>
  21. #include <CrySystem/ITimer.h>
  22. #include <CrySystem/ISystem.h>
  23. #include <CryNetwork/ISerialize.h>
  24.  
  25. #include <CrySystem/IConsole.h>
  26. #include "DebugDrawContext.h"
  27. #include <Cry3DEngine/I3DEngine.h>
  28.  
  29. const float CFormation::m_fDISTANCE_UPDATE_THR = 0.3f;
  30. const float CFormation::m_fSIGHT_WIDTH = 1.f;
  31.  
  32. CFormation::TFormationID CFormation::s_NextFormation = 0;
  33.  
  34. CFormation::CFormation()
  35.         : m_formationID(s_NextFormation++)
  36.         , m_bReservationAllowed(true)
  37.         , m_vLastUpdatePos(ZERO)
  38.         , m_vLastPos(ZERO)
  39.         , m_vLastTargetPos(ZERO)
  40.         , m_vLastMoveDir(ZERO)
  41.         , m_vInitialDir(ZERO)
  42.         , m_vBodyDir(ZERO)
  43.         , m_vMoveDir(ZERO)
  44.         , m_bInitMovement(true)
  45.         , m_bFirstUpdate(false)
  46.         , m_bUpdate(true)
  47.         , m_bForceReachable(false)
  48.         , m_bFollowingUnits(false)
  49.         , m_bFollowPointInitialized(false)
  50.         , m_fUpdateThreshold(m_fDISTANCE_UPDATE_THR)
  51.         , m_fDynamicUpdateThreshold(0.0f)
  52.         , m_fStaticUpdateThreshold(0.0f)
  53.         , m_fScaleFactor(1.0f)
  54.         , m_pPathMarker(nullptr)
  55.         , m_iSpecialPointIndex(-1)
  56.         , m_fMaxFollowDistance(0.0f)
  57.         , m_maxUpdateSightTimeMs(0)
  58.         , m_minUpdateSightTimeMs(0)
  59.         , m_fSightRotationRange(0.0f)
  60.         , m_orientationType(OT_MOVE)
  61.         , m_dbgVector1(ZERO)
  62.         , m_dbgVector2(ZERO)
  63.         , m_fRepositionSpeedWrefTarget(0.0f)
  64.         , m_vDesiredTargetPos(ZERO)
  65. {
  66.         SetUpdateThresholds(m_fDISTANCE_UPDATE_THR);
  67. }
  68.  
  69. CFormation::~CFormation()
  70. {
  71.         ReleasePoints();
  72.         SAFE_DELETE(m_pPathMarker);
  73. }
  74.  
  75. void CFormation::ReleasePoints(void)
  76. {
  77.         for (TFormationPoints::iterator itr(m_FormationPoints.begin()); itr != m_FormationPoints.end(); ++itr)
  78.         {
  79.                 CFormationPoint& curPoint(*itr);
  80.                 curPoint.m_refDummyTarget.Release();
  81.                 curPoint.m_refWorldPoint.Release();
  82.         }
  83. }
  84.  
  85. void CFormation::OnObjectRemoved(CAIObject* pAIObject)
  86. {
  87.         // (MATT) Although this goes through a couple of levels, I think much of this could be removed {2009/03/18}
  88.         CCCPOINT(CFormation_OnObjectRemoved);
  89.  
  90.         FreeFormationPoint(GetWeakRef(pAIObject));
  91. }
  92.  
  93. void CFormation::AddPoint(FormationNode& desc)
  94. {
  95.         CFormationPoint curPoint;
  96.         Vec3 pos = desc.vOffset;
  97.         char name[100];
  98.         int i = m_FormationPoints.size();
  99.  
  100.         {
  101.                 cry_sprintf(name, "FORMATION_%d", i);
  102.                 CStrongRef<CAIObject> refFormationDummy;
  103.                 gAIEnv.pAIObjectManager->CreateDummyObject(refFormationDummy, name);
  104.                 refFormationDummy.GetAIObject()->SetSubType(CAIObject::STP_FORMATION);
  105.                 curPoint.m_refWorldPoint = refFormationDummy;
  106.         }
  107.  
  108.         curPoint.m_vSight = desc.vSightDirection;
  109.         int iClass = desc.eClass;
  110.         if (iClass == SPECIAL_FORMATION_POINT)
  111.                 m_iSpecialPointIndex = i;
  112.         curPoint.m_Class = iClass;
  113.  
  114.         curPoint.m_FollowHeightOffset = desc.fFollowHeightOffset;
  115.         curPoint.m_FollowDistance = desc.fFollowDistance;
  116.         curPoint.m_FollowOffset = desc.fFollowOffset;
  117.         curPoint.m_FollowDistanceAlternate = desc.fFollowDistanceAlternate;
  118.         curPoint.m_FollowOffsetAlternate = desc.fFollowOffsetAlternate;
  119.  
  120.         if (curPoint.m_FollowDistance > 0)
  121.         {
  122.                 if (m_fMaxFollowDistance < curPoint.m_FollowDistance)
  123.                         m_fMaxFollowDistance = curPoint.m_FollowDistance;
  124.  
  125.                 m_bFollowingUnits = true;
  126.                 pos = Vec3(curPoint.m_FollowOffset, curPoint.m_FollowDistance, curPoint.m_FollowHeightOffset);
  127.         }
  128.         curPoint.m_vPoint = pos;
  129.  
  130.         {
  131.                 cry_sprintf(name, "FORMATION_DUMMY_TARGET_%d", i);
  132.                 CStrongRef<CAIObject> refNewDummyTarget;
  133.                 gAIEnv.pAIObjectManager->CreateDummyObject(refNewDummyTarget, name);
  134.                 curPoint.m_refDummyTarget = refNewDummyTarget;
  135.         }
  136.  
  137.         m_FormationPoints.push_back(curPoint);
  138. }
  139.  
  140. // fills the formation class with all necessary information
  141. void CFormation::Create(CFormationDescriptor& desc, CWeakRef<CAIObject> refOwner, Vec3 vTargetPos)
  142. {
  143.         CAIObject* const pOwner = refOwner.GetAIObject();
  144.  
  145.         CFormationDescriptor::TVectorOfNodes::iterator vi;
  146.         m_fMaxFollowDistance = 0;
  147.         //float m_fMaxYOffset = -1000000;
  148.         //m_iForemostNodeIndex = -1;
  149.         m_szDescriptor = desc.m_sName;
  150.  
  151.         for (vi = desc.m_Nodes.begin(); vi != desc.m_Nodes.end(); ++vi)
  152.         {
  153.                 FormationNode& nodeDesc = *vi;
  154.                 AddPoint(nodeDesc);
  155.         }
  156.  
  157.         // clamp max distance to a minimum decent value
  158.         if (m_fMaxFollowDistance < 1)
  159.                 m_fMaxFollowDistance = 1;
  160.  
  161.         /*if(m_iForemostNodeIndex<0)
  162.            m_bFollowingUnits = false; // if it was true but no foremost node, it means that all the nodes
  163.                         // were set to follow
  164.          */
  165.         m_bInitMovement = true;
  166.         m_bFirstUpdate = true;
  167.         m_bFollowPointInitialized = false;
  168.         m_vInitialDir = vTargetPos.IsZero() ? Vec3Constants<float>::fVec3_Zero : (vTargetPos - pOwner->GetPos()).GetNormalizedSafe();
  169.         m_vMoveDir = m_vInitialDir;
  170.  
  171.         m_dbgVector1.zero();
  172.         m_dbgVector2.zero();
  173.  
  174.         m_vLastUpdatePos = pOwner->GetPos();
  175.         m_vLastPos = pOwner->GetPos();
  176.         m_vLastTargetPos.zero();
  177.         m_vLastMoveDir = pOwner->GetMoveDir();
  178.         m_fLastUpdateTime = 0.f;//GetAISystem()->GetCurrentTime();
  179.         m_vDesiredTargetPos.zero();
  180.  
  181.         m_refOwner = refOwner;
  182.         m_FormationPoints[0].m_refReservation = StaticCast<CAIActor>(refOwner);
  183.  
  184.         if (m_bFollowingUnits)
  185.         {
  186.                 if (m_pPathMarker)
  187.                 {
  188.                         delete m_pPathMarker;
  189.                         m_pPathMarker = 0;
  190.                 }
  191.                 m_pPathMarker = new CPathMarker(m_fMaxFollowDistance + 10, m_fDISTANCE_UPDATE_THR / 2);
  192.                 m_vInitialDir.z = 0; // only in 2D
  193.                 m_vInitialDir.NormalizeSafe();
  194.                 m_pPathMarker->Init(pOwner->GetPos(), pOwner->GetPos() - pOwner->GetEntityDir() * 0.5f);
  195.         }
  196.  
  197.         m_fSightRotationRange = 0;
  198.  
  199.         InitWorldPosition(m_vInitialDir);
  200. }
  201.  
  202. //-----------------------------------------------------------------------------------------------------------------
  203. //
  204.  
  205. float CFormation::GetMaxWidth()
  206. {
  207.         int s = m_FormationPoints.size();
  208.         float maxDist = 0;
  209.         for (int i = 0; i < s; i++)
  210.                 for (int j = i + 1; j < s; j++)
  211.                 {
  212.                         float dist = Distance::Point_PointSq(m_FormationPoints[i].m_vPoint, m_FormationPoints[j].m_vPoint);
  213.                         if (dist > maxDist)
  214.                                 maxDist = dist;
  215.                 }
  216.         return sqrtf(maxDist);
  217. }
  218.  
  219. //-----------------------------------------------------------------------------------------------------------------
  220. //
  221.  
  222. bool CFormation::GetPointOffset(int i, Vec3& ret)
  223. {
  224.         if (i >= GetSize())
  225.                 return false;
  226.         CFormationPoint& point = m_FormationPoints[i];
  227.         if (point.m_FollowDistance != 0)
  228.         {
  229.                 ret.x = point.m_FollowOffset;
  230.                 ret.y = point.m_FollowDistance;
  231.                 ret.z = point.m_FollowHeightOffset;
  232.         }
  233.         else
  234.         {
  235.                 ret = point.m_vPoint;
  236.         }
  237.         ret *= m_fScaleFactor;
  238.         return true;
  239.  
  240. }
  241.  
  242. //-----------------------------------------------------------------------------------------------------------------
  243. //
  244. CAIObject* CFormation::GetOwner()
  245. {
  246.         return m_refOwner.GetAIObject();
  247. }
  248.  
  249. int CFormation::GetPointIndex(CWeakRef<const CAIObject> refRequester) const
  250. {
  251.         int pointIndex = 0;
  252.         for (TFormationPoints::const_iterator itrPoint(m_FormationPoints.begin()); itrPoint != m_FormationPoints.end(); ++itrPoint, ++pointIndex)
  253.                 if ((*itrPoint).m_refReservation == refRequester)
  254.                         return pointIndex;
  255.         return -1;
  256. }
  257.  
  258. //-----------------------------------------------------------------------------------------------------------------
  259. //
  260. Vec3 CFormation::GetPointSmooth(const Vec3& headPos, float followDist, float sideDist, float heightValue, int smoothValue, Vec3& smoothPosAlongCurve, CAIObject* pUser)
  261. {
  262.         Vec3 thePos(0, 0, 0), smoothOffset(0, 0, 0);//,smoothPosAlongCurve(0,0,0);
  263.         float smoothD = .5f;
  264.         float weight = (float)smoothValue;
  265.         Vec3 peppe = m_pPathMarker->GetPointAtDistance(headPos, followDist);
  266.         followDist -= smoothD * smoothValue / 2;
  267.         if (followDist < 0)
  268.                 followDist = 0;
  269.         smoothPosAlongCurve.zero();
  270.         for (int cnt = 0; cnt < smoothValue; ++cnt)
  271.         {
  272.                 const float d = followDist + smoothD * cnt;
  273.                 Vec3 vFollowDir;
  274.                 Vec3 vFollowPos;
  275.                 vFollowPos = m_pPathMarker->GetPointAtDistance(headPos, d);
  276.                 vFollowDir = m_pPathMarker->GetDirectionAtDistance(headPos, d);
  277.                 if (vFollowDir.IsZero())
  278.                         vFollowDir = m_vMoveDir;
  279.                 Vec3 vHOffset;
  280.                 vHOffset.x = -vFollowDir.y * sideDist;
  281.                 vHOffset.y = vFollowDir.x * sideDist;
  282.                 vHOffset.z = heightValue;
  283.                 smoothPosAlongCurve += vFollowPos;
  284.                 smoothOffset += vHOffset;
  285.                 //weight += 1.0f;
  286.         }
  287.         //      if(weight > 0)
  288.         {
  289.                 smoothPosAlongCurve /= weight;
  290.                 smoothOffset /= weight;
  291.         }
  292.  
  293.         //      float dist = Distance::Point_Point(smoothPosAlongCurve,peppe);
  294.         thePos = smoothPosAlongCurve + smoothOffset;
  295.  
  296.         return thePos;
  297. }
  298.  
  299. //====================================================================
  300. // MoveFormationPointOutOfVehicles
  301. //====================================================================
  302. /*static void MoveFormationPointOutOfVehicles(Vec3 &pos)
  303.    {
  304.    IAIObject *obstVehicle = GetAISystem()->GetNearestObjectOfTypeInRange( pos, AIOBJECT_VEHICLE, 0, 10, NULL, AIFAF_INCLUDE_DISABLED );
  305.    if (!obstVehicle)    // nothing to steer away from
  306.     return;
  307.  
  308.    // get bounding rectangle of the vehicle width length
  309.    Vec3 FL, FR, BL, BR;
  310.    obstVehicle->GetProxy()->GetWorldBoundingRect(FL, FR, BL, BR, 1.0f);
  311.  
  312.    // zero heights
  313.    FL.z = FR.z = BL.z = BR.z = 0.0f;
  314.  
  315.    Vec3 fwd = (FL - BL);
  316.    fwd.NormalizeSafe();
  317.    Vec3 right = (FR - FL);
  318.    right.NormalizeSafe();
  319.  
  320.    // +ve dist means we're inside
  321.    float distToFront =  (FL - pos) | fwd;
  322.    float distToBack  = -(BL - pos) | fwd;
  323.    float distToRight =  (FR - pos) | right;
  324.    float distToLeft  = -(FL - pos) | right;
  325.  
  326.    if (distToFront < 0.0f || distToBack < 0.0f ||
  327.       distToRight < 0.0f || distToLeft < 0.0f)
  328.       return;
  329.  
  330.    // inside - choose the smallest distance - not the most elegant way
  331.    float bestDist = distToFront;
  332.    Vec3 newPos = pos + fwd * distToFront;
  333.    if (distToBack < bestDist)
  334.    {
  335.     bestDist = distToBack;
  336.     newPos = pos - fwd * distToBack;
  337.    }
  338.    if (distToRight < bestDist)
  339.    {
  340.     bestDist = distToRight;
  341.     newPos = pos + right * distToRight;
  342.    }
  343.    if (distToLeft < bestDist)
  344.    {
  345.     bestDist = distToLeft;
  346.     newPos = pos - right * distToLeft;
  347.    }
  348.    pos = newPos;
  349.    }
  350.  */
  351.  
  352. // Update of the formation (refreshes position of formation points)
  353. void CFormation::Update()
  354. {
  355.         // (MATT) Here's one place we might trigger a delete {2009/03/18}
  356.         CAIObject* const pOwner = m_refOwner.GetAIObject();
  357.         if (!pOwner)
  358.                 return;
  359.  
  360.         if (!m_bReservationAllowed)
  361.                 return;
  362.  
  363.         CCCPOINT(CFormation_Update);
  364.  
  365.         Vec3 vUpdateMoveDir;
  366.         Vec3 vUpdateTargetDir;
  367.         Vec3 vMoveDir;
  368.  
  369.         TFormationPoints::iterator itFormEnd = m_FormationPoints.end();
  370.         if (m_bFirstUpdate)
  371.         {
  372.                 m_vLastMoveDir = pOwner->GetMoveDir();
  373.                 m_bFirstUpdate = false;
  374.                 m_fLastUpdateTime = 0.0f;//GetAISystem()->GetFrameStartTime();
  375.                 for (TFormationPoints::iterator itrPoint(m_FormationPoints.begin()); itrPoint != itFormEnd; ++itrPoint)
  376.                 {
  377.                         CAIObject* const pWorldPoint = itrPoint->m_refWorldPoint.GetAIObject();
  378.                         if (pWorldPoint)
  379.                         {
  380.                                 pWorldPoint->SetAssociation(m_refOwner);
  381.                                 pWorldPoint->Event(AIEVENT_DISABLE, NULL);
  382.                         }
  383.                 }
  384.         }
  385.  
  386.         // if it's in init movement, we don't consider the update threshold, but any movement!=0
  387.         CTimeValue currentTime = GetAISystem()->GetFrameStartTime();
  388.         int64 updateTimeMs = (currentTime - m_fLastUpdateTime).GetMilliSecondsAsInt64();
  389.         if (updateTimeMs <= 10)
  390.                 return;
  391.  
  392.         float updateTimeFloat = (float)(updateTimeMs);
  393.         float intervalRangeFloat = (float)(m_maxUpdateSightTimeMs - m_minUpdateSightTimeMs);
  394.  
  395.         Vec3 vOwnerPos = pOwner->GetPhysicsPos();
  396.  
  397.         vUpdateMoveDir = vOwnerPos - m_vLastUpdatePos;
  398.         float fMovement = vUpdateMoveDir.GetLength();
  399.  
  400.         vMoveDir = vUpdateMoveDir;
  401.  
  402.         if (m_bUpdate)
  403.         {
  404.                 m_vLastPos = vOwnerPos;
  405.  
  406.                 if (m_refReferenceTarget.ValidateOrReset())
  407.                 {
  408.                         const CAIObject* pReferenceTarget = m_refReferenceTarget.GetAIObject();
  409.                         const Vec3& vRefPos = pReferenceTarget->GetPos();
  410.                         vUpdateTargetDir = vRefPos - m_vLastTargetPos;
  411.  
  412.                         CCCPOINT(CFormation_OnObjectRemoved_A);
  413.  
  414.                         float fTargetMovement = vUpdateTargetDir.GetLength();
  415.                         if (fTargetMovement > fMovement)
  416.                                 fMovement = fTargetMovement;
  417.                         if (m_fRepositionSpeedWrefTarget == 0 || m_vDesiredTargetPos.IsZero())
  418.                                 m_vDesiredTargetPos = vRefPos;
  419.                         else
  420.                         {
  421.                                 Vec3 moveDir = (vRefPos - m_vDesiredTargetPos);
  422.                                 float length = moveDir.GetLength();
  423.                                 if (length < 0.1f)
  424.                                         m_vDesiredTargetPos = vRefPos;
  425.                                 else
  426.                                 {
  427.                                         moveDir.NormalizeSafe();
  428.                                         float dist = (vRefPos - vOwnerPos).GetLength();
  429.                                         m_vDesiredTargetPos += moveDir * min(length, m_fRepositionSpeedWrefTarget / 10 * dist);
  430.                                 }
  431.                         }
  432.                         m_vMoveDir = m_vDesiredTargetPos - vOwnerPos;
  433.                         m_vMoveDir.NormalizeSafe();
  434.                         if (m_vMoveDir.x == 0 && m_vMoveDir.y == 0)//2D only - .IsZero())
  435.                         {
  436.                                 m_vMoveDir = pReferenceTarget->GetMoveDir();
  437.                                 m_vMoveDir.z = 0;
  438.                                 m_vMoveDir.NormalizeSafe();
  439.                         }
  440.                 }
  441.         }
  442.  
  443.         if (!m_bUpdate || fMovement < m_fUpdateThreshold && !m_bInitMovement && m_fRepositionSpeedWrefTarget == 0)
  444.         {
  445.                 // always update special formation points
  446.                 Vec3 formDirXAxis(m_vMoveDir.y, -m_vMoveDir.x, 0);
  447.                 if (m_iSpecialPointIndex >= 0)
  448.                 {
  449.                         CFormationPoint& frmPoint = m_FormationPoints[m_iSpecialPointIndex];
  450.                         Vec3 pos = frmPoint.m_vPoint;
  451.                         Vec3 posRot;
  452.                         Vec3 vY(pOwner->GetMoveDir());
  453.                         Vec3 vX(vY.y, -vY.x, 0);
  454.                         vX.NormalizeSafe();
  455.  
  456.                         posRot = pos.x * vX + pos.y * vY;
  457.                         pos = posRot + vOwnerPos;
  458.  
  459.                         frmPoint.SetPos(pos, vOwnerPos, m_bForceReachable);
  460.  
  461.                         CAIObject* const pDummyTarget = frmPoint.m_refDummyTarget.GetAIObject();
  462.                         if (pDummyTarget)
  463.                         {
  464.                                 CCCPOINT(CFormation_Update_B);
  465.  
  466.                                 Vec3 vY2(posRot);
  467.                                 Vec3 vX2(vY.y, -vY.x, 0);
  468.                                 vX2.NormalizeSafe();
  469.                                 vY2.NormalizeSafe();
  470.                                 Vec3 vDummyPosRelativeToOwner = frmPoint.m_vPoint + frmPoint.m_vSight; // in owner's space
  471.                                 Vec3 posRot2 = vDummyPosRelativeToOwner.x * vX2 + vDummyPosRelativeToOwner.y * vY2;
  472.                                 Vec3 vDummyWorldPos = posRot2 + vOwnerPos;
  473.                                 // TO DO: set the sight dummy target position relative to the point's user if it's close enough
  474.                                 vDummyWorldPos.z = pos.z;
  475.                                 pDummyTarget->SetPos(vDummyWorldPos);
  476.                         }
  477.  
  478.                 }
  479.  
  480.                 // randomly rotate the look-at dummy targets when formation is not moving
  481.                 if (m_fSightRotationRange > 0)
  482.                 {
  483.                         float intervalRange = intervalRangeFloat;
  484.  
  485.                         for (TFormationPoints::iterator itrPoint(m_FormationPoints.begin()); itrPoint != itFormEnd; ++itrPoint)
  486.                         {
  487.                                 CFormationPoint& frmPoint = (*itrPoint);
  488.                                 int randomIntervalMs = m_minUpdateSightTimeMs + cry_random(0U, (uint32)intervalRange);
  489.                                 int pointUpdateTimeMs = (int)(currentTime - frmPoint.m_fLastUpdateSightTime).GetMilliSecondsAsInt64();
  490.  
  491.                                 if (pointUpdateTimeMs > randomIntervalMs)
  492.                                 {
  493.                                         frmPoint.m_fLastUpdateSightTime = currentTime;
  494.                                         Vec3 pos = frmPoint.m_vPoint;// m_vPoints[i];
  495.  
  496.                                         CAIObject* const pDummyTarget = frmPoint.m_refDummyTarget.GetAIObject();
  497.                                         const CAIObject* const pReferenceTarget = m_refReferenceTarget.GetAIObject();
  498.  
  499.                                         if (pDummyTarget)
  500.                                         {
  501.                                                 if (pReferenceTarget && frmPoint.m_Class != SPECIAL_FORMATION_POINT)
  502.                                                 {
  503.                                                         pDummyTarget->SetPos(pReferenceTarget->GetPos());
  504.                                                 }
  505.                                                 else
  506.                                                 {
  507.                                                         CCCPOINT(CFormation_Update_C);
  508.  
  509.                                                         float angle = cry_random(-0.5f, 0.5f) * m_fSightRotationRange;
  510.                                                         Vec3 vSight = frmPoint.m_vSight.GetRotated(Vec3Constants<float>::fVec3_OneZ, angle);
  511.                                                         Vec3 vDummyPosRelativeToOwner = frmPoint.m_vPoint + vSight; // in owner's space
  512.                                                         Vec3 posRot = vDummyPosRelativeToOwner.x * formDirXAxis + vDummyPosRelativeToOwner.y * m_vMoveDir;
  513.                                                         Vec3 vDummyWorldPos = posRot + vOwnerPos;
  514.                                                         // TO DO: set the sight dummy target position relative to the point's user if it's close enough
  515.                                                         vDummyWorldPos.z = pos.z;
  516.                                                         pDummyTarget->SetPos(vDummyWorldPos);
  517.                                                 }
  518.                                         }
  519.                                 }
  520.                         }
  521.                 }
  522.  
  523.                 m_fLastUpdateTime = currentTime;
  524.                 return;
  525.         }
  526.  
  527.         float invUpdateTime = updateTimeFloat * 0.001f;
  528.  
  529.         // formation's owner has moved
  530.  
  531.         if (!m_refReferenceTarget.IsValid())
  532.         {
  533.                 CAIObject* const pReservation0 = m_FormationPoints[0].m_refReservation.GetAIObject();
  534.                 CAIObject* const pEntityOwner = pOwner->CastToCAIActor() || !pReservation0 ? pOwner : pReservation0;
  535.                 m_vMoveDir = m_orientationType == OT_MOVE ? pEntityOwner->GetMoveDir() : pEntityOwner->GetViewDir();
  536.                 m_vMoveDir.z = 0;
  537.                 m_vMoveDir.NormalizeSafe();
  538.                 if (m_vMoveDir.IsEquivalent(Vec3Constants<float>::fVec3_Zero))
  539.                         m_vMoveDir = (vOwnerPos - m_vLastUpdatePos).GetNormalizedSafe();
  540.                 if (m_vMoveDir.IsEquivalent(Vec3Constants<float>::fVec3_Zero))
  541.                         m_vMoveDir = pOwner->GetViewDir();
  542.  
  543.                 if (vUpdateMoveDir.GetLengthSquared() > sqr(0.01f))
  544.                 {
  545.                         Vec3 vUpdateMoveDirN = vUpdateMoveDir.GetNormalizedSafe();
  546.                         if (vUpdateMoveDirN.Dot(m_vLastMoveDir.GetNormalizedSafe()) < -0.1f)
  547.                         {
  548.                                 //formation is inverting direction, flip it
  549.                                 if (m_pPathMarker)
  550.                                         m_pPathMarker->Init(vOwnerPos, vOwnerPos - m_fMaxFollowDistance * vUpdateMoveDirN);
  551.                                 for (TFormationPoints::iterator itrPoint(m_FormationPoints.begin()); itrPoint != itFormEnd; ++itrPoint)
  552.                                 {
  553.                                         CCCPOINT(CFormation_Update_D);
  554.  
  555.                                         CFormationPoint& frmPoint = (*itrPoint);
  556.                                         frmPoint.m_FollowOffset = -frmPoint.m_FollowOffset;
  557.                                         frmPoint.m_vPoint.x = -frmPoint.m_vPoint.x;
  558.                                         frmPoint.m_vSight.x = -frmPoint.m_vSight.x;
  559.                                 }
  560.                         }
  561.                 }
  562.         }
  563.         Vec3 formDirXAxis(m_vMoveDir.y, -m_vMoveDir.x, 0);
  564.         m_fUpdateThreshold = m_fDynamicUpdateThreshold;
  565.         m_fLastUpdateTime = currentTime;
  566.  
  567.         if (!vUpdateMoveDir.IsEquivalent(Vec3Constants<float>::fVec3_Zero))
  568.                 m_vLastMoveDir = vUpdateMoveDir;
  569.         m_vLastUpdatePos = vOwnerPos;
  570.  
  571.         if (m_refReferenceTarget.IsValid())
  572.                 m_vLastTargetPos = m_refReferenceTarget.GetAIObject()->GetPos();
  573.  
  574.         m_bInitMovement = false;
  575.  
  576.         static float speedUpdateFrac = 0.1f;
  577.         bool bFormationOwnerPoint = true;
  578.         //first update the fixed offset points
  579.         for (TFormationPoints::iterator itrPoint(m_FormationPoints.begin()); itrPoint != itFormEnd; ++itrPoint)
  580.         {
  581.                 CFormationPoint& frmPoint = (*itrPoint);
  582.                 Vec3 pos = frmPoint.m_vPoint;// m_vPoints[i];
  583.                 CAIObject* const pFormationDummy = frmPoint.m_refWorldPoint.GetAIObject(); // m_vWorldPoints[i];
  584.                 frmPoint.m_fLastUpdateSightTime = currentTime;
  585.  
  586.                 //Update nodes
  587.                 if (!(m_bFollowingUnits && frmPoint.m_FollowDistance > 0))// m_vFollowDistances[i]>0 ))
  588.                 {
  589.                         // fixed offset node
  590.                         Vec3 posRot;
  591.                         if (bFormationOwnerPoint)
  592.                         {
  593.                                 //force the formation owner point to be where the owner is - skip all the checks
  594.                                 frmPoint.m_refWorldPoint.GetAIObject()->SetPos(vOwnerPos);
  595.                                 bFormationOwnerPoint = false;
  596.                                 continue;
  597.                         }
  598.  
  599.                         posRot = pos.x * formDirXAxis + pos.y * m_vMoveDir;
  600.                         pos = posRot + vOwnerPos;
  601.                         frmPoint.m_LastPosition = pFormationDummy->GetPos();
  602.                         frmPoint.m_Dir = (pos - frmPoint.m_LastPosition) * invUpdateTime;
  603.                         frmPoint.SetPos(pos, vOwnerPos, m_bForceReachable);
  604.  
  605.                         if (!pFormationDummy->IsEnabled())
  606.                                 pFormationDummy->Event(AIEVENT_ENABLE, NULL);
  607.  
  608.                         // blend the speed estimation to smooth it since it's very noisy
  609.                         float newSpeed = (frmPoint.m_LastPosition - pos).GetLength() * invUpdateTime;
  610.                         frmPoint.m_Speed = speedUpdateFrac * newSpeed + (1.0f - speedUpdateFrac) * frmPoint.m_Speed;
  611.  
  612.                         //Update dummy targets
  613.  
  614.                         //rotate sighting
  615.                         CAIObject* const pDummyTarget = frmPoint.m_refDummyTarget.GetAIObject();
  616.                         const CAIObject* const pReferenceTarget = m_refReferenceTarget.GetAIObject();
  617.                         if (pDummyTarget)
  618.                         {
  619.                                 if (pReferenceTarget && frmPoint.m_Class != SPECIAL_FORMATION_POINT)
  620.                                 {
  621.                                         pDummyTarget->SetPos(pReferenceTarget->GetPos());
  622.                                 }
  623.                                 else
  624.                                 {
  625.                                         CCCPOINT(CFormation_Update_E);
  626.  
  627.                                         Vec3 vSight = frmPoint.m_vSight;
  628.                                         Vec3 vDummyPosRelativeToOwner = frmPoint.m_vPoint + vSight; // in owner's space
  629.                                         Vec3 posRot2 = vDummyPosRelativeToOwner.x * formDirXAxis + vDummyPosRelativeToOwner.y * m_vMoveDir;
  630.                                         Vec3 vDummyWorldPos = posRot2 + vOwnerPos;
  631.                                         // TO DO: set the sight dummy target position relative to the point's user if it's close enough
  632.                                         vDummyWorldPos.z = pos.z;
  633.                                         pDummyTarget->SetPos(vDummyWorldPos);
  634.                                 }
  635.                         }
  636.                 }
  637.         }
  638.  
  639.         if (m_bFollowingUnits)
  640.         {
  641.                 TFormationPoints::iterator itrPoint(m_FormationPoints.begin());
  642.  
  643.                 m_pPathMarker->Update(vOwnerPos, true);// true if 2D movement
  644.  
  645.                 bool bPlayerLeader = (pOwner && pOwner->GetType() == AIOBJECT_PLAYER);
  646.  
  647.                 // then update following-type nodes and sights
  648.                 for (; itrPoint != itFormEnd; ++itrPoint)
  649.                 {
  650.                         CFormationPoint& frmPoint = (*itrPoint);
  651.                         CAIObject* const pFormationDummy = frmPoint.m_refWorldPoint.GetAIObject();
  652.  
  653.                         if (frmPoint.m_FollowDistance > 0)
  654.                         {
  655.                                 float fDistance = frmPoint.m_FollowDistance;
  656.  
  657.                                 float fTotalDistance = m_pPathMarker->GetTotalDistanceRun();
  658.  
  659.                                 Vec3 vFollowDir;
  660.                                 if (fTotalDistance < 1.0f || fTotalDistance < fDistance)
  661.                                 {
  662.                                         // Keep the point disabled until it is possible to update it properly.
  663.                                         if (pFormationDummy->IsEnabled())
  664.                                                 pFormationDummy->Event(AIEVENT_DISABLE, NULL);
  665.  
  666.                                         if (frmPoint.m_refReservation.IsValid())
  667.                                         {
  668.                                                 // Only update the point after it has been reserved so that the formation point
  669.                                                 // assignment can find the nearest points.
  670.                                                 frmPoint.SetPos(vOwnerPos, vOwnerPos, true, bPlayerLeader);
  671.                                         }
  672.  
  673.                                         frmPoint.m_Speed = 0;
  674.  
  675.                                         vFollowDir = m_vMoveDir;
  676.                                 }
  677.                                 else
  678.                                 {
  679.                                         // There is enough path markers to update the point.
  680.                                         if (!pFormationDummy->IsEnabled())
  681.                                                 pFormationDummy->Event(AIEVENT_ENABLE, NULL);
  682.  
  683.                                         // follow-type node
  684.                                         vFollowDir = m_pPathMarker->GetDirectionAtDistance(vOwnerPos, fDistance);
  685.                                         if (vFollowDir.IsZero())
  686.                                                 vFollowDir = m_vMoveDir;
  687.  
  688.                                         int numSmoothPasses = 5;
  689.  
  690.                                         //don't smooth formation for squad-mates
  691.                                         if (pOwner->CastToCAIPlayer())
  692.                                                 numSmoothPasses = 1;
  693.  
  694.                                         if (vMoveDir.GetLengthSquared() > .01f && (vOwnerPos - pFormationDummy->GetPos()).Dot(vMoveDir) > 0.f)
  695.                                         {
  696.                                                 Vec3 pointAlongLeaderPath;
  697.                                                 Vec3 smoothedPos = GetPointSmooth(vOwnerPos, fDistance, frmPoint.m_FollowOffset, frmPoint.m_FollowHeightOffset, numSmoothPasses, pointAlongLeaderPath, frmPoint.m_refReservation.GetAIObject());
  698.                                                 frmPoint.SetPos(smoothedPos, pointAlongLeaderPath, m_bForceReachable, bPlayerLeader);
  699.                                         }
  700.  
  701.                                         float newSpeed = (frmPoint.m_LastPosition - pFormationDummy->GetPos()).GetLength() * invUpdateTime;
  702.                                         frmPoint.m_Speed = speedUpdateFrac * newSpeed + (1.0f - speedUpdateFrac) * frmPoint.m_Speed;
  703.                                 }
  704.  
  705.                                 CCCPOINT(CFormation_Update_F);
  706.  
  707.                                 frmPoint.m_Dir = (pFormationDummy->GetPos() - frmPoint.m_LastPosition) * invUpdateTime;
  708.                                 frmPoint.m_LastPosition = pFormationDummy->GetPos();
  709.  
  710.                                 //rotate 90 degrees
  711.                                 formDirXAxis.x = vFollowDir.y;
  712.                                 formDirXAxis.y = -vFollowDir.x;
  713.                                 formDirXAxis.z = 0;
  714.                                 //Update dummy targets
  715.                                 Vec3 vSight = frmPoint.m_vSight;
  716.                                 //rotate sighting
  717.  
  718.                                 Vec3 pos2 = pFormationDummy->GetPos();
  719.  
  720.                                 CAIObject* pDummyTarget = frmPoint.m_refDummyTarget.GetAIObject();
  721.                                 if (pDummyTarget)
  722.                                 {
  723.                                         Vec3 posRot = vSight.x * formDirXAxis + vSight.y * vFollowDir;
  724.                                         Vec3 vDummyWorldPos = posRot + pFormationDummy->GetPos();
  725.                                         // TO DO: set the sight dummy target position relative to the point's owner if it's close enough
  726.                                         vDummyWorldPos.z = pos2.z;
  727.                                         pDummyTarget->SetPos(vDummyWorldPos, vFollowDir);
  728.                                 }
  729.  
  730.                         }
  731.                 }
  732.         }
  733. }
  734.  
  735. void CFormationPoint::SetPos(Vec3 pos, const Vec3& startPos, bool force, bool bPlayerLeader)
  736. {
  737.         if (!m_refReservation.IsValid() && !force)
  738.         {
  739.                 m_refWorldPoint.GetAIObject()->SetPos(pos);
  740.                 return;
  741.         }
  742.  
  743.         if (!bPlayerLeader && m_FollowDistance > 0 && m_FollowOffset < 0.2f)
  744.         {
  745.                 //optimization: point is on a walked path (offset too low)
  746.                 m_refWorldPoint.GetAIObject()->SetPos(pos);
  747.                 return;
  748.         }
  749.  
  750.         // this line would replace all the code below
  751.         //m_pWorldPoint->SetReachablePos(pos,m_pReservation,startPos);
  752.  
  753.         CCCPOINT(CFormation_SetPos);
  754.  
  755.         IAISystem::tNavCapMask navMask;
  756.         float fPassRadius;
  757.         CAIActor* const pReservation = m_refReservation.GetAIObject();
  758.         if (pReservation)
  759.         {
  760.                 navMask = pReservation->GetMovementAbility().pathfindingProperties.navCapMask;
  761.                 fPassRadius = pReservation->GetParameters().m_fPassRadius;
  762.         }
  763.         else
  764.         {
  765.                 navMask = 0xff;
  766.                 fPassRadius = 0.6f;
  767.         }
  768.  
  769.         m_refWorldPoint.GetAIObject()->SetPos(pos);
  770. }
  771.  
  772. // returns an available formation point, if that exists right now by proximity
  773. CAIObject* CFormation::GetNewFormationPoint(CWeakRef<CAIActor> refRequester, int index)
  774. {
  775.         CAIObject* pPoint = NULL;
  776.  
  777.         int size = m_FormationPoints.size();
  778.         if (index >= size)
  779.                 return NULL;
  780.  
  781.         CCCPOINT(CFormation_GetNewFormationPoint);
  782.  
  783.         if (index < 0)
  784.         {
  785.                 float mindist = FLT_MAX;
  786.                 const Vec3& requesterPos = refRequester.GetAIObject()->GetPos();
  787.                 for (int i = 0; i < size; i++)
  788.                 {
  789.                         CFormationPoint& curFormationPoint(m_FormationPoints[i]);
  790.                         CAIObject* pThisPoint = curFormationPoint.m_refWorldPoint.GetAIObject();
  791.                         if (refRequester == curFormationPoint.m_refReservation)
  792.                                 return pThisPoint;
  793.                         if (curFormationPoint.m_Class == SPECIAL_FORMATION_POINT)
  794.                                 continue;
  795.                         if (!curFormationPoint.m_refReservation.IsValid())
  796.                         {
  797.                                 float dist = Distance::Point_PointSq(pThisPoint->GetPos(), requesterPos);
  798.                                 if (dist < mindist)
  799.                                 {
  800.                                         index = i;
  801.                                         mindist = dist;
  802.                                         pPoint = pThisPoint;
  803.                                 }
  804.                         }
  805.                 }
  806.         }
  807.         else if (m_FormationPoints[index].m_refReservation.IsNil() || refRequester == m_FormationPoints[index].m_refReservation)
  808.         {
  809.                 pPoint = m_FormationPoints[index].m_refWorldPoint.GetAIObject();
  810.         }
  811.         if (index >= 0)
  812.         {
  813.                 CCCPOINT(CFormation_GetNewFormationPoint_A);
  814.                 m_FormationPoints[index].m_refReservation = refRequester;
  815.                 pPoint = m_FormationPoints[index].m_refWorldPoint.GetAIObject();
  816.                 SetUpdate(true);
  817.         }
  818.         return pPoint;
  819. }
  820.  
  821. int CFormation::GetClosestPointIndex(CWeakRef<CAIActor> refRequester, bool bReserve, int maxSize, int iClass, bool bCLosestToOwner)
  822. {
  823.         CCCPOINT(CFormation_GetClosestPointIndex);
  824.  
  825.         int size = (maxSize == 0 ? m_FormationPoints.size() : maxSize);
  826.         int index = -1;
  827.         float mindist = 2000000.f;
  828.         Vec3 basePos = bCLosestToOwner ? m_FormationPoints[0].m_refWorldPoint.GetAIObject()->GetPos() : refRequester.GetAIObject()->GetPos();
  829.         for (int i = 1; i < size; i++)
  830.                 if ((iClass < 0 && m_FormationPoints[i].m_Class != SPECIAL_FORMATION_POINT) || (m_FormationPoints[i].m_Class & iClass))
  831.                 {
  832.                         if (!m_FormationPoints[i].m_refReservation.IsValid() || refRequester == m_FormationPoints[i].m_refReservation)
  833.                         {
  834.                                 CAIObject* pThisPoint = m_FormationPoints[i].m_refWorldPoint.GetAIObject();
  835.                                 float dist = Distance::Point_PointSq(pThisPoint->GetPos(), basePos);
  836.                                 if (dist < mindist)
  837.                                 {
  838.                                         index = i;
  839.                                         mindist = dist;
  840.                                 }
  841.                         }
  842.                 }
  843.         if (index >= 0 && bReserve)
  844.         {
  845.                 CCCPOINT(CFormation_GetClosestPointIndex_A);
  846.                 FreeFormationPoint(refRequester);
  847.                 m_FormationPoints[index].m_refReservation = refRequester;
  848.         }
  849.         return index;
  850. }
  851.  
  852. CAIObject* CFormation::GetFormationDummyTarget(CWeakRef<const CAIObject> refRequester) const
  853. {
  854.         CCCPOINT(CFormation_GetFormationDummyTarget);
  855.  
  856.         for (uint32 i = 0; i < m_FormationPoints.size(); i++)
  857.                 if (m_FormationPoints[i].m_refReservation == refRequester)
  858.                         return m_FormationPoints[i].m_refDummyTarget.GetAIObject();
  859.         return NULL;
  860. }
  861.  
  862. void CFormation::SetDummyTargetPosition(const Vec3& vPosition, CAIObject* pDummyTarget, const Vec3& vSight)
  863. {
  864.         Vec3 myDir;
  865.         Vec3 otherDir;
  866.  
  867.         if (pDummyTarget)
  868.         {
  869.  
  870.                 Vec3 myangles = vSight;
  871.  
  872.                 myangles.z = 0;
  873.  
  874.                 float fi = m_fSIGHT_WIDTH * cry_random(-0.5f, 0.5f);
  875.  
  876.                 Matrix33 m = Matrix33::CreateRotationXYZ(DEG2RAD(Ang3(0, 0, fi)));
  877.                 myangles = m * (Vec3)myangles;
  878.  
  879.                 myangles *= 20.f;
  880.  
  881.                 pDummyTarget->SetPos(vPosition + (Vec3)myangles);
  882.  
  883.         }
  884. }
  885.  
  886. void CFormation::Draw()
  887. {
  888.         CDebugDrawContext dc;
  889.  
  890.         ColorB lineColPathOk(0, 255, 0, 179);
  891.         ColorB lineColNoPath(255, 255, 255, 179);
  892.         ColorB lineColDiffPath(255, 255, 0, 179);
  893.         for (unsigned int i = 0; i < m_FormationPoints.size(); ++i)
  894.         {
  895.                 CFormationPoint& fp = m_FormationPoints[i];
  896.                 CAIObject* const pReservoir = fp.m_refReservation.GetAIObject();
  897.                 uint8 alfaSud = pReservoir ? 255 : 102;
  898.                 CAIObject* const pWorldPoint = fp.m_refReservation.GetAIObject();
  899.  
  900.                 if (!pWorldPoint)
  901.                         continue;
  902.  
  903.                 Vec3 pos = fp.m_refWorldPoint->GetPos(); //  pWorldPoint->GetPos();
  904.                 ColorB color;
  905.                 if (!pWorldPoint->IsEnabled())
  906.                         color.set(255, 0, 0, alfaSud);
  907.                 else if (fp.m_Speed > 0)
  908.                         color.set(0, 255, 0, alfaSud);
  909.                 else
  910.                         color.set(255, 255, 0, alfaSud);
  911.                 dc->DrawSphere(pos, i == m_iSpecialPointIndex ? 0.2f : 0.3f, color);
  912.  
  913.                 if (pReservoir)
  914.                 {
  915.                         ColorB lineColor;
  916.                         CPipeUser* pPiper = pReservoir->CastToCPipeUser();
  917.                         assert(pPiper);//Shut up SCA
  918.                         if (pPiper && pPiper->m_refPathFindTarget == pWorldPoint)
  919.                                 lineColor = (pPiper->m_nPathDecision == PATHFINDER_NOPATH ? lineColNoPath : lineColPathOk);
  920.                         else
  921.                                 lineColor = lineColDiffPath;
  922.                         dc->DrawLine(pos, lineColor, pReservoir->GetPos(), lineColor);
  923.                         pos.z += 1.0f;
  924.                         if (pPiper)
  925.                         {
  926.                                 CAIObject* pPathFindTarget = pPiper->m_refPathFindTarget.GetAIObject();
  927.                                 if ((pPathFindTarget != NULL))
  928.                                         dc->Draw3dLabel(pos, 1, "%s (%s->%s)", pWorldPoint->GetName(), pReservoir->GetName(), pPathFindTarget->GetName());
  929.                                 else
  930.                                         dc->Draw3dLabel(pos, 1, "%s (%s)", pWorldPoint->GetName(), pReservoir->GetName());
  931.  
  932.                                 dc->DrawArrow(pos, m_vMoveDir, 0.1f, ColorB(255, 0, 0));
  933.                         }
  934.                 }
  935.                 else
  936.                 {
  937.                         pos.z += 1;
  938.                         dc->Draw3dLabel(pos, 1, "%s", pWorldPoint->GetName());
  939.                 }
  940.  
  941.                 // Draw the initial position, this is to help the designers to match the initial character locations with formation points.
  942.                 dc->DrawLine(fp.m_DEBUG_vInitPos - Vec3(0, 0, 10), ColorB(255, 196, 0), fp.m_DEBUG_vInitPos + Vec3(0, 0, 10), ColorB(255, 196, 0));
  943.                 dc->DrawCone(fp.m_DEBUG_vInitPos + Vec3(0, 0, 0.5f), Vec3(0, 0, -1), 0.2f, 0.5f, ColorB(255, 196, 0));
  944.                 if (Distance::Point_PointSq(fp.m_DEBUG_vInitPos, pos) > 5.0f)
  945.                         dc->Draw3dLabel(fp.m_DEBUG_vInitPos + Vec3(0, 0, 0.5f), 1, "Init\n%s", pWorldPoint->GetName());
  946.         }
  947.  
  948.         for (unsigned int i = 0; i < m_FormationPoints.size(); i++)
  949.         {
  950.                 const CFormationPoint& fp = m_FormationPoints[i];
  951.                 float alfaSud = fp.m_refReservation.IsValid() ? 1 : 0.4f;
  952.                 ColorB colorSight(0, 255, 179, uint8(255 * alfaSud));
  953.                 Vec3 pos = fp.m_refWorldPoint.GetAIObject()->GetPos();
  954.                 Vec3 posd = fp.m_refDummyTarget.GetAIObject()->GetPos() - pos;
  955.                 posd.NormalizeSafe();
  956.                 Vec3 possight = pos + posd / 2;
  957.                 dc->DrawCone(possight, posd, 0.05f, 0.2f, colorSight);
  958.                 dc->DrawLine(pos, colorSight, possight, colorSight);
  959.                 dc->SetMaterialColor(1.f, 1.f, 0.0f, alfaSud);
  960.         }
  961.  
  962.         if (!m_FormationPoints.empty())
  963.         {
  964.                 ColorB color(255, 128, 255);
  965.                 Vec3 pos = m_FormationPoints[0].m_refWorldPoint.GetAIObject()->GetPos();
  966.                 dc->DrawLine(pos, color, pos + 3 * m_dbgVector1, color);
  967.                 dc->DrawLine(pos, color, pos + 3 * m_dbgVector2, color);
  968.         }
  969.  
  970.         if (m_pPathMarker)
  971.                 m_pPathMarker->DebugDraw();
  972. }
  973.  
  974. // (MATT) Note that weak references can't be used in things triggered when objects are deleted - because the ref goes first {2009/03/18}
  975. void CFormation::FreeFormationPoint(CWeakRef<const CAIObject> refCurrentHolder)
  976. {
  977.         for (uint32 i = 0; i < m_FormationPoints.size(); i++)
  978.         {
  979.                 CFormationPoint& point = m_FormationPoints[i];
  980.                 if (point.m_refReservation == refCurrentHolder)
  981.                         point.m_refReservation.Reset();
  982.                 if (point.m_refWorldPoint.GetAIObject()->GetAssociation() == refCurrentHolder)
  983.                         point.m_refWorldPoint.GetAIObject()->SetAssociation(NILREF);
  984.                 if (point.m_refDummyTarget.GetAIObject()->GetAssociation() == refCurrentHolder)
  985.                         point.m_refDummyTarget.GetAIObject()->SetAssociation(NILREF);
  986.         }
  987. }
  988.  
  989. void CFormation::FreeFormationPoint(int i)
  990. {
  991.         CCCPOINT(CFormation_FreeFormationPoint_i);
  992.  
  993.         CFormationPoint& point = m_FormationPoints[i];
  994.         point.m_refReservation.Reset();
  995.         point.m_refWorldPoint.GetAIObject()->SetAssociation(NILREF);
  996.         point.m_refDummyTarget.GetAIObject()->SetAssociation(NILREF);
  997. }
  998. //----------------------------------------------------------------------
  999.  
  1000. void CFormation::Reset()
  1001. {
  1002.         for (uint32 i = 0; i < m_FormationPoints.size(); i++)
  1003.                 m_FormationPoints[i].m_refReservation.Reset();
  1004. }
  1005.  
  1006. void CFormation::InitWorldPosition(Vec3 vDir)
  1007. {
  1008.         CCCPOINT(CFormation_InitWorldPosition);
  1009.  
  1010.         CAIObject* const pOwner = m_refOwner.GetAIObject();
  1011.         if (vDir.IsZero())
  1012.                 vDir = pOwner->GetViewDir();
  1013.         vDir.NormalizeSafe();
  1014.         if (vDir.IsZero())
  1015.                 vDir = pOwner->GetMoveDir();
  1016.  
  1017.         m_vInitialDir = vDir;
  1018.  
  1019.         SetOffsetPointsPos(vDir);
  1020.         InitFollowPoints(vDir);//,pOwner);
  1021. }
  1022.  
  1023. void CFormation::SetOffsetPointsPos(const Vec3& vMoveDir)
  1024. {
  1025.         Vec3 vBasePos = m_refOwner.GetAIObject()->GetPos();
  1026.         Vec3 moveDirXAxis(-vMoveDir.y, vMoveDir.x, 0);
  1027.  
  1028.         // update the fixed offset points
  1029.         for (TFormationPoints::iterator itrPoint(m_FormationPoints.begin()); itrPoint != m_FormationPoints.end(); ++itrPoint)
  1030.         {
  1031.                 bool bFirst = true;
  1032.                 CFormationPoint& formPoint = (*itrPoint);
  1033.                 Vec3 pos = formPoint.m_vPoint;
  1034.                 CAIObject* const pFormationDummy = formPoint.m_refWorldPoint.GetAIObject();
  1035.  
  1036.                 //Update nodes
  1037.                 if (!(m_bFollowingUnits && formPoint.m_FollowDistance > 0))
  1038.                 {
  1039.                         // fixed offset node
  1040.                         Vec3 posRot;
  1041.                         posRot = pos.x * moveDirXAxis + pos.y * vMoveDir;
  1042.                         pos = posRot + vBasePos;
  1043.                         pos.z = gEnv->p3DEngine->GetTerrainElevation(pos.x, pos.y) + 1.75f;
  1044.  
  1045.                         if (bFirst)
  1046.                                 pFormationDummy->SetPos(pos);
  1047.                         else
  1048.                                 formPoint.SetPos(pos, vBasePos);
  1049.  
  1050.                         formPoint.m_DEBUG_vInitPos = pos;
  1051.  
  1052.                         formPoint.m_LastPosition = pos;
  1053.                         //Update dummy targets
  1054.                         Vec3 vSight = formPoint.m_vSight;
  1055.  
  1056.                         CAIObject* pDummyTarget = formPoint.m_refDummyTarget.GetAIObject();
  1057.                         const CAIObject* const pReferenceTarget = m_refReferenceTarget.GetAIObject();
  1058.                         if (pDummyTarget)
  1059.                         {
  1060.                                 if ((pReferenceTarget != NULL) && (formPoint.m_Class != SPECIAL_FORMATION_POINT))
  1061.                                 {
  1062.                                         pDummyTarget->SetPos(pReferenceTarget->GetPos());
  1063.                                 }
  1064.                                 else
  1065.                                 {
  1066.                                         CCCPOINT(CFormation_SetOffsetPointsPos);
  1067.  
  1068.                                         Vec3 vDummyPosRelativeToOwner = formPoint.m_vPoint + vSight; // in owner's space
  1069.                                         Vec3 posRot2 = vDummyPosRelativeToOwner.x * moveDirXAxis + vDummyPosRelativeToOwner.y * vMoveDir;
  1070.                                         Vec3 vDummyWorldPos = posRot2 + vBasePos;
  1071.                                         vDummyWorldPos.z = pos.z;
  1072.                                         pDummyTarget->SetPos(vDummyWorldPos);
  1073.                                 }
  1074.                         }
  1075.                 }
  1076.         }
  1077. }
  1078.  
  1079. //----------------------------------------------------------------------
  1080. void CFormation::InitFollowPoints(const Vec3& vDirection)
  1081. {
  1082.         CCCPOINT(CFormation_InitFollowPoints);
  1083.  
  1084.         CAIObject* const pOwner = m_refOwner.GetAIObject();
  1085.  
  1086.         // update the follow points
  1087.         Vec3 vInitPos = pOwner->GetPos();
  1088.         Vec3 vDir(vDirection.IsZero() ? (m_vLastMoveDir.IsZero() ? m_vMoveDir : m_vLastMoveDir) : vDirection);
  1089.         vDir.z = 0; //2d only
  1090.         vDir.NormalizeSafe();
  1091.  
  1092.         Vec3 vX(-vDir.y, vDir.x, 0);
  1093.  
  1094.         // The initial follow points are used for assigning the formation positions.
  1095.         // For this reason the formation points are slightly contracted, to allow a bit more setup in the level.
  1096.  
  1097.         // Find the nearest follow distance.
  1098.         float nearestFollowDistance = FLT_MAX;
  1099.         for (TFormationPoints::iterator itrPoint = m_FormationPoints.begin(), end = m_FormationPoints.end(); itrPoint != end; ++itrPoint)
  1100.         {
  1101.                 CFormationPoint& formPoint = (*itrPoint);
  1102.                 if (formPoint.m_FollowDistance > 0)
  1103.                         nearestFollowDistance = min(nearestFollowDistance, formPoint.m_FollowDistance);
  1104.         }
  1105.  
  1106.         bool bPlayerLeader = (pOwner && pOwner->GetType() == AIOBJECT_PLAYER);
  1107.         for (TFormationPoints::iterator itrPoint(m_FormationPoints.begin()); itrPoint != m_FormationPoints.end(); ++itrPoint)
  1108.         {
  1109.                 CFormationPoint& formPoint = (*itrPoint);
  1110.                 if (formPoint.m_FollowDistance > 0)
  1111.                 {
  1112.                         float totalFollowDist = formPoint.m_FollowDistance - nearestFollowDistance; // Contracted formation.
  1113.                         Vec3 requestedPosAlongCurve(vInitPos - vDir * totalFollowDist);
  1114.                         Vec3 offsetPos = vX * formPoint.m_FollowOffset + Vec3(0, 0, formPoint.m_FollowHeightOffset);
  1115.                         Vec3 requestedPos(requestedPosAlongCurve + offsetPos);
  1116.                         formPoint.SetPos(requestedPos, vInitPos, true, bPlayerLeader);
  1117.                         formPoint.m_LastPosition = requestedPos;
  1118.                         formPoint.m_DEBUG_vInitPos = requestedPos;
  1119.                         Vec3 vSight = formPoint.m_vSight;
  1120.  
  1121.                         CAIObject* pDummyTarget = formPoint.m_refDummyTarget.GetAIObject();
  1122.                         if (pDummyTarget)
  1123.                         {
  1124.                                 Vec3 vDummyPosRelativeToOwner = formPoint.m_vPoint + vSight; // in owner's space
  1125.                                 Vec3 posRot = -vDummyPosRelativeToOwner.x * vX + vDummyPosRelativeToOwner.y * vDir;
  1126.                                 Vec3 vDummyWorldPos = posRot + vInitPos;
  1127.                                 vDummyWorldPos.z = requestedPos.z;
  1128.                                 pDummyTarget->SetPos(vDummyWorldPos);
  1129.  
  1130.                                 CCCPOINT(CFormation_InitFollowPoints_A);
  1131.                         }
  1132.  
  1133.                 }
  1134.         }
  1135. }
  1136.  
  1137. //----------------------------------------------------------------------
  1138. CAIObject* CFormation::GetFormationPoint(CWeakRef<const CAIObject> refRequester) const
  1139. {
  1140.         for (TFormationPoints::const_iterator itrPoint(m_FormationPoints.begin()); itrPoint != m_FormationPoints.end(); ++itrPoint)
  1141.                 if ((*itrPoint).m_refReservation == refRequester)
  1142.                         return (*itrPoint).m_refWorldPoint.GetAIObject();
  1143.         return NULL;
  1144. }
  1145.  
  1146. //----------------------------------------------------------------------
  1147. float CFormation::GetFormationPointSpeed(CWeakRef<const CAIObject> refRequester) const
  1148. {
  1149.         for (TFormationPoints::const_iterator itrPoint(m_FormationPoints.begin()); itrPoint != m_FormationPoints.end(); ++itrPoint)
  1150.                 if ((*itrPoint).m_refReservation == refRequester)
  1151.                         return (*itrPoint).m_Speed;
  1152.         return 0;
  1153. }
  1154.  
  1155. //----------------------------------------------------------------------
  1156. float CFormation::GetDistanceToOwner(int i) const
  1157. {
  1158.  
  1159.         if ((unsigned)i >= m_FormationPoints.size())
  1160.                 return 0;
  1161.         if (m_FormationPoints[i].m_FollowDistance)
  1162.                 return sqrtf(m_FormationPoints[i].m_FollowDistance * m_FormationPoints[i].m_FollowDistance +
  1163.                              m_FormationPoints[i].m_FollowOffset * m_FormationPoints[i].m_FollowOffset +
  1164.                              m_FormationPoints[i].m_FollowHeightOffset * m_FormationPoints[i].m_FollowHeightOffset);
  1165.         else
  1166.                 return (m_FormationPoints[i].m_vPoint - m_FormationPoints[0].m_vPoint).GetLength();
  1167.  
  1168. }
  1169.  
  1170. //----------------------------------------------------------------------
  1171. int CFormation::CountFreePoints() const
  1172. {
  1173.         int iSize = GetSize();
  1174.         int iFree = 0;
  1175.         for (int i = 0; i < iSize; i++)
  1176.                 if (m_FormationPoints[i].m_refReservation.IsNil())
  1177.                         iFree++;
  1178.         return iFree;
  1179. }
  1180.  
  1181. //----------------------------------------------------------------------
  1182. float CFormationDescriptor::GetNodeDistanceToOwner(const FormationNode& nodeDescriptor) const
  1183. {
  1184.         if (m_Nodes.size())
  1185.         {
  1186.                 if (nodeDescriptor.fFollowDistance)
  1187.                         return sqrtf(nodeDescriptor.fFollowDistance * nodeDescriptor.fFollowDistance +
  1188.                                      nodeDescriptor.fFollowOffset * nodeDescriptor.fFollowOffset);
  1189.                 else
  1190.                         return nodeDescriptor.vOffset.GetLength();
  1191.         }
  1192.         else
  1193.                 return 0;
  1194. }
  1195.  
  1196. //----------------------------------------------------------------------
  1197. void CFormationDescriptor::AddNode(const FormationNode& nodeDescriptor)
  1198. {
  1199.         // insert new node descriptor in a distance-to-owner sorted vector
  1200.         if (m_Nodes.size() && nodeDescriptor.eClass != SPECIAL_FORMATION_POINT)
  1201.         {
  1202.                 TVectorOfNodes::iterator itNext = m_Nodes.begin();
  1203.                 float fDist = GetNodeDistanceToOwner(nodeDescriptor);
  1204.                 for (TVectorOfNodes::iterator it = m_Nodes.begin(); it != m_Nodes.end(); ++it)
  1205.                 {
  1206.                         ++itNext;
  1207.                         if (itNext != m_Nodes.end())
  1208.                         {
  1209.                                 float fDistNext = GetNodeDistanceToOwner(*itNext);
  1210.                                 if (fDist < fDistNext || itNext->eClass == SPECIAL_FORMATION_POINT)
  1211.                                 // leave the special formation points at the bottom
  1212.                                 {
  1213.                                         m_Nodes.insert(itNext, nodeDescriptor);
  1214.                                         break;
  1215.                                 }
  1216.                         }
  1217.                         else
  1218.                         {
  1219.                                 m_Nodes.push_back(nodeDescriptor);
  1220.                                 break;
  1221.                         }
  1222.                 }
  1223.         }
  1224.         else
  1225.                 m_Nodes.push_back(nodeDescriptor);
  1226. }
  1227.  
  1228. void CFormation::SetUpdate(bool bUpdate)
  1229. {
  1230.         m_bUpdate = bUpdate;
  1231.         if (bUpdate)
  1232.                 m_fLastUpdateTime.SetValue(0); // force update the next time, when SetUpdate(true) is called
  1233. }
  1234.  
  1235. //----------------------------------------------------------------------
  1236. void CFormation::SetUpdateThresholds(float value)
  1237. {
  1238.         m_fDynamicUpdateThreshold = value;
  1239.         m_fStaticUpdateThreshold = 5 * value;
  1240. }
  1241.  
  1242. //----------------------------------------------------------------------
  1243. CAIObject* CFormation::GetClosestPoint(CAIActor* pRequester, bool bReserve, int iClass)
  1244. {
  1245.         int index = GetClosestPointIndex(GetWeakRef(pRequester), bReserve, 0, iClass);
  1246.         return (index < 0 ? NULL : m_FormationPoints[index].m_refWorldPoint.GetAIObject());
  1247. }
  1248.  
  1249. //
  1250. //--------------------------------------------------------------------------------------------------------------
  1251. void CFormation::Serialize(TSerialize ser)
  1252. {
  1253.         ser.BeginGroup("AIFormation");
  1254.         {
  1255.                 ser.Value("m_Id", m_formationID);
  1256.                 ser.Value("m_FormationPoints", m_FormationPoints);
  1257.  
  1258.                 m_refOwner.Serialize(ser, "m_refOwner");
  1259.  
  1260.                 ser.Value("m_bReservationAllowed", m_bReservationAllowed);
  1261.  
  1262.                 ser.Value("m_vLastUpdatePos", m_vLastUpdatePos);
  1263.                 ser.Value("m_vLastPos", m_vLastPos);
  1264.                 ser.Value("m_vLastTargetPos", m_vLastTargetPos);
  1265.                 ser.Value("m_vLastMoveDir", m_vLastMoveDir);
  1266.                 ser.Value("m_vInitialDir", m_vInitialDir);
  1267.                 ser.Value("m_vMoveDir", m_vMoveDir);
  1268.                 ser.Value("m_bInitMovement", m_bInitMovement);
  1269.                 ser.Value("m_bFirstUpdate", m_bFirstUpdate);
  1270.                 ser.Value("m_bUpdate", m_bUpdate);
  1271.                 ser.Value("m_bForceReachable", m_bForceReachable);
  1272.                 ser.Value("m_bFollowingUnits", m_bFollowingUnits);
  1273.                 ser.Value("m_bFollowingPointInitialized", m_bFollowPointInitialized);
  1274.                 ser.Value("m_fUpdateThreshold", m_fUpdateThreshold);
  1275.                 ser.Value("m_fDynamicUpdateThreshold", m_fDynamicUpdateThreshold);
  1276.                 ser.Value("m_fStaticUpdateThreshold", m_fStaticUpdateThreshold);
  1277.                 ser.Value("m_fScaleFactor", m_fScaleFactor);
  1278.                 ser.Value("m_iSpecialPointIndex", m_iSpecialPointIndex);
  1279.                 ser.Value("m_fMaxFollowDistance", m_fMaxFollowDistance);
  1280.                 ser.Value("m_fLastUpdateTime", m_fLastUpdateTime);
  1281.                 ser.Value("m_fMaxUpdateSightTime", m_maxUpdateSightTimeMs);
  1282.                 ser.Value("m_fMinUpdateSightTime", m_minUpdateSightTimeMs);
  1283.                 ser.Value("m_fSightRotationRange", m_fSightRotationRange);
  1284.                 ser.Value("m_szDescriptor", m_szDescriptor);
  1285.  
  1286.                 m_refReferenceTarget.Serialize(ser, "m_refReferenceTarget");
  1287.  
  1288.                 ser.Value("m_fRepositionSpeedWrefTarget", m_fRepositionSpeedWrefTarget);
  1289.                 ser.Value("m_vDesiredTargetPos", m_vDesiredTargetPos);
  1290.                 ser.EnumValue("m_orientationType", m_orientationType, OT_MOVE, OT_VIEW);
  1291.  
  1292.                 if (ser.IsWriting())
  1293.                 {
  1294.                         if (ser.BeginOptionalGroup("FormationPathMarker", m_pPathMarker != NULL))
  1295.                         {
  1296.                                 if (m_pPathMarker)
  1297.                                         m_pPathMarker->Serialize(ser);
  1298.                                 ser.EndGroup();
  1299.                         }
  1300.                 }
  1301.                 else
  1302.                 {
  1303.                         m_fLastUpdateTime = 0.0f;
  1304.                         if (ser.BeginOptionalGroup("FormationPathMarker", true))
  1305.                         {
  1306.                                 if (m_pPathMarker)
  1307.                                 {
  1308.                                         delete m_pPathMarker;
  1309.                                         m_pPathMarker = 0;
  1310.                                 }
  1311.                                 m_pPathMarker = new CPathMarker(m_fMaxFollowDistance + 10, m_fDISTANCE_UPDATE_THR / 2);
  1312.                                 m_pPathMarker->Serialize(ser);
  1313.                                 ser.EndGroup();
  1314.                         }
  1315.                 }
  1316.                 ser.EndGroup();
  1317.         }
  1318.  
  1319. }
  1320.  
  1321. //
  1322. //--------------------------------------------------------------------------------------------------------------
  1323. CFormationPoint::CFormationPoint()
  1324.         : m_vPoint(ZERO)
  1325.         , m_vSight(ZERO)
  1326.         , m_FollowDistance(0.0f)
  1327.         , m_FollowOffset(0.0f)
  1328.         , m_FollowDistanceAlternate(0.0f)
  1329.         , m_FollowOffsetAlternate(0.0f)
  1330.         , m_FollowHeightOffset(0.0f)
  1331.         , m_Speed(0)
  1332.         , m_LastPosition(ZERO)
  1333.         , m_Dir(ZERO)
  1334.         , m_Class(0)
  1335.         , m_FollowFlag(false)
  1336.         , m_DEBUG_vInitPos(ZERO)
  1337. {
  1338.  
  1339. }
  1340.  
  1341. //
  1342. //--------------------------------------------------------------------------------------------------------------
  1343. CFormationPoint::~CFormationPoint()
  1344. {
  1345. }
  1346.  
  1347. //
  1348. //--------------------------------------------------------------------------------------------------------------
  1349. void CFormationPoint::Serialize(TSerialize ser)
  1350. {
  1351.         ser.BeginGroup("FormationPoint");
  1352.         ser.Value("m_vPoint", m_vPoint);
  1353.         ser.Value("m_vSight", m_vSight);
  1354.         ser.Value("m_FollowDistance", m_FollowDistance);
  1355.         ser.Value("m_FollowOffset", m_FollowOffset);
  1356.         ser.Value("m_FollowHeightOffset", m_FollowHeightOffset);
  1357.         ser.Value("m_FollowDistanceAlternate", m_FollowDistanceAlternate);
  1358.         ser.Value("m_FollowOffsetAlternate", m_FollowOffsetAlternate);
  1359.         ser.Value("m_Speed", m_Speed);
  1360.         ser.Value("m_LastPosition", m_LastPosition);
  1361.         ser.Value("m_Dir", m_Dir);
  1362.         ser.Value("m_Class", m_Class);
  1363.  
  1364.         m_refWorldPoint.Serialize(ser, "m_refWorldPoint");
  1365.         m_refReservation.Serialize(ser, "m_refReservation");
  1366.         m_refDummyTarget.Serialize(ser, "m_refDummyTarget");
  1367.  
  1368.         ser.Value("m_FollowFlag", m_FollowFlag);
  1369.         ser.EndGroup();
  1370. }
  1371.  
  1372. //
  1373. //--------------------------------------------------------------------------------------------------------------
  1374. void CFormation::Change(CFormationDescriptor& desc, float fScale)
  1375. {
  1376.         if (desc.m_sName != m_szDescriptor)
  1377.         {
  1378.  
  1379.                 if (desc.m_Nodes.empty() || m_FormationPoints.empty())
  1380.                         return;
  1381.  
  1382.                 m_szDescriptor = desc.m_sName;
  1383.                 CFormationDescriptor::TVectorOfNodes::iterator vi;
  1384.                 TFormationPoints::iterator fi;
  1385.  
  1386.                 std::vector<bool> vDescChanged;
  1387.                 std::vector<bool> vPointChanged;
  1388.  
  1389.                 for (vi = desc.m_Nodes.begin(); vi != desc.m_Nodes.end(); ++vi)
  1390.                         vDescChanged.push_back(false);
  1391.  
  1392.                 for (fi = m_FormationPoints.begin(); fi != m_FormationPoints.end(); ++fi)
  1393.                         vPointChanged.push_back(false);
  1394.  
  1395.                 m_bFollowingUnits = false;
  1396.  
  1397.                 m_fMaxFollowDistance = 0;
  1398.                 //              float m_fMaxYOffset = -1000000;
  1399.                 //              m_iForemostNodeIndex = -1;
  1400.                 m_iSpecialPointIndex = -1;
  1401.  
  1402.                 m_fScaleFactor = 1;
  1403.  
  1404.                 float oldMaxFollowDistance = m_fMaxFollowDistance;
  1405.                 m_fMaxFollowDistance = 0;
  1406.                 //int i =0;
  1407.                 for (int iteration = 0; iteration < 2; iteration++)
  1408.                 {
  1409.                         // iteration = 0 : consider only current points with a reservation (change them first)
  1410.                         // iteration = 1 : consider all current points
  1411.                         int i = 0;
  1412.                         TFormationPoints::iterator itrPoint(m_FormationPoints.begin());
  1413.  
  1414.                         for (++itrPoint; itrPoint != m_FormationPoints.end(); ++itrPoint)
  1415.                         {
  1416.                                 CFormationPoint& frmPoint = (*itrPoint);
  1417.  
  1418.                                 if (iteration == 0 && !frmPoint.m_refReservation.IsValid() || iteration == 1 && vPointChanged[i])
  1419.                                         continue;
  1420.  
  1421.                                 int iClass = frmPoint.m_Class;
  1422.  
  1423.                                 bool bFound = false;
  1424.                                 for (int iTestType = 0; iTestType < 5 && !bFound; iTestType++)
  1425.                                 {
  1426.                                         int j = 1;
  1427.                                         vi = desc.m_Nodes.begin();
  1428.                                         for (++vi; !bFound && vi != desc.m_Nodes.end(); ++vi)
  1429.                                         {
  1430.                                                 int iNewClass = (*vi).eClass;
  1431.                                                 if (!vDescChanged[j] &&
  1432.                                                     (iTestType == 0 && iNewClass == iClass ||
  1433.                                                      iTestType == 1 && (iNewClass & iClass) == min(iNewClass, iClass) ||
  1434.                                                      iTestType == 2 && (iNewClass & iClass) != 0 ||
  1435.                                                      iTestType == 3 && (iNewClass == UNIT_CLASS_UNDEFINED) ||
  1436.                                                      iTestType == 4))
  1437.                                                 {
  1438.                                                         Vec3 pos = (*vi).vOffset;
  1439.                                                         float fDistance = (*vi).fFollowDistance;
  1440.                                                         frmPoint.m_FollowDistance = fDistance;
  1441.  
  1442.                                                         if (frmPoint.m_FollowDistance > 0)
  1443.                                                         {
  1444.                                                                 pos = Vec3((*vi).fFollowOffset, fDistance, 0);
  1445.                                                                 if (m_fMaxFollowDistance < frmPoint.m_FollowDistance)
  1446.                                                                         m_fMaxFollowDistance = frmPoint.m_FollowDistance;
  1447.                                                         }
  1448.                                                         /*else if(m_fMaxYOffset < pos.y)
  1449.                                                            { // find the foremost formation unit to be followed
  1450.                                                            m_fMaxYOffset = pos.y;
  1451.                                                            m_iForemostNodeIndex = i;
  1452.                                                            }*/
  1453.                                                         if (iClass == SPECIAL_FORMATION_POINT)
  1454.                                                                 m_iSpecialPointIndex = i;
  1455.                                                         frmPoint.m_vPoint = pos;
  1456.                                                         frmPoint.m_FollowOffset = (*vi).fFollowOffset;
  1457.  
  1458.                                                         frmPoint.m_FollowDistanceAlternate = (*vi).fFollowDistanceAlternate;
  1459.                                                         frmPoint.m_FollowOffsetAlternate = (*vi).fFollowOffsetAlternate;
  1460.                                                         frmPoint.m_FollowHeightOffset = (*vi).fFollowHeightOffset;
  1461.  
  1462.                                                         vDescChanged[j] = true;
  1463.                                                         vPointChanged[i] = true;
  1464.                                                         bFound = true;
  1465.                                                 }
  1466.                                                 j++;
  1467.                                         } // vi
  1468.  
  1469.                                 } // testType
  1470.  
  1471.                                 ++i;
  1472.                         } // itrpoint
  1473.                 }   // iteration
  1474.                 //              if(m_iForemostNodeIndex<0)
  1475.                 //                      m_bFollowingUnits = false; // if it was true but no foremost node, it means that all the nodes
  1476.                 // were set to follow
  1477.                 int i = 0;
  1478.  
  1479.                 // Delete old points not used and set the flag m_bFollowingUnits
  1480.                 for (TFormationPoints::iterator itrPoint(m_FormationPoints.begin()); itrPoint != m_FormationPoints.end(); )
  1481.                 {
  1482.                         CFormationPoint& frmPoint = (*itrPoint);
  1483.                         if (!vPointChanged[i] && !frmPoint.m_refReservation.IsValid())
  1484.                         {
  1485.                                 frmPoint.m_refWorldPoint.Release();
  1486.                                 frmPoint.m_refDummyTarget.Release();
  1487.                                 itrPoint = m_FormationPoints.erase(itrPoint);
  1488.                         }
  1489.                         else
  1490.                         {
  1491.  
  1492.                                 if (frmPoint.m_FollowDistance > 0)
  1493.                                         m_bFollowingUnits = true;
  1494.                                 ++itrPoint;
  1495.                         }
  1496.                         i++;
  1497.                 }
  1498.  
  1499.                 // Add new points
  1500.                 int j = 1;
  1501.                 vi = desc.m_Nodes.begin();
  1502.                 for (++vi; vi != desc.m_Nodes.end(); ++vi)
  1503.                 {
  1504.                         if (!vDescChanged[j])
  1505.                         {
  1506.                                 FormationNode& descNode = *vi;
  1507.                                 AddPoint(descNode);
  1508.                         }
  1509.                         j++;
  1510.                 }
  1511.  
  1512.                 m_bInitMovement = true;
  1513.                 m_bFirstUpdate = true;
  1514.                 m_bFollowPointInitialized = false;
  1515.  
  1516.                 CAIObject* const pOwner = m_refOwner.GetAIObject();
  1517.                 if (pOwner)
  1518.                 {
  1519.                         if (m_bFollowingUnits && oldMaxFollowDistance < m_fMaxFollowDistance)
  1520.                         {
  1521.                                 if (m_pPathMarker)
  1522.                                 {
  1523.                                         delete m_pPathMarker;
  1524.                                         m_pPathMarker = 0;
  1525.                                 }
  1526.                                 m_pPathMarker = new CPathMarker(m_fMaxFollowDistance + 10, m_fDISTANCE_UPDATE_THR / 2);
  1527.                                 m_pPathMarker->Init(pOwner->GetPos(), pOwner->GetPos() - m_fMaxFollowDistance * m_vMoveDir);
  1528.                         }
  1529.                         InitWorldPosition(m_vMoveDir);
  1530.                 }
  1531.         }
  1532.  
  1533.         if (fScale != m_fScaleFactor)
  1534.         {
  1535.                 // (MATT) The only call {2009/02/14}
  1536.                 SetScale(fScale);
  1537.         }
  1538.  
  1539. }
  1540. //
  1541. //--------------------------------------------------------------------------------------------------------------
  1542. void CFormation::SetScale(float fScale)
  1543. {
  1544.         // to do: retrieve the original offsets/distances when the old scale factor is 0?
  1545.         if (fScale == 0)
  1546.                 return;
  1547.  
  1548.         if (fScale == m_fScaleFactor)
  1549.                 return;
  1550.  
  1551.         float fActualScale = fScale / m_fScaleFactor;
  1552.         m_fMaxFollowDistance *= fActualScale;
  1553.         m_fScaleFactor = fScale;
  1554.  
  1555.         if (!m_FormationPoints.empty())
  1556.         {
  1557.                 // modify all points
  1558.                 for (TFormationPoints::iterator itrPoint(m_FormationPoints.begin()); itrPoint != m_FormationPoints.end(); ++itrPoint)
  1559.                 {
  1560.                         itrPoint->m_vPoint *= fActualScale;
  1561.                         itrPoint->m_FollowDistance *= fActualScale;
  1562.                         itrPoint->m_FollowOffset *= fActualScale;
  1563.                         itrPoint->m_FollowDistanceAlternate *= fActualScale;
  1564.                         itrPoint->m_FollowOffsetAlternate *= fActualScale;
  1565.                         itrPoint->m_FollowHeightOffset *= fActualScale;
  1566.                 }
  1567.  
  1568.                 CAIObject* const pOwner = m_FormationPoints[0].m_refReservation.GetAIObject();
  1569.                 if (!pOwner)
  1570.                         return;
  1571.  
  1572.                 CCCPOINT(CFormation_SetScale);
  1573.  
  1574.                 // find the formation orientation
  1575.                 Vec3 vDir = m_vMoveDir;
  1576.                 if (vDir.IsZero())
  1577.                 {
  1578.                         if (m_bFollowingUnits && m_pPathMarker)
  1579.                         {
  1580.                                 vDir = m_pPathMarker->GetPointAtDistance(pOwner->GetPos(), 1);
  1581.                                 vDir -= pOwner->GetPos();
  1582.                                 vDir.z = 0; //2d only
  1583.                                 vDir.NormalizeSafe();
  1584.                                 if (vDir.IsZero())
  1585.                                         vDir = pOwner->GetMoveDir();
  1586.                         }
  1587.                         else
  1588.                         {
  1589.                                 pe_status_dynamics dSt;
  1590.                                 pOwner->GetProxy()->GetPhysics()->GetStatus(&dSt);
  1591.                                 vDir = -dSt.v;
  1592.                                 if (!vDir.IsZero())
  1593.                                         vDir.Normalize();
  1594.                                 else
  1595.                                         vDir = pOwner->GetMoveDir();
  1596.  
  1597.                         }
  1598.                 }
  1599.                 SetOffsetPointsPos(vDir);
  1600.                 // modify path marker if the new formation is bigger
  1601.                 if (m_bFollowingUnits && fActualScale > 1)
  1602.                 {
  1603.                         vDir.z = 0;
  1604.                         vDir.NormalizeSafe();
  1605.                         m_vInitialDir = vDir;
  1606.  
  1607.                         if (m_pPathMarker)
  1608.                         {
  1609.                                 delete m_pPathMarker;
  1610.                                 m_pPathMarker = 0;
  1611.                         }
  1612.  
  1613.                         // (MATT) Apart from serialisation, this is the only place the marker is set {2009/02/14}
  1614.                         CCCPOINT(CFormation_SetScale_NewPathMarker);
  1615.                         m_pPathMarker = new CPathMarker(m_fMaxFollowDistance + 10, m_fDISTANCE_UPDATE_THR / 2);
  1616.                         m_pPathMarker->Init(pOwner->GetPos(), pOwner->GetPos() - m_fMaxFollowDistance * vDir);
  1617.                         InitFollowPoints();//,vDir,pOwner);
  1618.  
  1619.                 }
  1620.         }
  1621. }
  1622.  
  1623. Vec3 CFormation::GetPredictedPointPosition(CWeakRef<const CAIObject> refRequestor, const Vec3& ownerPos, const Vec3& ownerLookDir, Vec3 ownerMoveDir) const
  1624. {
  1625.         const CFormationPoint* pFormPoint = NULL;
  1626.         if (ownerMoveDir.IsZero())
  1627.                 ownerMoveDir = ownerLookDir;
  1628.  
  1629.         for (TFormationPoints::const_iterator itrPoint(m_FormationPoints.begin()); itrPoint != m_FormationPoints.end(); ++itrPoint)
  1630.                 if (itrPoint->m_refReservation == refRequestor)
  1631.                 {
  1632.                         pFormPoint = &(*itrPoint);
  1633.                         break;
  1634.                 }
  1635.  
  1636.         if (!pFormPoint)
  1637.                 return ZERO;
  1638.  
  1639.         CCCPOINT(CFormation_GetPredictedPointPosition);
  1640.  
  1641.         Vec3 vPredictedPos;
  1642.         if (pFormPoint->m_FollowDistance > 0)
  1643.         {
  1644.                 // approximate, assumes that the follow points will be aligned along ownerDir
  1645.                 vPredictedPos.Set(pFormPoint->m_FollowOffset * (ownerMoveDir.x),
  1646.                                   pFormPoint->m_FollowDistance * (-ownerMoveDir.y),
  1647.                                   pFormPoint->m_FollowHeightOffset);
  1648.                 vPredictedPos += ownerPos;
  1649.                 return vPredictedPos;
  1650.         }
  1651.         else
  1652.         {
  1653.                 vPredictedPos.Set(pFormPoint->m_vPoint.x * ownerLookDir.y, pFormPoint->m_vPoint.y * (-ownerLookDir.x), pFormPoint->m_vPoint.z);
  1654.                 vPredictedPos += ownerPos;
  1655.                 return vPredictedPos;
  1656.         }
  1657. }
  1658.  
  1659. void CFormation::SetReferenceTarget(const CAIObject* pTarget, float speed)
  1660. {
  1661.         m_refReferenceTarget = GetWeakRef(pTarget);
  1662.         m_vLastTargetPos.zero();
  1663.         m_fRepositionSpeedWrefTarget = speed;
  1664.         m_vDesiredTargetPos.zero();
  1665.         m_vLastUpdatePos.zero(); //to force update
  1666.         Update();
  1667. }
  1668.  
  1669. void CFormation::SetUpdateSight(float angleRange, float minTime /*=0*/, float maxTime /*=0*/)
  1670. {
  1671.         m_fSightRotationRange = angleRange;
  1672.         m_minUpdateSightTimeMs = (int)(minTime * 1000.0f);
  1673.         m_maxUpdateSightTimeMs = (int)(maxTime * 1000.0f);
  1674. }
  1675.  
downloadFormation.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