BVB Source Codes

CRYENGINE Show FireCommand.cpp Source code

Return Download CRYENGINE: download FireCommand.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:   FireCommand.cpp
  6.    $Id$
  7.    Description:
  8.  
  9.    -------------------------------------------------------------------------
  10.    History:
  11.    -
  12.  
  13.  *********************************************************************/
  14. #include "StdAfx.h"
  15. #include "FireCommand.h"
  16. #include "Puppet.h"
  17. #include <CryMath/PNoise3.h>
  18. #include "DebugDrawContext.h"
  19. #include "AIPlayer.h"
  20.  
  21. #if defined(GetObject)
  22.         #undef GetObject
  23. #endif
  24.  
  25. //#pragma optimize("", off)
  26. //#pragma inline_depth(0)
  27.  
  28. //====================================================================
  29. // CFireCommandInstant
  30. //====================================================================
  31. CFireCommandInstant::CFireCommandInstant(IAIActor* pShooter)
  32.         : m_pShooter(((CAIActor*)pShooter)->CastToCPuppet())
  33.         , m_weaponBurstState(BURST_NONE)
  34.         , m_weaponBurstTime(0.0f)
  35.         , m_weaponBurstTimeScale(1.0f)
  36.         , m_weaponBurstTimeWithoutShot(0.0f)
  37.         , m_weaponBurstBulletCount(0)
  38.         , m_curBurstBulletCount(0)
  39.         , m_curBurstPauseTime(0.0f)
  40.         , m_weaponTriggerTime(0.0f)
  41.         , m_weaponTriggerState(true)
  42.         , m_coverFireTime(0.0f)
  43.         , m_ShotsCount(0)
  44. {
  45. }
  46.  
  47. //
  48. //--------------------------------------------------------------------------------------------------------
  49. void CFireCommandInstant::Reset()
  50. {
  51.         AIAssert(m_pShooter);
  52.         m_weaponBurstState = BURST_NONE;
  53.         m_weaponBurstTime = 0;
  54.         m_weaponBurstTimeScale = 1;
  55.         m_weaponBurstTimeWithoutShot = 0.0f;
  56.         m_weaponBurstBulletCount = 0;
  57.         m_curBurstBulletCount = 0;
  58.         m_curBurstPauseTime = 0;
  59.         m_weaponTriggerTime = 0;
  60.         m_weaponTriggerState = true;
  61.  
  62.         m_drawFire.Reset();
  63. }
  64.  
  65. //
  66. //--------------------------------------------------------------------------------------------------------
  67. EAIFireState CFireCommandInstant::Update(IAIObject* pITarget, bool canFire, EFireMode fireMode, const AIWeaponDescriptor& descriptor, Vec3& outShootTargetPos)
  68. {
  69.         float dt = GetAISystem()->GetFrameDeltaTime();
  70.  
  71.         m_coverFireTime = descriptor.coverFireTime * gAIEnv.CVars.RODCoverFireTimeMod;
  72.  
  73.         if (!canFire || !pITarget)
  74.         {
  75.                 m_weaponBurstState = BURST_NONE;
  76.                 canFire = false;
  77.         }
  78.  
  79.         EAimState aim = m_pShooter->GetAimState();
  80.         if (aim != AI_AIM_READY && aim != AI_AIM_FORCED)
  81.         {
  82.                 m_weaponBurstState = BURST_NONE;
  83.                 canFire = false;
  84.         }
  85.  
  86.         bool canHit = m_drawFire.Update(dt, m_pShooter, pITarget, descriptor, outShootTargetPos, canFire);
  87.  
  88.         if (!canFire)
  89.                 return eAIFS_Off;
  90.  
  91.         const float clampAngle = DEG2RAD(5.0f);
  92.  
  93.         float FakeHitChance = gAIEnv.CVars.RODFakeHitChance;
  94.         if (m_pShooter->m_targetZone == AIZONE_KILL)
  95.                 FakeHitChance = 1.0f;
  96.         else if (gAIEnv.configuration.eCompatibilityMode != ECCM_GAME04)
  97.         {
  98.                 if (!m_pShooter->HasFiringReactionTimePassed())
  99.                         FakeHitChance = 0.0f;
  100.         }
  101.  
  102.         if (m_drawFire.GetState() != DrawFireEffect::Finished)
  103.         {
  104.                 if (gAIEnv.CVars.DebugDrawFireCommand)
  105.                 {
  106.                         CDebugDrawContext dc;
  107.  
  108.                         Vec3 shooter = m_pShooter->GetPos();
  109.  
  110.                         float x, y, z;
  111.                         if (dc->ProjectToScreen(shooter.x, shooter.y, shooter.z, &x, &y, &z))
  112.                         {
  113.                                 if (z >= 0.0f)
  114.                                 {
  115.                                         x *= (float)dc->GetWidth() * 0.01f;
  116.                                         y *= (float)dc->GetHeight() * 0.01f;
  117.  
  118.                                         dc->Draw2dLabel(x, y + 10, 1.25f, Col_YellowGreen, true, "%s", "Draw Fire");
  119.                                 }
  120.                         }
  121.                 }
  122.  
  123.                 CAIObject* targetObject = static_cast<CAIObject*>(pITarget);
  124.                 CAIPlayer* player = pITarget ? pITarget->CastToCAIPlayer() : 0;
  125.  
  126.                 const bool canFakeHit = cry_random(0.0f, 1.0f) <= FakeHitChance;
  127.                 const bool allowedToHit = gAIEnv.CVars.AllowedToHit && (!player || gAIEnv.CVars.AllowedToHitPlayer) && m_pShooter->IsAllowedToHitTarget();
  128.                 const bool shouldHit = m_pShooter->CanDamageTarget() || canFakeHit;
  129.  
  130.                 if (m_pShooter->AdjustFireTarget(targetObject, outShootTargetPos, allowedToHit && shouldHit, descriptor.spreadRadius,
  131.                                                  DEG2RAD(5.5f), &outShootTargetPos))
  132.                 {
  133.                         if (m_pShooter->IsFireTargetValid(outShootTargetPos, targetObject))
  134.                                 return eAIFS_On;
  135.                 }
  136.  
  137.                 return eAIFS_Off;
  138.         }
  139.  
  140.         // Determine how we should handle a memory target fire
  141.         if (!m_pShooter->CanMemoryFire() &&
  142.             fireMode != FIREMODE_CONTINUOUS && fireMode != FIREMODE_FORCED &&
  143.             fireMode != FIREMODE_PANIC_SPREAD && fireMode != FIREMODE_KILL)
  144.         {
  145.                 m_weaponBurstState = BURST_NONE;
  146.  
  147.                 return eAIFS_Off;
  148.         }
  149.  
  150.         const int burstBulletCountMin = descriptor.burstBulletCountMin;
  151.         const int burstBulletCountMax = descriptor.burstBulletCountMax;
  152.         const float burstPauseTimeMin = descriptor.burstPauseTimeMin;
  153.         const float burstPauseTimeMax = descriptor.burstPauseTimeMax;
  154.         const float singleFireTriggerTime = descriptor.singleFireTriggerTime;
  155.  
  156.         bool singleFireMode = singleFireTriggerTime > 0.0f;
  157.  
  158.         if (singleFireMode)
  159.         {
  160.                 m_weaponTriggerTime -= dt;
  161.  
  162.                 if (m_weaponTriggerTime <= 0.0f)
  163.                 {
  164.                         m_weaponTriggerState = !m_weaponTriggerState;
  165.                         m_weaponTriggerTime += singleFireTriggerTime * cry_random(0.75f, 1.25f);
  166.                 }
  167.         }
  168.         else
  169.         {
  170.                 m_weaponTriggerTime = 0.0f;
  171.                 m_weaponTriggerState = true;
  172.         }
  173.  
  174.         // Burst control
  175.         if (fireMode == FIREMODE_BURST || fireMode == FIREMODE_BURST_DRAWFIRE ||
  176.             fireMode == FIREMODE_BURST_WHILE_MOVING || fireMode == FIREMODE_BURST_SNIPE)
  177.         {
  178.                 float distScale = m_pShooter->GetBurstFireDistanceScale();
  179.  
  180.                 const float lostFadeMinTime = m_coverFireTime * 0.25f;
  181.                 const float lostFadeMaxTime = m_coverFireTime;
  182.                 const int fadeSteps = 6;
  183.  
  184.                 float a = 1.0f;
  185.                 float fade = clamp_tpl((m_pShooter->m_targetLostTime - lostFadeMinTime) / max(lostFadeMaxTime - lostFadeMinTime, FLT_EPSILON), 0.0f, 1.0f);
  186.                 a *= 1.0f - floorf(fade * fadeSteps) / (float)fadeSteps; // more lost, less bullets
  187.                 a *= distScale;                                          // scaling based on the zone (distance)
  188.                 a *= m_pShooter->IsAllowedToHitTarget() ? 1.0f : 0.2f;
  189.                 m_curBurstBulletCount = (int)(burstBulletCountMin + (burstBulletCountMax - burstBulletCountMin) * a * m_weaponBurstTimeScale);
  190.                 m_curBurstPauseTime = burstPauseTimeMin + (1.0f - sqr(a) * 0.75f) * (burstPauseTimeMax - burstPauseTimeMin) * m_weaponBurstTimeScale;
  191.  
  192.                 float chargeTime = std::max(0.0f, descriptor.fChargeTime);
  193.  
  194.                 if (m_weaponBurstState == BURST_NONE)
  195.                 {
  196.                         // Init
  197.                         m_weaponBurstTime = 0.0f;
  198.                         m_weaponBurstTimeScale = cry_random(1, 6) / 6.0f;
  199.                         m_weaponBurstState = BURST_FIRE;
  200.                         m_weaponBurstBulletCount = 0;
  201.                         m_weaponBurstTimeWithoutShot = 0;
  202.  
  203.                         m_pShooter->HandleBurstFireInit();
  204.                 }
  205.                 else if (m_weaponBurstState == BURST_FIRE)
  206.                 {
  207.                         int shotCount = m_pShooter->GetProxy()->GetAndResetShotBulletCount();
  208.                         m_weaponBurstBulletCount += shotCount;
  209.  
  210.                         m_weaponBurstTimeWithoutShot = shotCount ? 0.0f : (m_weaponBurstTimeWithoutShot + dt);
  211.  
  212.                         if (m_weaponBurstBulletCount >= m_curBurstBulletCount)
  213.                         {
  214.                                 if (m_curBurstPauseTime > 0.0f)
  215.                                         m_weaponBurstState = BURST_PAUSE;
  216.                         }
  217.                         else if (!singleFireMode && !shotCount && (m_weaponBurstTimeWithoutShot >= (chargeTime + m_curBurstPauseTime)))
  218.                         {
  219.                                 m_weaponBurstState = BURST_PAUSE;
  220.                         }
  221.                 }
  222.                 else
  223.                 {
  224.                         // Wait
  225.                         m_weaponBurstTime += dt;
  226.                         if (m_weaponBurstTime >= m_curBurstPauseTime)
  227.                                 m_weaponBurstState = BURST_NONE;
  228.                 }
  229.         }
  230.         else
  231.         {
  232.                 // Allow to fire always.
  233.                 m_weaponBurstState = BURST_FIRE;
  234.         }
  235.  
  236.         if (m_weaponBurstState != BURST_FIRE)
  237.         {
  238.                 m_weaponTriggerTime = 0;
  239.                 m_weaponTriggerState = true;
  240.                 return eAIFS_Off;
  241.         }
  242.  
  243.         if (!m_weaponTriggerState)
  244.                 return eAIFS_Off;
  245.  
  246.         CAIObject* targetObject = static_cast<CAIObject*>(pITarget);
  247.         CAIPlayer* player = pITarget ? pITarget->CastToCAIPlayer() : 0;
  248.  
  249.         float burstCanStartHitPercent = 0.0f;
  250.  
  251.         switch (m_pShooter->m_targetZone)
  252.         {
  253.         case AIZONE_OUT:
  254.                 if (pITarget)
  255.                         burstCanStartHitPercent = 0.75f;
  256.                 break;
  257.         case AIZONE_WARN:
  258.                 burstCanStartHitPercent = 0.75f;
  259.                 break;
  260.         case AIZONE_COMBAT_FAR:
  261.                 burstCanStartHitPercent = 0.65f;
  262.                 break;
  263.         case AIZONE_COMBAT_NEAR:
  264.                 burstCanStartHitPercent = 0.35f;
  265.                 break;
  266.         default:
  267.                 break;
  268.         }
  269.  
  270.         const size_t burstFirstHit = (size_t)((m_curBurstBulletCount * burstCanStartHitPercent) + 0.5f);
  271.         const bool canFakeHit = cry_random(0.0f, 1.0f) <= FakeHitChance;
  272.         const bool allowedToHit = gAIEnv.CVars.AllowedToHit && (!player || gAIEnv.CVars.AllowedToHitPlayer) && m_pShooter->IsAllowedToHitTarget();
  273.         const bool shouldHit = m_pShooter->CanDamageTarget() || canFakeHit;
  274.         const bool burstHit = (size_t)m_weaponBurstBulletCount >= burstFirstHit;
  275.  
  276.         if (m_pShooter->AdjustFireTarget(targetObject, outShootTargetPos, allowedToHit && shouldHit && burstHit,
  277.                                          descriptor.spreadRadius, DEG2RAD(5.5f), &outShootTargetPos))
  278.                 return eAIFS_On;
  279.  
  280.         return eAIFS_Off;
  281. }
  282.  
  283. void CFireCommandInstant::DebugDraw()
  284. {
  285.         if (!m_pShooter) return;
  286.  
  287.         const float lostFadeMinTime = m_coverFireTime * 0.25f;
  288.         const float lostFadeMaxTime = m_coverFireTime;
  289.         const int fadeSteps = 6;
  290.  
  291.         float a = 1.0f;
  292.         float fade = clamp_tpl((m_pShooter->m_targetLostTime - lostFadeMinTime) / (lostFadeMaxTime - lostFadeMinTime), 0.0f, 1.0f);
  293.         a *= 1.0f - floorf(fade * fadeSteps) / (float)fadeSteps;  // more lost, less bullets
  294.  
  295.         CDebugDrawContext dc;
  296.         dc->Draw3dLabel(m_pShooter->GetFirePos() - Vec3(0, 0, 1.5f), 1, "Weapon\nShot:%d/%d\nWait:%.2f/%.2f\nA=%f", m_weaponBurstBulletCount, m_curBurstBulletCount, m_weaponBurstTime, m_curBurstPauseTime, a);
  297. }
  298.  
  299. float CFireCommandInstant::GetTimeToNextShot() const
  300. {
  301.         return m_curBurstPauseTime;
  302. }
  303.  
  304. CFireCommandInstant::DrawFireEffect::EState CFireCommandInstant::DrawFireEffect::GetState() const
  305. {
  306.         return m_state.state;
  307. }
  308.  
  309. bool CFireCommandInstant::DrawFireEffect::Update(float updateTime, CPuppet* pShooter, IAIObject* pTarget, const AIWeaponDescriptor& descriptor,
  310.                                                  Vec3& aimTarget, bool canFire)
  311. {
  312.         if (gAIEnv.CVars.DrawFireEffectEnabled < 1)
  313.         {
  314.                 m_state.state = Finished;
  315.                 return true;
  316.         }
  317.  
  318.         if (!pTarget || !pTarget->CastToCAIPlayer())
  319.         {
  320.                 m_state.state = Finished;
  321.                 return true;
  322.         }
  323.  
  324.         const float tooClose = gAIEnv.CVars.DrawFireEffectMinDistance;
  325.         const Vec3& firePos = pShooter->GetFirePos();
  326.         const Vec3& targetPos = pTarget->GetPos();
  327.         float distanceSq = Distance::Point_PointSq(targetPos, firePos);
  328.  
  329.         if (distanceSq <= sqr(tooClose))
  330.         {
  331.                 m_state.state = Finished;
  332.                 return true;
  333.         }
  334.  
  335.         float denom = gAIEnv.CVars.DrawFireEffectDecayRange - tooClose;
  336.         float distance = sqrt_tpl(distanceSq);
  337.         float distanceFactor = (distance - tooClose) / max(denom, 1.0f);
  338.         distanceFactor = clamp_tpl(distanceFactor, 0.0f, 1.0f);
  339.  
  340.         float fovCos = cos_tpl(DEG2RAD(gAIEnv.CVars.DrawFireEffectMinTargetFOV * 0.5f));
  341.  
  342.         Vec3 viewTarget = (firePos - targetPos) * (1.0f / distance);
  343.         Vec3 targetViewDir = pTarget->GetViewDir();
  344.         float viewAngleCos = viewTarget.dot(targetViewDir);
  345.  
  346.         float fovFactor = 0.0f;
  347.         if (viewAngleCos < fovCos)
  348.                 fovFactor = 2.5f * (1.0f - viewAngleCos) / fovCos;
  349.         fovFactor = clamp_tpl(fovFactor, 0.0f, 1.0f);
  350.  
  351.         float drawTime = gAIEnv.CVars.DrawFireEffectTimeScale * descriptor.drawTime;
  352.         drawTime = (0.75f * distanceFactor) * drawTime + (0.25f * fovFactor) * drawTime;
  353.  
  354.         if (drawTime < 0.125f)
  355.         {
  356.                 m_state.state = Finished;
  357.                 return true;
  358.         }
  359.  
  360.         if (canFire)
  361.                 m_state.time += updateTime;
  362.         else
  363.                 m_state.idleTime += updateTime;
  364.  
  365.         if (canFire && drawTime > 0.0f)
  366.         {
  367.                 if (m_state.idleTime >= descriptor.burstPauseTimeMax + 0.15f)
  368.                         m_state = State();
  369.                 m_state.idleTime = 0.0f;
  370.  
  371.                 if (m_state.time > drawTime)
  372.                 {
  373.                         m_state.state = Finished;
  374.                         return true;
  375.                 }
  376.  
  377.                 float targetHeight = 1.75f;
  378.                 if (CAIActor* pTargetActor = pTarget->CastToCAIActor())
  379.                         targetHeight = targetPos.z - pTargetActor->GetPhysicsPos().z;
  380.  
  381.                 Vec3 targetToShooter = firePos - pTarget->GetPos();
  382.                 targetToShooter.z = 0.0f;
  383.  
  384.                 float distance2D = targetToShooter.NormalizeSafe();
  385.                 float t = clamp_tpl(m_state.time / drawTime, 0.0f, 1.0f);
  386.                 float smoothedInvT = sqr(1.0f - sqr(t));
  387.                 float smoothedT = 1.0f - smoothedInvT;
  388.  
  389.                 CPNoise3* noiseGen = gEnv->pSystem->GetNoiseGen();
  390.  
  391.                 float noiseScale = 3.0f * smoothedInvT;
  392.                 float noise = noiseScale * noiseGen->Noise1D(m_state.startSeed + m_state.time * descriptor.sweepFrequency);
  393.  
  394.                 Vec3 right(targetToShooter.y, -targetToShooter.x, 0.0f);
  395.                 Vec3 front(targetViewDir);
  396.                 front.z = clamp_tpl(front.z, -0.35f, 0.35f);
  397.                 front.Normalize();
  398.  
  399.                 float startDistance = distance2D - 5.0f;
  400.                 float angleDecay = clamp_tpl((distance - gAIEnv.CVars.DrawFireEffectMinDistance) / gAIEnv.CVars.DrawFireEffectDecayRange, 0.0f, 1.0f);
  401.                 float maxAngle = DEG2RAD(gAIEnv.CVars.DrawFireEffectMaxAngle) * angleDecay;
  402.  
  403.                 float angle = fabs_tpl(atan2_tpl(targetHeight, startDistance));
  404.                 angle = clamp_tpl(angle, 0.0f, maxAngle);
  405.                 float verticalOffset = tan_tpl(angle) * distance;
  406.  
  407.                 float targetZ = aimTarget.z;
  408.                 float startZ = aimTarget.z - verticalOffset;
  409.  
  410.                 aimTarget += right * (noise * descriptor.sweepWidth);
  411.                 aimTarget.z = startZ + (targetZ - startZ) * smoothedT;
  412.  
  413.                 float frontFactor = (fovFactor * smoothedInvT * descriptor.sweepWidth);
  414.                 aimTarget += front * frontFactor;
  415.  
  416.                 bool canHit = false;
  417.                 if ((aimTarget.z >= (targetPos.z - targetHeight)) && (frontFactor <= 0.35f))
  418.                         canHit = true;
  419.  
  420.                 if (aimTarget.z > targetPos.z + 0.05f)
  421.                         aimTarget.z -= 2.0f * (aimTarget.z - targetPos.z);
  422.  
  423.                 m_state.state = Running;
  424.  
  425.                 if (gAIEnv.CVars.DebugDrawAmbientFire)
  426.                 {
  427.                         float terrainZ = gEnv->p3DEngine->GetTerrainElevation(aimTarget.x, aimTarget.y);
  428.  
  429.                         GetAISystem()->AddDebugSphere(Vec3(aimTarget.x, aimTarget.y, terrainZ + 0.075f), 0.175f, 106, 90, 205, 1.5f);
  430.                         GetAISystem()->AddDebugSphere(targetPos, 0.25f, 255, 0, 0, 1.5f);
  431.                 }
  432.  
  433.                 return canHit;
  434.         }
  435.  
  436.         return true;
  437. }
  438.  
  439. void CFireCommandInstant::DrawFireEffect::Reset()
  440. {
  441.         m_state = State();
  442. }
  443.  
  444. //====================================================================
  445. // CFireCommandLob
  446. //====================================================================
  447. CFireCommandLob::CFireCommandLob(IAIActor* pShooter)
  448.         : m_pShooter(((CAIActor*)pShooter)->CastToCPuppet())
  449.         , m_lastStep(0)
  450.         , m_targetPos(ZERO)
  451.         , m_throwDir(ZERO)
  452.         , m_nextFireTime(0.0f)
  453.         , m_preferredHeight(0.0f)
  454.         , m_projectileSpeedScale(0.0f)
  455.         , m_bestScore(-1)
  456. {
  457. #ifdef CRYAISYSTEM_DEBUG
  458.         m_debugBest = 0.0f;
  459. #endif //CRYAISYSTEM_DEBUG
  460.  
  461.         assert(m_pShooter);
  462. }
  463.  
  464. //
  465. //---------------------------------------------------------------------------------------------------------------
  466. CFireCommandLob::~CFireCommandLob()
  467. {
  468.         ClearDebugEvals();
  469. }
  470.  
  471. //
  472. //---------------------------------------------------------------------------------------------------------------
  473. void CFireCommandLob::Reset()
  474. {
  475.         m_lastStep = 0;
  476.         m_targetPos.zero();
  477.         m_throwDir.zero();
  478.         m_nextFireTime = 0.0f;
  479.         m_preferredHeight = 0.0f;
  480.         m_projectileSpeedScale = 0.0f;
  481.         m_bestScore = -1;
  482. }
  483.  
  484. //
  485. //---------------------------------------------------------------------------------------------------------------
  486. void CFireCommandLob::ClearDebugEvals()
  487. {
  488. #ifdef CRYAISYSTEM_DEBUG
  489.         m_DEBUG_evals.clear();
  490.         m_debugBest = 0.0f;
  491. #endif //CRYAISYSTEM_DEBUG
  492. }
  493.  
  494. //
  495. //---------------------------------------------------------------------------------------------------------------
  496. EAIFireState CFireCommandLob::Update(IAIObject* pTarget, bool canFire, EFireMode fireMode, const AIWeaponDescriptor& descriptor, Vec3& outShootTargetPos)
  497. {
  498.         FUNCTION_PROFILER(gEnv->pSystem, PROFILE_AI);
  499.  
  500.         EAIFireState state = eAIFS_Off;
  501.  
  502.         if (canFire && pTarget && m_pShooter)
  503.         {
  504.                 const CTimeValue currTime = GetAISystem()->GetFrameStartTime();
  505.  
  506.                 // First fire should wait for the charge time
  507.                 if (m_nextFireTime <= 0.0f)
  508.                 {
  509.                         m_nextFireTime = currTime + descriptor.fChargeTime;
  510.                 }
  511.  
  512.                 // Keep testing lob path if we've already started or if enough time has past since last fire
  513.                 bool bGetBestLob = (0 != m_lastStep || m_nextFireTime <= currTime);
  514.                 if (bGetBestLob)
  515.                 {
  516.                         const EAimState aim = m_pShooter->GetAimState();
  517.                         const bool bValidAim = (aim == AI_AIM_READY || aim == AI_AIM_FORCED || !IsUsingPrimaryWeapon());
  518.                         if (bValidAim)
  519.                         {
  520.                                 state = GetBestLob(pTarget, descriptor, outShootTargetPos);
  521.                                 if (state != eAIFS_Blocking)
  522.                                 {
  523.                                         // Calculate next fire time
  524.                                         const float fNextFireTime = cry_random(descriptor.burstPauseTimeMin, descriptor.burstPauseTimeMax);
  525.                                         m_nextFireTime = currTime + fNextFireTime;
  526.                                         m_lastStep = 0;
  527.                                 }
  528.                                 else
  529.                                 {
  530.                                         outShootTargetPos = (m_throwDir.IsZero()) ? pTarget->GetPos() : m_throwDir;
  531.                                 }
  532.                         }
  533.                         else
  534.                         {
  535.                                 // Let agent take aim first
  536.                                 outShootTargetPos = pTarget->GetPos();
  537.                                 state = eAIFS_Blocking;
  538.                         }
  539.                 }
  540.         }
  541.         else
  542.         {
  543.                 m_nextFireTime = 0.0f;
  544.         }
  545.  
  546.         return state;
  547. }
  548.  
  549. //
  550. //---------------------------------------------------------------------------------------------------------------
  551. EAIFireState CFireCommandLob::GetBestLob(IAIObject* pTarget, const AIWeaponDescriptor& descriptor, Vec3& outShootTargetPos)
  552. {
  553.         FUNCTION_PROFILER(gEnv->pSystem, PROFILE_GAME);
  554.  
  555.         assert(m_pShooter);
  556.         assert(pTarget);
  557.  
  558.         const Vec3 vCurrTargetPos = pTarget->GetPos();
  559.         const Vec3 vCurrShooterPos = m_pShooter->GetPos();
  560.         const Vec3 vCurrShooterFirePos = m_pShooter->GetFirePos();
  561.  
  562.         if (0 == m_lastStep)
  563.         {
  564.                 // First iteration, setup tests
  565.                 ClearDebugEvals();
  566.  
  567.                 // Calculate target offset.
  568.                 Vec3 targetDir2D(vCurrTargetPos - vCurrShooterPos);
  569.                 targetDir2D.z = 0.0f;
  570.                 /*
  571.                                                                      ^
  572.                    |targetRightDirection
  573.  
  574.                  |
  575.                  |
  576.                    shooter ---<distToTarget>------------------   ----target---- (parallelRadius)          -> targetDir2D
  577.                  |
  578.                  | perpendicularRadius
  579.                  */
  580.                 const float distScale = m_pShooter->GetParameters().m_fProjectileLaunchDistScale;
  581.                 const float distToTarget = targetDir2D.NormalizeSafe();
  582.                 const float inaccuracyRadius = distToTarget * gAIEnv.CVars.LobThrowPercentageOfDistanceToTargetUsedForInaccuracySimulation;
  583.  
  584.                 const float randomPercentageForPerpendicularRadius = gAIEnv.CVars.LobThrowSimulateRandomInaccuracy ? cry_random(0.0f, 1.0f) : 0.0f;
  585.                 float perpendicularRadius = -inaccuracyRadius + randomPercentageForPerpendicularRadius * (2 * inaccuracyRadius);
  586.  
  587.                 const float randomPercentageForParallelRadius = gAIEnv.CVars.LobThrowSimulateRandomInaccuracy ? cry_random(0.0f, 1.0f) : 0.0f;
  588.                 float parallelRadius = randomPercentageForParallelRadius * inaccuracyRadius + (1.0f - distScale) * distToTarget;
  589.  
  590.                 Vec3 targetRightDirection(-targetDir2D.y, targetDir2D.x, 0.0f);
  591.                 m_targetPos = vCurrTargetPos + targetRightDirection * perpendicularRadius - targetDir2D * parallelRadius;
  592.  
  593.                 const float minZOffsetForLob = (distToTarget > descriptor.closeDistance) ?
  594.                                                descriptor.preferredHeight : descriptor.preferredHeightForCloseDistance;
  595.                 m_preferredHeight = max(minZOffsetForLob, m_targetPos.z - vCurrShooterPos.z + minZOffsetForLob);
  596.  
  597.                 m_bestScore = -1.0f;
  598.         }
  599.  
  600.         // Flat target dir
  601.         Vec3 targetDir2D = m_targetPos - vCurrShooterPos;
  602.         targetDir2D.z = 0;
  603. #ifdef CRYAISYSTEM_DEBUG
  604.         m_Apex = vCurrShooterFirePos + (0.5 * targetDir2D);
  605. #endif
  606.         const float distToTarget = targetDir2D.NormalizeSafe();
  607.  
  608.         const float minimumDistanceToFriendsSq = sqr(descriptor.minimumDistanceFromFriends >= 0.0f ?
  609.                                                      descriptor.minimumDistanceFromFriends : gAIEnv.CVars.LobThrowMinAllowedDistanceFromFriends);
  610.  
  611.         const unsigned maxStepsPerUpdate = 1;
  612.         const unsigned maxSteps = 5;
  613.         for (unsigned iStep = 0; iStep < maxStepsPerUpdate && m_lastStep < maxSteps; ++iStep)
  614.         {
  615.                 const float u = (float)m_lastStep / (float)(maxSteps - 1) - 0.25f;
  616.                 const Vec3 fireDir = m_targetPos - vCurrShooterFirePos;
  617.                 const float x = targetDir2D.Dot(fireDir) - u * distToTarget * 0.25f;
  618.                 const float y = fireDir.z;
  619.                 const float h = max(1.0f, y + m_preferredHeight);
  620. #ifdef CRYAISYSTEM_DEBUG
  621.                 m_Apex.z += h;
  622. #endif
  623.                 const float g = descriptor.projectileGravity.z;
  624.  
  625.                 // Try good solution
  626.                 const float vy = sqrt_tpl(-h * g);
  627.                 const float det = sqr(vy) + 2 * g * y;
  628.                 if (det >= 0.0f)
  629.                 {
  630.                         const float tx = (-vy - sqrt_tpl(det)) / g;
  631.                         const float vx = x / tx;
  632.  
  633.                         Vec3 dir = targetDir2D * vx + Vec3(0, 0, vy);
  634.                         const float plannedLaunchSpeed = dir.NormalizeSafe();
  635.  
  636.                         Vec3 throwHitPos(ZERO);
  637.                         Vec3 throwHitDir(ZERO);
  638.                         float throwSpeed = 1.0f;
  639.                         Trajectory trajectory;
  640.                         const float score = EvaluateThrow(m_targetPos, pTarget->GetViewDir(), dir, plannedLaunchSpeed,
  641.                                                           throwHitPos, throwHitDir, throwSpeed, trajectory, descriptor.maxAcceptableDistanceFromTarget,
  642.                                                           minimumDistanceToFriendsSq);
  643.  
  644.                         if (score >= 0.0f && (score < m_bestScore || m_bestScore < 0.0f))
  645.                         {
  646.                                 const float throwDistance = Distance::Point_Point(vCurrShooterPos, throwHitPos);
  647.                                 m_throwDir = vCurrShooterPos + throwHitDir * throwDistance;
  648.                                 m_projectileSpeedScale = plannedLaunchSpeed / throwSpeed;
  649.                                 m_bestScore = score;
  650.                                 m_bestTrajectory = trajectory;
  651.                         }
  652.  
  653.                         ++m_lastStep;
  654.                 }
  655.         }
  656.  
  657.         if (m_lastStep >= maxSteps)
  658.         {
  659.                 if (m_bestScore <= 0.0f)
  660.                 {
  661.                         return eAIFS_Off;
  662.                 }
  663.                 else if (m_pShooter->CanAimWithoutObstruction(m_throwDir))
  664.                 {
  665. #ifdef CRYAISYSTEM_DEBUG
  666.                         m_debugBest = m_bestScore;
  667. #endif //CRYAISYSTEM_DEBUG
  668.  
  669.                         if (!outShootTargetPos.IsZero() || CanHaveZeroTargetPos())
  670.                         {
  671.                                 const Vec3& positionToLobTowards = m_throwDir;
  672.                                 outShootTargetPos = positionToLobTowards;
  673.  
  674.                                 Vec3 launchPosition = m_bestTrajectory.GetSample(0).position;
  675.                                 Vec3 launchVelocity = (positionToLobTowards - launchPosition).GetNormalized();
  676.  
  677.                                 // Step through the trajectory samples until we leave the
  678.                                 // critical zone (defined as "within 5 meters of the shooter").
  679.                                 // Once the projectile has left the critical zone we'll spawn the
  680.                                 // projectile with the sampled position and velocity.
  681.                                 // This eliminates most cases in which the grenade would hit the
  682.                                 // cover surface or a close wall, detonate, and kill the shooter.
  683.  
  684.                                 const Vec3& shooterPosition = m_pShooter->GetPos();
  685.  
  686.                                 for (size_t i = 0, n = m_bestTrajectory.GetSampleCount(); i < n; ++i)
  687.                                 {
  688.                                         const Trajectory::Sample& sample = m_bestTrajectory.GetSample(i);
  689.  
  690.                                         const float shooterToSampleDistanceSq = shooterPosition.GetSquaredDistance(sample.position);
  691.                                         const float criticalDistanceSq = square(descriptor.lobCriticalDistance);
  692.  
  693.                                         if (shooterToSampleDistanceSq > criticalDistanceSq)
  694.                                         {
  695.                                                 launchPosition = sample.position;
  696.                                                 launchVelocity = sample.velocity;
  697.                                                 break;
  698.                                         }
  699.                                 }
  700.  
  701.                                 // Pass this information along to the AI Proxy
  702.                                 m_pShooter->m_State.vLobLaunchPosition = launchPosition;
  703.                                 m_pShooter->m_State.vLobLaunchVelocity = launchVelocity;
  704.  
  705.                                 return eAIFS_On;
  706.                         }
  707.                         else
  708.                         {
  709.                                 outShootTargetPos.zero();
  710.                                 return eAIFS_Off;
  711.                         }
  712.                 }
  713.         }
  714.  
  715.         return eAIFS_Blocking;
  716. }
  717.  
  718. //
  719. //---------------------------------------------------------------------------------------------------------------
  720. float CFireCommandLob::EvaluateThrow(const Vec3& targetPos, const Vec3& targetViewDir, const Vec3& dir, float vel,
  721.                                      Vec3& outThrowHitPos, Vec3& outThrowHitDir, float& outSpeed,
  722.                                      Trajectory& trajectory, const float maxAllowedDistanceFromTarget,
  723.                                      const float minimumDistanceToFriendsSq) const
  724. {
  725.         FUNCTION_PROFILER(gEnv->pSystem, PROFILE_GAME);
  726.         CCCPOINT(CFireCommandLob_EvaluateThisThrow);
  727.  
  728.         IAIActorProxy* pPuppetProxy = m_pShooter->GetProxy();
  729.  
  730.         trajectory.sampleCount = trajectory.MaxSamples;
  731.  
  732.         outThrowHitPos.zero();
  733.         outThrowHitDir.zero();
  734.         const bool bUsingPrimaryWeapon = IsUsingPrimaryWeapon();
  735.         const ERequestedGrenadeType eReqGrenadeType = bUsingPrimaryWeapon ? eRGT_INVALID : m_pShooter->GetState().requestedGrenadeType;
  736.  
  737.         bool bPredicted = false;
  738.         if (bUsingPrimaryWeapon)
  739.         {
  740.                 outThrowHitDir = dir;
  741.                 bPredicted = pPuppetProxy->PredictProjectileHit(vel, outThrowHitPos, outThrowHitDir, outSpeed, &trajectory.positions[0], &trajectory.sampleCount, &trajectory.velocities[0]);
  742.         }
  743.         else
  744.         {
  745.                 bPredicted = pPuppetProxy->PredictProjectileHit(dir, vel, outThrowHitPos, outSpeed, eReqGrenadeType, &trajectory.positions[0], &trajectory.sampleCount, &trajectory.velocities[0]);
  746.                 outThrowHitDir = dir;
  747.         }
  748.  
  749.         float score = -1.0f;
  750.  
  751.         if (bPredicted && IsValidDestination(eReqGrenadeType, outThrowHitPos, minimumDistanceToFriendsSq))
  752.         {
  753.                 const Vec3& shooterPos = m_pShooter->GetPos();
  754.                 const Vec3 targetToHit = outThrowHitPos - targetPos;
  755.  
  756.                 // Prefer positions that are close to the target
  757.                 const float distanceSq = targetToHit.GetLengthSquared();
  758.                 const bool acceptThisThrow = maxAllowedDistanceFromTarget < 0 || distanceSq < sqr(maxAllowedDistanceFromTarget);
  759.                 if (acceptThisThrow)
  760.                         score = distanceSq;
  761.         }
  762.  
  763. #ifdef CRYAISYSTEM_DEBUG
  764.         m_DEBUG_evals.push_back(SDebugThrowEval());
  765.         SDebugThrowEval* pDebugEval = &m_DEBUG_evals.back();
  766.  
  767.         pDebugEval->score = 0.0f;
  768.         pDebugEval->fake = false;
  769.         pDebugEval->pos = outThrowHitPos;
  770.         pDebugEval->score = score;
  771.  
  772.         const size_t sampleCount = trajectory.GetSampleCount();
  773.         pDebugEval->trajectory.resize(sampleCount);
  774.         for (size_t i = 0; i < sampleCount; ++i)
  775.         {
  776.                 pDebugEval->trajectory[i] = trajectory.GetSample(i).position;
  777.         }
  778.  
  779. #endif //CRYAISYSTEM_DEBUG
  780.  
  781.         return score;
  782. }
  783.  
  784. //
  785. //---------------------------------------------------------------------------------------------------------------
  786. bool CFireCommandLob::IsValidDestination(ERequestedGrenadeType eReqGrenadeType, const Vec3& throwHitPos,
  787.                                          const float minimumDistanceToFriendsSq) const
  788. {
  789.         bool bValid = true;
  790.  
  791.         // no friends proximity checks for smoke grenades
  792.         if (eRGT_SMOKE_GRENADE != eReqGrenadeType)
  793.         {
  794.                 // make sure not to throw grenade near NOGRENADE_SPOT
  795.                 AutoAIObjectIter itAnchors(gAIEnv.pAIObjectManager->GetFirstAIObject(OBJFILTER_TYPE, AIANCHOR_NOGRENADE_SPOT));
  796.                 IAIObject* pAvoidAnchor = itAnchors->GetObject();
  797.                 while (bValid && (pAvoidAnchor != NULL))
  798.                 {
  799.                         if (pAvoidAnchor->IsEnabled())
  800.                         {
  801.                                 float avoidDistSq(pAvoidAnchor->GetRadius());
  802.                                 avoidDistSq *= avoidDistSq;
  803.  
  804.                                 const float checkDistance = Distance::Point_PointSq(throwHitPos, pAvoidAnchor->GetPos());
  805.                                 bValid = (checkDistance >= avoidDistSq);
  806.                         }
  807.  
  808.                         // Advance
  809.                         itAnchors->Next();
  810.                         pAvoidAnchor = itAnchors->GetObject();
  811.                 }
  812.  
  813.                 // Check friendly distance
  814.                 const float timePrediction = gAIEnv.CVars.LobThrowTimePredictionForFriendPositions;
  815.                 AutoAIObjectIter itFriend(gAIEnv.pAIObjectManager->GetFirstAIObject(OBJFILTER_FACTION, m_pShooter->GetFactionID()));
  816.                 IAIObject* pFriend = itFriend->GetObject();
  817.                 while (bValid && (pFriend != NULL))
  818.                 {
  819.                         if (pFriend->IsEnabled())
  820.                         {
  821.                                 Vec3 friendPositionToEvaluate = pFriend->GetPos();
  822.                                 if (CPipeUser* pPipeUser = CastToCPipeUserSafe(pFriend))
  823.                                 {
  824.                                         const Vec3& moveDir = pPipeUser->GetMoveDir();
  825.                                         if (!moveDir.IsZero())
  826.                                         {
  827.                                                 friendPositionToEvaluate += moveDir * timePrediction;
  828.                                         }
  829.                                 }
  830.  
  831.                                 const float checkDistanceSq = Distance::Point_PointSq(throwHitPos, friendPositionToEvaluate);
  832.                                 bValid = (checkDistanceSq >= minimumDistanceToFriendsSq);
  833.                         }
  834.  
  835.                         // Advance
  836.                         itFriend->Next();
  837.                         pFriend = itFriend->GetObject();
  838.                 }
  839.         }
  840.  
  841.         return bValid;
  842. }
  843.  
  844. //
  845. //---------------------------------------------------------------------------------------------------------------
  846. void CFireCommandLob::DebugDraw()
  847. {
  848. #ifdef CRYAISYSTEM_DEBUG
  849.         CDebugDrawContext dc;
  850.  
  851.         const ColorB colWhite(255, 255, 255);
  852.         const ColorB colRed(255, 0, 0);
  853.         const ColorB colGreen(0, 255, 0);
  854.  
  855.         TDebugEvals::const_iterator itDebug = m_DEBUG_evals.begin();
  856.         TDebugEvals::const_iterator itDebugEnd = m_DEBUG_evals.end();
  857.         for (; itDebug != itDebugEnd; ++itDebug)
  858.         {
  859.                 const SDebugThrowEval& eval = *itDebug;
  860.                 const bool bBest = (m_debugBest >= 0.0f && eval.score == m_debugBest);
  861.  
  862.                 dc->DrawSphere(eval.pos, 0.2f, bBest ? colGreen : colRed);
  863.                 dc->Draw3dLabel(eval.pos, bBest ? 1.2f : 0.8f, "%.1f%s", eval.score, bBest ? " [BEST]" : "");
  864.                 dc->DrawPolyline(&eval.trajectory[0], eval.trajectory.size(), false, eval.fake ? colRed : colWhite, bBest ? 2.0f : 1.25f);
  865.         }
  866.         dc->DrawSphere(m_Apex, 0.2f, Col_Black);
  867. #endif //CRYAISYSTEM_DEBUG
  868. }
  869.  
  870. float CFireCommandLob::GetTimeToNextShot() const
  871. {
  872.         return 0.0f;
  873. }
  874.  
  875. bool CFireCommandLob::GetOverrideAimingPosition(Vec3& overrideAimingPosition) const
  876. {
  877.         if (!m_throwDir.IsZero())
  878.         {
  879.                 overrideAimingPosition = m_throwDir;
  880.                 return true;
  881.         }
  882.         return false;
  883. }
  884.  
  885. //====================================================================
  886. // CFireCommandProjectileSlow
  887. //====================================================================
  888. CFireCommandProjectileSlow::CFireCommandProjectileSlow(IAIActor* pShooter) : CFireCommandLob(pShooter)
  889. {
  890.  
  891. }
  892.  
  893. //====================================================================
  894. // CFireCommandProjectileFast
  895. //====================================================================
  896. CFireCommandProjectileFast::CFireCommandProjectileFast(IAIActor* pShooter)
  897.         : m_pShooter(((CAIActor*)pShooter)->CastToCPuppet())
  898.         , m_aimPos(ZERO)
  899.         , m_trackingId(0)
  900. {
  901. }
  902.  
  903. //
  904. //---------------------------------------------------------------------------------------------------------------
  905. void CFireCommandProjectileFast::Reset()
  906. {
  907.         m_trackingId = 0;
  908. }
  909.  
  910. //
  911. //---------------------------------------------------------------------------------------------------------------
  912. EAIFireState CFireCommandProjectileFast::Update(IAIObject* pTarget, bool canFire, EFireMode fireMode, const AIWeaponDescriptor& descriptor, Vec3& outShootTargetPos)
  913. {
  914.         SAIWeaponInfo weaponInfo;
  915.         m_pShooter->GetProxy()->QueryWeaponInfo(weaponInfo);
  916.  
  917.         EAIFireState state = eAIFS_Off;
  918.  
  919.         if (canFire && pTarget && !weaponInfo.shotIsDone && m_pShooter->IsAllowedToHitTarget())
  920.         {
  921.                 const EAimState aim = m_pShooter->GetAimState();
  922.                 const bool bValidAim = (aim == AI_AIM_READY || aim == AI_AIM_FORCED);
  923.  
  924.                 if (bValidAim)
  925.                 {
  926.                         const Vec3& vTargetPos = pTarget->GetPos();
  927.                         const Vec3& vTargetVel = pTarget->GetVelocity();
  928.                         const float aimAheadTime(0.5f);
  929.  
  930.                         // Set the general aim position
  931.                         m_aimPos = vTargetPos + vTargetVel * aimAheadTime;
  932.  
  933.                         if (fireMode == FIREMODE_FORCED)
  934.                         {
  935.                                 ChooseShootPoint(outShootTargetPos, pTarget, descriptor.fDamageRadius, 0.4f, CFireCommandProjectileFast::AIM_INFRONT);
  936.                                 state = eAIFS_On;
  937.                         }
  938.                         else
  939.                         {
  940.                                 // Try different aim points, prefer front points if possible
  941.                                 bool bValidShootPoint = false;
  942.                                 bValidShootPoint = bValidShootPoint || ChooseShootPoint(outShootTargetPos, pTarget, descriptor.fDamageRadius, 0.4f, CFireCommandProjectileFast::AIM_INFRONT);
  943.                                 bValidShootPoint = bValidShootPoint || ChooseShootPoint(outShootTargetPos, pTarget, descriptor.fDamageRadius, 0.8f, CFireCommandProjectileFast::AIM_SIDES);
  944.                                 bValidShootPoint = bValidShootPoint || ChooseShootPoint(outShootTargetPos, pTarget, descriptor.fDamageRadius, 0.8f, CFireCommandProjectileFast::AIM_BACK);
  945.  
  946.                                 state = (bValidShootPoint ? eAIFS_On : eAIFS_Off);
  947.                         }
  948.                 }
  949.                 else
  950.                 {
  951.                         // Let agent take aim first
  952.                         outShootTargetPos = pTarget->GetPos();
  953.                         state = eAIFS_Blocking;
  954.                 }
  955.         }
  956.  
  957.         return state;
  958. }
  959.  
  960. //
  961. //---------------------------------------------------------------------------------------------------------------
  962. bool CFireCommandProjectileFast::ChooseShootPoint(Vec3& outShootPoint, IAIObject* pTarget, float explRadius, float missRatio, CFireCommandProjectileFast::EAimMode aimMode)
  963. {
  964.         assert(m_pShooter);
  965.         assert(pTarget);
  966.  
  967.         outShootPoint.zero();
  968.         Vec3 shootAtPos = m_aimPos;
  969.         float fAccuracy = 1.0f;
  970.  
  971.         if (m_trackingId != 0)
  972.         {
  973.                 aimMode = AIM_DIRECTHIT;
  974.         }
  975.         else
  976.         {
  977.                 const bool bCanDamageTarget = (m_pShooter->GetAttentionTarget() == pTarget ? m_pShooter->CanDamageTarget() : true);
  978.                 fAccuracy = (bCanDamageTarget ? m_pShooter->GetAccuracy(static_cast<CAIObject*>(pTarget)) : 0.f);
  979.                 if (cry_random(0.0f, 1.0f) <= fAccuracy)
  980.                         aimMode = AIM_DIRECTHIT;
  981.         }
  982.  
  983.         // Deal with eye-height for aiming at feed
  984.         if (AIM_INFRONT == aimMode && AIOBJECT_VEHICLE != static_cast<CAIObject*>(pTarget)->GetType())
  985.         {
  986.                 CAIActor* pTargetActor(CastToCAIActorSafe(pTarget));
  987.                 if (pTargetActor)
  988.                 {
  989.                         const SAIBodyInfo& bodyInfo = pTargetActor->GetBodyInfo();
  990.                         shootAtPos.z -= bodyInfo.stanceSize.GetSize().z;
  991.                 }
  992.         }
  993.         else if (AIM_DIRECTHIT == aimMode)
  994.         {
  995.                 shootAtPos = pTarget->GetPos();
  996.                 m_trackingId = pTarget->GetEntityID();
  997.         }
  998.         else
  999.         {
  1000.                 Vec3 targetForward2D(pTarget->GetEntityDir());
  1001.                 targetForward2D.z = 0.0f;
  1002.  
  1003.                 // if target looks down - use direction to shooter as forward
  1004.                 if (targetForward2D.IsZero(.07f))
  1005.                 {
  1006.                         targetForward2D = m_pShooter->GetPos() - pTarget->GetPos();
  1007.                         targetForward2D.z = 0.0f;
  1008.                 }
  1009.  
  1010.                 targetForward2D.NormalizeSafe(Vec3Constants<float>::fVec3_OneY);
  1011.  
  1012.                 const float shotMissOffset = explRadius * missRatio * (1.0f - fAccuracy);
  1013.                 const Vec3 shootDir(-targetForward2D.y, targetForward2D.x, 0.0f);
  1014.                 switch (aimMode)
  1015.                 {
  1016.                 case AIM_INFRONT:
  1017.                         {
  1018.                                 const float leftRightOffset = cry_random(-0.2f, 0.2f);
  1019.                                 shootAtPos += targetForward2D * shotMissOffset + shootDir * shotMissOffset * leftRightOffset;
  1020.                         }
  1021.                         break;
  1022.  
  1023.                 case AIM_SIDES:
  1024.                         {
  1025.                                 const float leftRightOffset = cry_random(0.5f, 1.0f) * (cry_random(0, 1) == 0 ? 0.4f : -0.4f);
  1026.                                 shootAtPos += targetForward2D * shotMissOffset * 0.1f + shootDir * shotMissOffset * leftRightOffset;
  1027.                         }
  1028.                         break;
  1029.  
  1030.                 case AIM_BACK:
  1031.                         {
  1032.                                 const float leftRightOffset = cry_random(0.5f, 1.0f) * (cry_random(0, 1) == 0 ? 0.1f : -0.1f);
  1033.                                 shootAtPos += -targetForward2D * shotMissOffset + shootDir * shotMissOffset * leftRightOffset;
  1034.                         }
  1035.                         break;
  1036.  
  1037.                 default:
  1038.                         CRY_ASSERT_MESSAGE(false, "CFireCommandProjectileFast::ChooseShootPoint Unhandled Aim Mode");
  1039.                 }
  1040.         }
  1041.  
  1042.         // Use floor position if possible
  1043.         const bool bHasFloorPos = GetFloorPos(outShootPoint, shootAtPos, WalkabilityFloorUpDist, WalkabilityFloorDownDist, WalkabilityDownRadius, AICE_STATIC);
  1044.         if (bHasFloorPos)
  1045.                 outShootPoint.z += 0.5f;
  1046.         else
  1047.                 outShootPoint = shootAtPos;
  1048.  
  1049.         // Validate the final position
  1050.         const bool bValid = IsValidShootPoint(m_pShooter->GetFirePos(), outShootPoint, explRadius);
  1051.         return bValid;
  1052. }
  1053.  
  1054. //
  1055. //---------------------------------------------------------------------------------------------------------------
  1056. void CFireCommandProjectileFast::OnReload()
  1057. {
  1058.         m_trackingId = 0;
  1059. }
  1060.  
  1061. //
  1062. //---------------------------------------------------------------------------------------------------------------
  1063. bool CFireCommandProjectileFast::IsValidShootPoint(const Vec3& firePos, const Vec3& shootPoint, float explRadius) const
  1064. {
  1065.         bool bResult = false;
  1066.  
  1067.         const Vec3 vFireDir = (shootPoint - firePos);
  1068.         const Vec3 vTargetPos = firePos + vFireDir;
  1069.         if (m_pShooter->CanAimWithoutObstruction(vTargetPos))
  1070.         {
  1071.                 // Check for friendlies in the area
  1072.                 bResult = NoFriendNearAimTarget(explRadius, shootPoint);
  1073.         }
  1074.  
  1075.         return bResult;
  1076. }
  1077.  
  1078. //
  1079. //---------------------------------------------------------------------------------------------------------------
  1080. bool CFireCommandProjectileFast::NoFriendNearAimTarget(float explRadius, const Vec3& shootPoint) const
  1081. {
  1082.         assert(m_pShooter);
  1083.  
  1084.         bool bValid = true;
  1085.         const float minAllowedDistanceForFriendsSq = sqr(1.5f * explRadius);
  1086.  
  1087.         AutoAIObjectIter itFriend(gAIEnv.pAIObjectManager->GetFirstAIObject(OBJFILTER_FACTION, m_pShooter->GetFactionID()));
  1088.         IAIObject* pFriend = itFriend->GetObject();
  1089.         while (bValid && (pFriend != NULL))
  1090.         {
  1091.                 if (pFriend->IsEnabled())
  1092.                 {
  1093.                         const float distanceSq = Distance::Point_PointSq(shootPoint, pFriend->GetPos());
  1094.                         bValid = (distanceSq >= minAllowedDistanceForFriendsSq);
  1095.                 }
  1096.  
  1097.                 // Advance
  1098.                 itFriend->Next();
  1099.                 pFriend = itFriend->GetObject();
  1100.         }
  1101.  
  1102.         return bValid;
  1103. }
  1104.  
  1105. //
  1106. //---------------------------------------------------------------------------------------------------------------
  1107. void CFireCommandProjectileFast::DebugDraw()
  1108. {
  1109.         if (m_pShooter)
  1110.         {
  1111.                 CDebugDrawContext dc;
  1112.                 const ColorB color(255, 255, 255, 128);
  1113.                 dc->DrawLine(m_pShooter->GetFirePos() + Vec3(0, 0, 0.25f), color, m_aimPos + Vec3(0, 0, 0.25f), color);
  1114.         }
  1115. }
  1116.  
  1117. float CFireCommandProjectileFast::GetTimeToNextShot() const
  1118. {
  1119.         return 0.0f;
  1120. }
  1121.  
  1122. #if 0
  1123. // deprecated and won't compile at all...
  1124.  
  1125. //====================================================================
  1126. // CFireCommandStrafing
  1127. //====================================================================
  1128. CFireCommandStrafing::CFireCommandStrafing(IAIActor* pShooter) :
  1129.         m_pShooter(((CAIActor*)pShooter)->CastToCPuppet())
  1130. {
  1131.         CTimeValue fCurrentTime = GetAISystem()->GetFrameStartTime();
  1132.         m_fLastStrafingTime = fCurrentTime;
  1133.         m_fLastUpdateTime = fCurrentTime;
  1134.         m_StrafingCounter = 0;
  1135. }
  1136.  
  1137. //
  1138. //
  1139. //
  1140. //----------------------------------------------------------------------------------------------------------------
  1141. void CFireCommandStrafing::Reset()
  1142. {
  1143.         AIAssert(m_pShooter);
  1144.         CTimeValue fCurrentTime = GetAISystem()->GetFrameStartTime();
  1145.         m_fLastStrafingTime = fCurrentTime;
  1146.         m_fLastUpdateTime = fCurrentTime;
  1147.         m_StrafingCounter = 0;
  1148. }
  1149.  
  1150. //
  1151. //
  1152. //
  1153. //----------------------------------------------------------------------------------------------------------------
  1154. bool CFireCommandStrafing::ManageFireDirStrafing(IAIObject* pTarget, Vec3& vTargetPos, bool& fire, const AIWeaponDescriptor& descriptor)
  1155. {
  1156.         fire = false;
  1157.  
  1158.         const AgentParameters& params = m_pShooter->GetParameters();
  1159.  
  1160.         CPuppet* pShooterPuppet = m_pShooter->CastToCPuppet();
  1161.         if (!pShooterPuppet)
  1162.                 return false;
  1163.  
  1164.         if (!m_pShooter->GetProxy())
  1165.                 return false;
  1166.  
  1167.         const SAIBodyInfo& bodyInfo = pShooterPuppet->GetBodyInfo();
  1168.  
  1169.         bool strafeLoop(false);
  1170.         int maxStrafing = (int)params.m_fStrafingPitch;
  1171.         if (maxStrafing == 0)
  1172.                 maxStrafing = 1;
  1173.  
  1174.         if (maxStrafing < 0)
  1175.         {
  1176.                 maxStrafing = -maxStrafing;
  1177.                 strafeLoop = true;
  1178.                 if (maxStrafing * 2 <= m_StrafingCounter)
  1179.                         m_StrafingCounter = 0;
  1180.         }
  1181.  
  1182.         Vec3 vActualFireDir = bodyInfo.vFireDir;
  1183.         if (m_StrafingCounter == 0)
  1184.         {
  1185.                 CTimeValue fCurrentTime = GetAISystem()->GetFrameStartTime();
  1186.                 m_fLastStrafingTime = fCurrentTime;
  1187.                 m_fLastUpdateTime = fCurrentTime;
  1188.                 m_StrafingCounter++;
  1189.         }
  1190.         if (strafeLoop || maxStrafing * 2 > m_StrafingCounter)
  1191.         {
  1192.  
  1193.                 CTimeValue fCurrentTime = GetAISystem()->GetFrameStartTime();
  1194.                 m_fLastUpdateTime = fCurrentTime;
  1195.  
  1196.                 // { t : (X-C)N=0,X=P+tV,V=N } <-> t=(C-P)N
  1197.  
  1198.                 Vec3 N, C, P, X, V, V2;
  1199.                 float t;
  1200.                 //              float d,s;
  1201.  
  1202.                 N = Vec3(0.0, 0.0, 1.0f);
  1203.                 C = vTargetPos - Vec3(0.0f, 0.0f, 0.3f);
  1204.                 P = m_pShooter->GetFirePos();
  1205.                 V = m_pShooter->GetVelocity();
  1206.                 V2 = pTarget->GetVelocity();
  1207.                 P += V2 * 2.0f;
  1208.                 //              d = (C-P).GetLength();
  1209.                 t = (C - P).Dot(N);
  1210.  
  1211.                 if (fabs(t) > 0.01f)  //means if we have enough distance to the target.
  1212.                 {
  1213.                         X = N;
  1214.                         X.SetLength(t);
  1215.                         X += P;
  1216.  
  1217.                         Vec3 vStrafingDirUnit = X - C;
  1218.                         float fStrafingLen = vStrafingDirUnit.GetLength();
  1219.                         Limit(fStrafingLen, 1.0f, 30.0f);
  1220.  
  1221.                         //                      float r = (float)m_StrafingCounter /(float)maxStrafing;
  1222.  
  1223.                         float fStrafingOffset = ((float)(maxStrafing - m_StrafingCounter)) * fStrafingLen / (float)maxStrafing;
  1224.                         if (fStrafingOffset < 0)
  1225.                                 fStrafingOffset = 0.0f;
  1226.  
  1227.                         vTargetPos = vStrafingDirUnit;
  1228.                         vTargetPos.SetLength(fStrafingOffset);
  1229.                         vTargetPos += C;
  1230.  
  1231.                         Vec3 vShootDirection = vTargetPos - P;
  1232.                         vShootDirection.NormalizeSafe();
  1233.  
  1234.                         float dotUp = 1.0f;
  1235.                         float tempSolution = 30.0f;
  1236.                         if (pShooterPuppet->GetSubType() == CAIObject::STP_2D_FLY)
  1237.                                 tempSolution = 60.0f;
  1238.  
  1239.                         if (bodyInfo.linkedVehicleEntity && bodyInfo.linkedVehicleEntity->HasAI())
  1240.                         {
  1241.                                 Matrix33 wm(bodyInfo.linkedVehicleEntity->GetWorldTM());
  1242.                                 Vec3 vUp = wm.GetColumn(2);
  1243.                                 //float dotUp = vUp.Dot( Vec3(0.0f,0.0f,1.0f) );
  1244.                                 //i hope this version is correct [MM]
  1245.                                 dotUp = vUp.Dot(Vec3(0.0f, 0.0f, 1.0f));
  1246.                         }
  1247.                         /*
  1248.                               {
  1249.                                 GetAISystem()->AddDebugLine(m_pShooter->GetFirePos(), vTargetPos, 0, 0, 255, 0.1f);
  1250.                               }
  1251.                          */
  1252.                         if (pShooterPuppet->GetSubType() == CAIObject::STP_2D_FLY)
  1253.                         {
  1254.                         }
  1255.                         else
  1256.                         {
  1257.                                 pShooterPuppet->m_State.vAimTargetPos = vTargetPos;
  1258.                         }
  1259.  
  1260.                         bool rejected = false;
  1261.                         if (dotUp > cos_tpl(DEG2RAD(tempSolution)))
  1262.                         {
  1263.                                 float dot = vShootDirection.Dot(vActualFireDir);
  1264.  
  1265.                                 if (dot > cos_tpl(DEG2RAD(tempSolution)))
  1266.                                 {
  1267.                                         if (pShooterPuppet->GetSubType() == CAIObject::STP_2D_FLY)
  1268.                                         {
  1269.                                                 if (pShooterPuppet->CheckAndAdjustFireTarget(vTargetPos, descriptor.spreadRadius, vTargetPos, -1, -1))
  1270.                                                         fire = true;
  1271.                                                 else
  1272.                                                         rejected = true;
  1273.                                         }
  1274.                                         else
  1275.                                         {
  1276.                                                 if (pShooterPuppet->CheckAndAdjustFireTarget(vTargetPos, descriptor.spreadRadius, vTargetPos, -1, -1))
  1277.                                                 {
  1278.                                                         fire = true;
  1279.                                                 }
  1280.                                                 else
  1281.                                                         rejected = true;
  1282.                                         }
  1283.                                 }
  1284.                         }
  1285.                         /*
  1286.                               if ( fire== true )
  1287.                               {
  1288.                                 Vec3 v1 = m_pShooter->GetFirePos();
  1289.                                 GetAISystem()->AddDebugLine(v1, vTargetPos, 255, 255, 255, 0.1f);
  1290.                                 Vec3 v2 =vActualFireDir * 100.0f;
  1291.                                 GetAISystem()->AddDebugLine(v1, v1 + v2, 255, 0, 0, 0.1f);
  1292.                               }
  1293.                          */
  1294.                         if (rejected == true)
  1295.                         {
  1296.                                 if ((fCurrentTime - m_fLastStrafingTime).GetSeconds() > 0.8f)
  1297.                                 {
  1298.                                         m_fLastStrafingTime = fCurrentTime;
  1299.                                         m_StrafingCounter++;
  1300.                                 }
  1301.                         }
  1302.                         if ((fCurrentTime - m_fLastStrafingTime).GetSeconds() > 0.08f)
  1303.                         {
  1304.                                 m_fLastStrafingTime = fCurrentTime;
  1305.                                 m_StrafingCounter++;
  1306.                         }
  1307.                 }
  1308.         }
  1309.         return false;
  1310. }
  1311.  
  1312. //
  1313. //
  1314. //
  1315. //----------------------------------------------------------------------------------------------------------------
  1316. EAIFireState CFireCommandStrafing::Update(IAIObject* pTargetSrc, bool canFire, EFireMode fireMode, const AIWeaponDescriptor& descriptor, Vec3& outShootTargetPos)
  1317. {
  1318.         AIAssert(m_pShooter);
  1319.         AIAssert(GetAISystem());
  1320.  
  1321.         if (!canFire)
  1322.         {
  1323.                 Reset();
  1324.                 return eAIFS_Off;
  1325.         }
  1326.  
  1327.         if (!pTargetSrc)
  1328.         {
  1329.                 Reset();
  1330.                 return eAIFS_Off;
  1331.         }
  1332.  
  1333.         CPuppet* pShooterPuppet = m_pShooter->CastToCPuppet();
  1334.         if (!pShooterPuppet)
  1335.         {
  1336.                 Reset();
  1337.                 return eAIFS_Off;
  1338.         }
  1339.  
  1340.         CAIObject* pTarget = (CAIObject*)pTargetSrc;
  1341.  
  1342.         CAIObject* pAssoc = pTarget->GetAssociation().GetAIObject();
  1343.         if (pAssoc)
  1344.                 pTarget = pAssoc;
  1345.  
  1346.         Vec3 vTargetPos = pTarget->GetPos();
  1347.  
  1348.         int targetType = pTarget->GetType();
  1349.         if (targetType == AIOBJECT_VEHICLE)
  1350.         {
  1351.                 EntityId driverID = pTarget->GetProxy()->GetLinkedDriverEntityId();
  1352.  
  1353.                 if (driverID)
  1354.                 {
  1355.                         if (IEntity* entity = gEnv->pEntitySystem->GetEntity(driverID))
  1356.                         {
  1357.                                 if (entity->HasAI())
  1358.                                 {
  1359.                                         pTarget = (CAIObject*)entity->GetAI();
  1360.                                         vTargetPos = pTarget->GetPos();
  1361.                                         vTargetPos.z -= 2.0f;
  1362.                                 }
  1363.                         }
  1364.                 }
  1365.         }
  1366.  
  1367.         bool fire = false;
  1368.  
  1369.         ManageFireDirStrafing(pTarget, vTargetPos, fire, descriptor);
  1370.         outShootTargetPos = vTargetPos;
  1371.  
  1372.         return (fire ? eAIFS_On : eAIFS_Off);
  1373. }
  1374.  
  1375. float CFireCommandStrafing::GetTimeToNextShot() const
  1376. {
  1377.         return 0.0f;
  1378. }
  1379. //====================================================================
  1380. // CFireCommandFastLightMOAR
  1381. //====================================================================
  1382. CFireCommandFastLightMOAR::CFireCommandFastLightMOAR(IAIActor* pShooter) :
  1383.         m_pShooter((CAIActor*)pShooter)
  1384. {
  1385. }
  1386.  
  1387. void CFireCommandFastLightMOAR::Reset()
  1388. {
  1389.         m_startTime = GetAISystem()->GetFrameStartTime();
  1390.         m_startFiring = false;
  1391. }
  1392.  
  1393. //
  1394. //
  1395. //
  1396. //----------------------------------------------------------------------------------------------------------------
  1397. EAIFireState CFireCommandFastLightMOAR::Update(IAIObject* pTarget, bool canFire, EFireMode fireMode, const AIWeaponDescriptor& descriptor, Vec3& outShootTargetPos)
  1398. {
  1399.  
  1400.         AIAssert(m_pShooter);
  1401.         AIAssert(GetAISystem());
  1402.  
  1403.         if (!pTarget)
  1404.                 return eAIFS_Off;
  1405.  
  1406.         const float chargeTime = descriptor.fChargeTime;
  1407.         float drawTime = descriptor.drawTime;
  1408.  
  1409.         float dt = GetAISystem()->GetFrameDeltaTime();
  1410.         float elapsedTime = (GetAISystem()->GetFrameStartTime() - m_startTime).GetSeconds();
  1411.         Vec3 targetPos(pTarget->GetPos());
  1412.         Vec3 dirToTarget(targetPos - m_pShooter->GetFirePos());
  1413.  
  1414.         float distToTarget = dirToTarget.GetLength();
  1415.         float sightRange2 = m_pShooter->GetParameters().m_PerceptionParams.sightRange / 2;
  1416.         if (sightRange2 > 0 && distToTarget > sightRange2)
  1417.                 drawTime *= 1 + (distToTarget - sightRange2) / sightRange2;
  1418.         // The moment it is
  1419.         if (canFire && !m_startFiring)
  1420.         {
  1421.                 m_laggedTarget = m_pShooter->GetFirePos() + m_pShooter->GetViewDir() * distToTarget;
  1422.                 m_startFiring = true;
  1423.                 m_startDist = distToTarget;
  1424.                 m_rand.set(cry_random(-1.0f, 1.0f), cry_random(-1.0f, 1.0f));
  1425.         }
  1426.  
  1427.         if (m_startFiring)
  1428.         {
  1429.                 float f = min(dt * 2.0f, 1.0f);
  1430.                 m_laggedTarget += (targetPos - m_laggedTarget) * f;
  1431.  
  1432.                 float t = 0;
  1433.  
  1434.                 if (elapsedTime < chargeTime)
  1435.                 {
  1436.                         // Wait until the weapon has charged
  1437.                         t = 0;
  1438.                 }
  1439.                 else if (elapsedTime < chargeTime + drawTime)
  1440.                 {
  1441.                         t = ((elapsedTime - chargeTime) / drawTime);
  1442.                 }
  1443.                 else
  1444.                 {
  1445.                         t = 1.0f;
  1446.                 }
  1447.  
  1448.                 /*
  1449.                    // Spiral draw fire.
  1450.                    Matrix33     basis;
  1451.                    basis.SetRotationVDir(dirToTarget.GetNormalizedSafe());
  1452.                    // Wobbly offset
  1453.                    float        oa = sinf(cosf(t * gf_PI * 33.321f) * gf_PI + t * gf_PI * 45.0f) * cosf(t * gf_PI * 13.1313f) + cosf(t * gf_PI * 6.1313f) * cosf(t * gf_PI * 4.1313f);
  1454.                    float        or = cosf(sinf(t * gf_PI * 22.521f) * gf_PI + t * gf_PI * 64.1f) * sinf(t * gf_PI * 9.1413f) + cosf(t * gf_PI * 7.3313f) * sinf(t * gf_PI * 3.6313f);
  1455.  
  1456.                    float        ang = t * gf_PI * 4.0f + oa * DEG2RAD(4.0f);
  1457.                    float        rad = (sqrtf(1.0f - t) * 6.0f) * (0.9f + or * 0.2f);
  1458.  
  1459.                    Vec3 offset(sinf(ang) * rad, 0, -cosf(ang) * rad);
  1460.  
  1461.                    outShootTargetPos = m_laggedTarget + basis * offset;
  1462.                  */
  1463.  
  1464.                 // Line draw fire.
  1465.                 Vec3 dir = m_laggedTarget - m_pShooter->GetFirePos();
  1466.                 //              dir.z = 0;
  1467.                 float dist = dir.GetLength();
  1468.                 if (dist > 0.0f)
  1469.                         dir /= dist;
  1470.  
  1471.                 Matrix33 basis;
  1472.                 basis.SetRotationVDir(dir);
  1473.  
  1474.                 const float drawLen = 20.0f;
  1475.                 float minDist = dist - drawLen;
  1476.                 if (minDist < m_startDist * 0.5f) minDist = m_startDist * 0.5f;
  1477.  
  1478.                 //              float   startHeight = ((minDist - dist) / drawLen) * drawLen / 5.0f; //(minDist - dist) / (dist - minDist) * (drawLen / 3.0f);
  1479.  
  1480.                 //float a = (sinf(t * gf_PI * 3.321f + m_rand.x * 0.23424f) + sinf(t * gf_PI * 17.321f + m_rand.y * 0.433221) * 0.2f) / 1.2f;
  1481.                 float a = (t < 1 ? sinf((descriptor.sweepFrequency * t + m_rand.x) * gf_PI) * descriptor.sweepWidth * (1 - t * t) : 0);
  1482.                 Vec3 h;
  1483.                 h.x = a;//cosf(gf_PI/2 + a/2 * gf_PI/2) * startHeight;
  1484.                 h.y = 0;
  1485.                 h.z = (t - 1) * (2 + distToTarget / max(sightRange2, 2.f));//m_startDist/(2.f*max(distToTarget,0.01f)) ;//sinf(gf_PI/2 + a/2 * gf_PI/2) * startHeight;
  1486.                 h = h * basis;
  1487.  
  1488.                 Vec3 start = m_laggedTarget + dir * (minDist - dist) + h;  //basis.GetRow(2) * startHeight;
  1489.                 Vec3 end = m_laggedTarget;
  1490.  
  1491.                 GetAISystem()->AddDebugLine(m_laggedTarget + dir * (minDist - dist), m_laggedTarget, 0, 0, 0, 0.1f);
  1492.  
  1493.                 GetAISystem()->AddDebugLine(start, end, 255, 255, 255, 0.1f);
  1494.  
  1495.                 Vec3 shoot = start + (end - start) * t * t;
  1496.                 GetAISystem()->AddDebugLine(shoot, shoot + basis.GetRow(2), 255, 0, 0, 0.1f);
  1497.  
  1498.                 Vec3 wob;
  1499.                 wob.x = sinf(t * gf_PI * 4.321f + m_rand.x) + cosf(t * gf_PI * 15.321f + m_rand.y * 0.433221f) * 0.2f;
  1500.                 wob.y = 0;
  1501.                 wob.z = 0;//cosf(t * gf_PI * 3.231415f + m_rand.y) + sinf(t * gf_PI * 16.321f + m_rand.x * 0.333221) * 0.2f;
  1502.                 wob = wob * basis;
  1503.  
  1504.                 GetAISystem()->AddDebugLine(shoot, shoot + wob, 255, 0, 0, 0.1f);
  1505.  
  1506.                 outShootTargetPos = shoot + wob * 0.5f * sqrtf(1 - t);
  1507.  
  1508.                 //              float   wobble = sinf(cosf(t * gf_PI * 33.321f) * gf_PI + t * gf_PI * 45.0f) * cosf(t * gf_PI * 13.1313f) + cosf(t * gf_PI * 6.1313f) * cosf(t * gf_PI * 4.1313f);
  1509.  
  1510.                 /*              Matrix33        basis;
  1511.                     basis.SetRotationVDir(dirToTarget.GetNormalizedSafe());
  1512.  
  1513.                     Vec3        wob;
  1514.                     wob.x = sinf(cosf(t * gf_PI * 33.321f) * gf_PI + t * gf_PI * 45.0f) * cosf(t * gf_PI * 13.1313f) + cosf(t * gf_PI * 6.1313f) * cosf(t * gf_PI * 4.1313f);
  1515.                     wob.y = 0;
  1516.                     wob.z = cosf(sinf(t * gf_PI * 22.521f) * gf_PI + t * gf_PI * 64.1f) * sinf(t * gf_PI * 9.1413f) + cosf(t * gf_PI * 7.3313f) * sinf(t * gf_PI * 3.6313f);
  1517.  
  1518.                     Vec3        pos = m_pShooter->GetFirePos();
  1519.                     pos.z = m_laggedTarget.z;
  1520.  
  1521.                     outShootTargetPos = m_laggedTarget + (advance * dir); // + basis * (wob * 0.2f);*/
  1522.         }
  1523.  
  1524.         return (canFire ? eAIFS_On : eAIFS_Off);
  1525. }
  1526.  
  1527. float CFireCommandFastLightMOAR::GetTimeToNextShot() const
  1528. {
  1529.         return 0.0f;
  1530. }
  1531.  
  1532. //====================================================================
  1533. // CFireCommandHunterMOAR
  1534. //====================================================================
  1535. CFireCommandHunterMOAR::CFireCommandHunterMOAR(IAIActor* pShooter)
  1536.         : m_pShooter((CAIActor*) pShooter)
  1537. {
  1538. }
  1539.  
  1540. EAIFireState CFireCommandHunterMOAR::Update(IAIObject* pTarget, bool canFire, EFireMode fireMode, const AIWeaponDescriptor& descriptor, Vec3& outShootTargetPos)
  1541. {
  1542.         if (!pTarget)
  1543.                 return eAIFS_Off;
  1544.  
  1545.         float elapsedTime = (GetAISystem()->GetFrameStartTime() - m_startTime).GetSeconds() - descriptor.fChargeTime;
  1546.         float dt = GetAISystem()->GetFrameDeltaTime();
  1547.  
  1548.         const Vec3& targetPos = pTarget->GetPos();
  1549.  
  1550.         if (!m_startFiring)
  1551.         {
  1552.                 m_lastPos = m_targetPos = targetPos;
  1553.                 m_startFiring = true;
  1554.         }
  1555.  
  1556.         if (m_startFiring)
  1557.         {
  1558.                 if (elapsedTime < 0)
  1559.                 {
  1560.                         // Wait until the weapon has charged
  1561.                         return (canFire ? eAIFS_On : eAIFS_Off);
  1562.                 }
  1563.  
  1564.                 const float oscillationFrequency = 1.0f; // GetPortFloat( pActInfo, 1 );
  1565.                 const float oscillationAmplitude = 1.0f; // GetPortFloat( pActInfo, 2 );
  1566.                 //              const float duration = 6.0f; // GetPortFloat( pActInfo, 3 );
  1567.                 const float alignSpeed = 8.0f; // GetPortFloat( pActInfo, 4 );
  1568.  
  1569.                 if (dt > 0)
  1570.                 {
  1571.                         // make m_lastPos follow m_targetPos with limited speed
  1572.                         Vec3 aim = targetPos + (targetPos - m_targetPos) * 2.0f;
  1573.                         m_targetPos = targetPos;
  1574.                         Vec3 dir = aim - m_lastPos;
  1575.                         float maxDelta = alignSpeed * dt;
  1576.                         if (maxDelta > 0)
  1577.                         {
  1578.                                 if (dir.GetLengthSquared() > maxDelta * maxDelta)
  1579.                                         dir.SetLength(maxDelta);
  1580.                         }
  1581.                         m_lastPos += dir;
  1582.                 }
  1583.  
  1584.                 // a - vertical offset
  1585.                 float a = min(8.0f, max((2.5f - elapsedTime) * 3.0f, -0.5f));
  1586.                 a += cosf(elapsedTime * (100.0f * gf_PI / 180.0f)) * 1.5f; // add some high frequency low amplitude vertical oscillation
  1587.  
  1588.                 // b - horizontal offset
  1589.                 float b = sinf(powf(elapsedTime, 1.4f) * oscillationFrequency * (2.0f * gf_PI));
  1590.                 b += sinf(elapsedTime * 355.0f * (gf_PI / 180.0f)) * 0.1f;
  1591.                 b *= max(2.5f - elapsedTime, 0.0f) * oscillationAmplitude;
  1592.  
  1593.                 Vec3 fireDir = m_lastPos - m_pShooter->GetFirePos();
  1594.                 Vec3 fireDir2d(fireDir.x, fireDir.y, 0);
  1595.                 Vec3 sideDir = fireDir.Cross(fireDir2d);
  1596.                 Vec3 vertDir = sideDir.Cross(fireDir).normalized();
  1597.                 sideDir.NormalizeSafe();
  1598.  
  1599.                 outShootTargetPos = m_lastPos - vertDir * a + sideDir * b;
  1600.         }
  1601.  
  1602.         return (canFire ? eAIFS_On : eAIFS_Off);
  1603. }
  1604.  
  1605. float CFireCommandHunterMOAR::GetTimeToNextShot() const
  1606. {
  1607.         return 0.0f;
  1608. }
  1609. //====================================================================
  1610. // CFireCommandHunterSweepMOAR
  1611. //====================================================================
  1612. CFireCommandHunterSweepMOAR::CFireCommandHunterSweepMOAR(IAIActor* pShooter)
  1613.         : m_pShooter((CAIActor*) pShooter)
  1614. {
  1615. }
  1616.  
  1617. EAIFireState CFireCommandHunterSweepMOAR::Update(IAIObject* pTarget, bool canFire, EFireMode fireMode, const AIWeaponDescriptor& descriptor, Vec3& outShootTargetPos)
  1618. {
  1619.         if (!pTarget)
  1620.                 return eAIFS_Off;
  1621.  
  1622.         float elapsedTime = (GetAISystem()->GetFrameStartTime() - m_startTime).GetSeconds() - descriptor.fChargeTime;
  1623.         float dt = GetAISystem()->GetFrameDeltaTime();
  1624.  
  1625.         const Vec3& targetPos = pTarget->GetPos();
  1626.  
  1627.         if (!m_startFiring)
  1628.         {
  1629.                 m_lastPos = m_targetPos = targetPos;
  1630.                 m_startFiring = true;
  1631.         }
  1632.  
  1633.         if (m_startFiring)
  1634.         {
  1635.                 if (elapsedTime < 0)
  1636.                 {
  1637.                         // Wait until the weapon has charged
  1638.                         return (canFire ? eAIFS_On : eAIFS_Off);
  1639.                 }
  1640.  
  1641.                 const float baseDist = 20.0f;      // GetPortFloat( pActInfo, 1 );
  1642.                 const float leftRightSpeed = 6.0f; // GetPortFloat( pActInfo, 2);
  1643.                 const float width = 10.0f;         // GetPortFloat( pActInfo, 3);
  1644.                 const float nearFarSpeed = 7.0f;   // GetPortFloat( pActInfo, 4);
  1645.                 const float dist = 7.0f;           // GetPortFloat( pActInfo, 5);
  1646.                 const float duration = 10.0f;      // GetPortFloat( pActInfo, 6);
  1647.  
  1648.                 Matrix34 worldTransform = m_pShooter->GetEntity()->GetWorldTM();
  1649.                 Vec3 fireDir = worldTransform.GetColumn1();
  1650.                 Vec3 sideDir = worldTransform.GetColumn0();
  1651.                 Vec3 upDir = worldTransform.GetColumn2();
  1652.                 Vec3 pos = worldTransform.GetColumn3();
  1653.  
  1654.                 // runs from 0 to 2*PI and indicates where in the 2*PI long cycle we are now
  1655.                 float t = 2.0f * gf_PI * elapsedTime / duration;
  1656.  
  1657.                 // NOTE Mrz 31, 2007: <pvl> essetially a Lissajous curve, with some
  1658.                 // irregularity added by a higher frequency harmonic and offset vertically
  1659.                 // because we don't want the hunter to shoot at the sky.
  1660.                 outShootTargetPos = m_pShooter->GetPos() +
  1661.                                     baseDist * fireDir +
  1662.                                     dist * sinf(nearFarSpeed * t) * upDir +
  1663.                                     0.2f * dist * sinf(2.3f * nearFarSpeed * t + 1.0f /*phase shift*/) * upDir +
  1664.                                     -1.8f * dist * upDir +
  1665.                                     width * sinf(leftRightSpeed * t) * sideDir +
  1666.                                     0.2f * width * sinf(2.3f * leftRightSpeed * t + 1.0f /*phase shift*/) * sideDir;
  1667.         }
  1668.  
  1669.         return (canFire ? eAIFS_On : eAIFS_Off);
  1670. }
  1671.  
  1672. float CFireCommandHunterSweepMOAR::GetTimeToNextShot() const
  1673. {
  1674.         return 0.0f;
  1675. }
  1676. //====================================================================
  1677. // CFireCommandHunterSingularityCannon
  1678. //====================================================================
  1679. CFireCommandHunterSingularityCannon::CFireCommandHunterSingularityCannon(IAIActor* pShooter)
  1680.         : m_pShooter((CAIActor*) pShooter)
  1681. {
  1682. }
  1683.  
  1684. EAIFireState CFireCommandHunterSingularityCannon::Update(IAIObject* pTarget, bool canFire, EFireMode fireMode, const AIWeaponDescriptor& descriptor, Vec3& outShootTargetPos)
  1685. {
  1686.         if (!pTarget)
  1687.                 return eAIFS_Off;
  1688.  
  1689.         float elapsedTime = (GetAISystem()->GetFrameStartTime() - m_startTime).GetSeconds() - descriptor.fChargeTime;
  1690.         float dt = GetAISystem()->GetFrameDeltaTime();
  1691.  
  1692.         const Vec3& targetPos = pTarget->GetPos();
  1693.         outShootTargetPos = targetPos;
  1694.  
  1695.         if (!m_startFiring)
  1696.         {
  1697.                 m_targetPos = targetPos;
  1698.                 m_startFiring = true;
  1699.         }
  1700.  
  1701.         /*
  1702.            if ( m_startFiring )
  1703.            {
  1704.             if ( elapsedTime < 0 )
  1705.             {
  1706.               // Wait until the weapon has charged
  1707.               return (canFire ? eAIFS_On : eAIFS_Off);
  1708.             }
  1709.            }
  1710.          */
  1711.  
  1712.         return (canFire ? eAIFS_On : eAIFS_Off);
  1713. }
  1714.  
  1715. float CFireCommandHunterSingularityCannon::GetTimeToNextShot() const
  1716. {
  1717.         return 0.0f;
  1718. }
  1719.  
  1720. //====================================================================
  1721. // CFireCommandHurricane
  1722. //====================================================================
  1723. CFireCommandHurricane::CFireCommandHurricane(IAIActor* pShooter) :
  1724.         /*m_fLastShootingTime(0),
  1725.            m_fDrawFireLastTime(0),
  1726.            m_nDrawFireCounter(0),
  1727.            m_JustReset(false),
  1728.            m_bIsTriggerDown(false),
  1729.            m_bIsBursting(false),
  1730.            m_fTimeOut(-1.f),
  1731.            m_fLastBulletOutTime(0.f),
  1732.            m_fFadingToNormalTime(0.f),
  1733.            m_fLastValidTragetTime(0.f),*/
  1734.         m_pShooter(((CAIActor*)pShooter)->CastToCPuppet())
  1735. {
  1736. }
  1737.  
  1738. void CFireCommandHurricane::Reset()
  1739. {
  1740. }
  1741.  
  1742. //
  1743. //
  1744. //
  1745. //----------------------------------------------------------------------------------------------------------------
  1746. EAIFireState CFireCommandHurricane::Update(IAIObject* pITarget, bool canFire, EFireMode fireMode, const AIWeaponDescriptor& descriptor, Vec3& outShootTargetPos)
  1747. {
  1748.         if (!pITarget)
  1749.                 return eAIFS_Off;
  1750.  
  1751.         if (!canFire)
  1752.                 return eAIFS_Off;
  1753.  
  1754.         CAIObject* pTarget((CAIObject*)pITarget);
  1755.  
  1756.         bool fireNow(SelectFireDirNormalFire(pTarget, 1.f, outShootTargetPos));
  1757.  
  1758.         // Check if weapon is not pointing too differently from where we want to shoot
  1759.         // The outShootTargetPos is initialized with the aim target.
  1760.         if (fireNow && !IsWeaponPointingRight(outShootTargetPos))
  1761.                 return eAIFS_Off;
  1762.  
  1763.         if (fireNow && !ValidateFireDirection(outShootTargetPos - m_pShooter->GetFirePos(), false))
  1764.                 return eAIFS_Off;
  1765.  
  1766.         return (fireNow ? eAIFS_On : eAIFS_Off);
  1767. }
  1768.  
  1769. //
  1770. //--------------------------------------------------------------------------------------------------------
  1771. bool CFireCommandHurricane::SelectFireDirNormalFire(CAIObject* pTarget, float fAccuracyRamping, Vec3& outShootTargetPos)
  1772. {
  1773.         //accuracy/missing management: miss if not in front of player or if accuracy needed
  1774.         float shooterCurrentAccuracy = m_pShooter->GetAccuracy(pTarget);
  1775.         bool bAccuracyMiss = cry_random(0.f, 100.f) > (shooterCurrentAccuracy * 100.f);
  1776.         bool bMissNow = bAccuracyMiss; // || m_pShooter->GetAmbientFire();
  1777.  
  1778.         ++dbg_ShotCounter;
  1779.  
  1780.         if (bMissNow)
  1781.         {
  1782.                 outShootTargetPos = ChooseMissPoint(pTarget);
  1783.         }
  1784.         else
  1785.         {
  1786.                 Vec3 vTargetPos;
  1787.                 Vec3 vTargetDir;
  1788.                 // In addition to common fire checks, make sure that we do not hit something too close between us and the target.
  1789.                 // check if we don't hit anything (rocks/trees/cars)
  1790.                 bool lowDamage = fAccuracyRamping < 1.0f;
  1791.                 //              if(pTarget->GetType() == AIOBJECT_PLAYER)
  1792.                 //                      lowDamage = lowDamage || !GetAISystem()->GetCurrentDifficultyProfile()->allowInstantKills;
  1793.                 if (!lowDamage)
  1794.                         lowDamage = cry_random(0.f, 100.f) > (shooterCurrentAccuracy * 50.f);  // decide if want to hit legs/arms (low damage)
  1795.                 if (!m_pShooter->CheckAndGetFireTarget_Deprecated(pTarget, lowDamage, vTargetPos, vTargetDir))
  1796.                         return false;
  1797.                 outShootTargetPos = vTargetPos;
  1798.  
  1799.                 if (!outShootTargetPos.IsZero(1.f))
  1800.                 {
  1801.                         ++dbg_ShotHitCounter;
  1802.                 }
  1803.         }
  1804.         //
  1805.         if (outShootTargetPos.IsZero(1.f))
  1806.         {
  1807.                 outShootTargetPos = pTarget->GetPos();
  1808.                 return false;
  1809.         }
  1810.  
  1811.         return true;
  1812. }
  1813.  
  1814. //
  1815. //      we have candidate shooting direction, let's check if it is good
  1816. //
  1817. //--------------------------------------------------------------------------------------------------------
  1818. bool CFireCommandHurricane::ValidateFireDirection(const Vec3& fireVector, bool mustHit)
  1819. {
  1820.         ray_hit hit;
  1821.         int rwiResult;
  1822.         IPhysicalWorld* pWorld = gEnv->pPhysicalWorld;
  1823.         rwiResult = pWorld->RayWorldIntersection(
  1824.           m_pShooter->GetFirePos(), fireVector, COVER_OBJECT_TYPES,
  1825.           AI_VISION_RAY_CAST_FLAG_BLOCKED_BY_SOLID_COVER,
  1826.           &hit, 1);
  1827.         // if hitting something too close to shooter - bad fire direction
  1828.         float fireVectorLen;
  1829.         if (rwiResult != 0)
  1830.         {
  1831.                 fireVectorLen = fireVector.GetLength();
  1832.                 if (mustHit || hit.dist < fireVectorLen * (m_pShooter->GetFireMode() == FIREMODE_FORCED ? 0.3f : 0.73f))
  1833.                         return false;
  1834.         }
  1835.         return !m_pShooter->CheckFriendsInLineOfFire(fireVector, false);
  1836. }
  1837.  
  1838. //
  1839. //--------------------------------------------------------------------------------------------------------
  1840. bool CFireCommandHurricane::IsWeaponPointingRight(const Vec3& shootTargetPos)  //const
  1841. {
  1842.         // Check if weapon is not pointing too differently from where we want to shoot
  1843.         Vec3 fireDir(shootTargetPos - m_pShooter->GetFirePos());
  1844.         float dist2(fireDir.GetLengthSquared());
  1845.         // if within 2m from target - make very loose angle check
  1846.         float trhAngle(fireDir.GetLengthSquared() < sqr(5.f) ? 73.f : 22.f);
  1847.         fireDir.normalize();
  1848.         const SAIBodyInfo& bodyInfo = m_pShooter->GetBodyInfo();
  1849.  
  1850.         //dbg_AngleDiffValue = acos_tpl( fireDir.Dot(bodyInfo.vFireDir));
  1851.         dbg_AngleDiffValue = RAD2DEG(acos_tpl((fireDir.Dot(bodyInfo.vFireDir))));
  1852.  
  1853.         if (fireDir.Dot(bodyInfo.vFireDir) < cos_tpl(DEG2RAD(trhAngle)))
  1854.         {
  1855.                 dbg_AngleTooDifferent = true;
  1856.                 return false;
  1857.         }
  1858.         dbg_AngleTooDifferent = false;
  1859.         return true;
  1860. }
  1861.  
  1862. //
  1863. //--------------------------------------------------------------------------------------------------------
  1864. Vec3 CFireCommandHurricane::ChooseMissPoint(CAIObject* pTarget) const
  1865. {
  1866.         Vec3 vTargetPos(pTarget->GetPos());
  1867.         float targetGroundLevel = pTarget->GetPhysicsPos().z;
  1868.         return m_pShooter->ChooseMissPoint_Deprecated(vTargetPos);
  1869. }
  1870.  
  1871. float CFireCommandHurricane::GetTimeToNextShot() const
  1872. {
  1873.         return 0.0f;
  1874. }
  1875. #endif // 0
  1876. //
  1877. //---------------------------------------------------------------------------------------------------------------
  1878.  
downloadFireCommand.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